diff --git a/DEPS b/DEPS index b33f8a4..d374861 100644 --- a/DEPS +++ b/DEPS
@@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '9b8584120201e28d95740d0777e4f657b2139ff8', + 'catapult_revision': '61ceb4a8f878ac2ab668e0eaede6755907b6905f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index e385c47..df0b83b 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -15,27 +15,12 @@ component("ash") { sources = [ - "accelerators/accelerator_commands.cc", - "accelerators/accelerator_commands.h", "accelerators/accelerator_commands_aura.cc", "accelerators/accelerator_commands_aura.h", - "accelerators/accelerator_controller.cc", - "accelerators/accelerator_controller.h", - "accelerators/accelerator_controller_delegate.h", "accelerators/accelerator_controller_delegate_aura.cc", "accelerators/accelerator_controller_delegate_aura.h", "accelerators/accelerator_delegate.cc", "accelerators/accelerator_delegate.h", - "accelerators/accelerator_router.cc", - "accelerators/accelerator_router.h", - "accelerators/accelerator_table.cc", - "accelerators/accelerator_table.h", - "accelerators/ash_focus_manager_factory.cc", - "accelerators/ash_focus_manager_factory.h", - "accelerators/debug_commands.cc", - "accelerators/debug_commands.h", - "accelerators/exit_warning_handler.cc", - "accelerators/exit_warning_handler.h", "accelerators/key_hold_detector.cc", "accelerators/key_hold_detector.h", "accelerators/magnifier_key_scroller.cc", @@ -64,6 +49,21 @@ "autoclick/autoclick_controller.h", "cancel_mode.cc", "cancel_mode.h", + "common/accelerators/accelerator_commands.cc", + "common/accelerators/accelerator_commands.h", + "common/accelerators/accelerator_controller.cc", + "common/accelerators/accelerator_controller.h", + "common/accelerators/accelerator_controller_delegate.h", + "common/accelerators/accelerator_router.cc", + "common/accelerators/accelerator_router.h", + "common/accelerators/accelerator_table.cc", + "common/accelerators/accelerator_table.h", + "common/accelerators/ash_focus_manager_factory.cc", + "common/accelerators/ash_focus_manager_factory.h", + "common/accelerators/debug_commands.cc", + "common/accelerators/debug_commands.h", + "common/accelerators/exit_warning_handler.cc", + "common/accelerators/exit_warning_handler.h", "common/accessibility_delegate.h", "common/accessibility_types.h", "common/ash_constants.cc", @@ -80,8 +80,29 @@ "common/devtools/ash_devtools_css_agent.h", "common/devtools/ash_devtools_dom_agent.cc", "common/devtools/ash_devtools_dom_agent.h", + "common/drag_drop/drag_image_view.cc", + "common/drag_drop/drag_image_view.h", "common/focus_cycler.cc", "common/focus_cycler.h", + "common/frame/caption_buttons/caption_button_types.h", + "common/frame/caption_buttons/frame_caption_button.cc", + "common/frame/caption_buttons/frame_caption_button.h", + "common/frame/caption_buttons/frame_caption_button_container_view.cc", + "common/frame/caption_buttons/frame_caption_button_container_view.h", + "common/frame/caption_buttons/frame_size_button.cc", + "common/frame/caption_buttons/frame_size_button.h", + "common/frame/caption_buttons/frame_size_button_delegate.h", + "common/frame/custom_frame_view_ash.cc", + "common/frame/custom_frame_view_ash.h", + "common/frame/default_header_painter.cc", + "common/frame/default_header_painter.h", + "common/frame/frame_border_hit_test.cc", + "common/frame/frame_border_hit_test.h", + "common/frame/header_painter.h", + "common/frame/header_painter_util.cc", + "common/frame/header_painter_util.h", + "common/frame/header_view.cc", + "common/frame/header_view.h", "common/gpu_support.h", "common/gpu_support_stub.cc", "common/gpu_support_stub.h", @@ -95,6 +116,10 @@ "common/material_design/material_design_controller.h", "common/media_controller.cc", "common/media_controller.h", + "common/metrics/gesture_action_type.h", + "common/metrics/pointer_metrics_recorder.cc", + "common/metrics/pointer_metrics_recorder.h", + "common/metrics/user_metrics_action.h", "common/mojo_interface_factory.cc", "common/mojo_interface_factory.h", "common/multi_profile_uma.cc", @@ -110,9 +135,318 @@ "common/session/session_state_delegate.h", "common/session/session_state_observer.cc", "common/session/session_state_observer.h", + "common/shelf/app_list_button.cc", + "common/shelf/app_list_button.h", + "common/shelf/app_list_shelf_item_delegate.cc", + "common/shelf/app_list_shelf_item_delegate.h", + "common/shelf/ink_drop_button_listener.h", + "common/shelf/overflow_bubble.cc", + "common/shelf/overflow_bubble.h", + "common/shelf/overflow_bubble_view.cc", + "common/shelf/overflow_bubble_view.h", + "common/shelf/overflow_button.cc", + "common/shelf/overflow_button.h", + "common/shelf/shelf_alignment_menu.cc", + "common/shelf/shelf_alignment_menu.h", + "common/shelf/shelf_application_menu_model.cc", + "common/shelf/shelf_application_menu_model.h", + "common/shelf/shelf_background_animator.cc", + "common/shelf/shelf_background_animator.h", + "common/shelf/shelf_background_animator_observer.h", + "common/shelf/shelf_button.cc", + "common/shelf/shelf_button.h", + "common/shelf/shelf_button_pressed_metric_tracker.cc", + "common/shelf/shelf_button_pressed_metric_tracker.h", + "common/shelf/shelf_constants.cc", + "common/shelf/shelf_constants.h", + "common/shelf/shelf_controller.cc", + "common/shelf/shelf_controller.h", + "common/shelf/shelf_delegate.h", + "common/shelf/shelf_item_delegate.cc", + "common/shelf/shelf_item_delegate.h", + "common/shelf/shelf_item_types.cc", + "common/shelf/shelf_item_types.h", + "common/shelf/shelf_layout_manager.cc", + "common/shelf/shelf_layout_manager.h", + "common/shelf/shelf_layout_manager_observer.h", + "common/shelf/shelf_locking_manager.cc", + "common/shelf/shelf_locking_manager.h", + "common/shelf/shelf_model.cc", + "common/shelf/shelf_model.h", + "common/shelf/shelf_model_observer.h", + "common/shelf/shelf_tooltip_manager.cc", + "common/shelf/shelf_tooltip_manager.h", + "common/shelf/shelf_view.cc", + "common/shelf/shelf_view.h", + "common/shelf/shelf_widget.cc", + "common/shelf/shelf_widget.h", + "common/shelf/shelf_window_watcher.cc", + "common/shelf/shelf_window_watcher.h", + "common/shelf/shelf_window_watcher_item_delegate.cc", + "common/shelf/shelf_window_watcher_item_delegate.h", + "common/shelf/wm_shelf.cc", + "common/shelf/wm_shelf.h", + "common/shelf/wm_shelf_observer.h", + "common/shelf/wm_shelf_util.cc", + "common/shelf/wm_shelf_util.h", "common/shell_delegate.h", "common/shutdown_controller.cc", "common/shutdown_controller.h", + "common/system/accessibility_observer.h", + "common/system/brightness_control_delegate.h", + "common/system/chromeos/audio/audio_detailed_view.cc", + "common/system/chromeos/audio/audio_detailed_view.h", + "common/system/chromeos/audio/tray_audio.cc", + "common/system/chromeos/audio/tray_audio.h", + "common/system/chromeos/audio/tray_audio_delegate.h", + "common/system/chromeos/audio/tray_audio_delegate_chromeos.cc", + "common/system/chromeos/audio/tray_audio_delegate_chromeos.h", + "common/system/chromeos/audio/volume_view.cc", + "common/system/chromeos/audio/volume_view.h", + "common/system/chromeos/bluetooth/bluetooth_notification_controller.cc", + "common/system/chromeos/bluetooth/bluetooth_notification_controller.h", + "common/system/chromeos/bluetooth/bluetooth_observer.h", + "common/system/chromeos/bluetooth/tray_bluetooth.cc", + "common/system/chromeos/bluetooth/tray_bluetooth.h", + "common/system/chromeos/brightness/brightness_controller_chromeos.cc", + "common/system/chromeos/brightness/brightness_controller_chromeos.h", + "common/system/chromeos/brightness/tray_brightness.cc", + "common/system/chromeos/brightness/tray_brightness.h", + "common/system/chromeos/cast/tray_cast.cc", + "common/system/chromeos/cast/tray_cast.h", + "common/system/chromeos/devicetype_utils.cc", + "common/system/chromeos/devicetype_utils.h", + "common/system/chromeos/enterprise/enterprise_domain_observer.h", + "common/system/chromeos/enterprise/tray_enterprise.cc", + "common/system/chromeos/enterprise/tray_enterprise.h", + "common/system/chromeos/ime_menu/ime_list_view.cc", + "common/system/chromeos/ime_menu/ime_list_view.h", + "common/system/chromeos/ime_menu/ime_menu_tray.cc", + "common/system/chromeos/ime_menu/ime_menu_tray.h", + "common/system/chromeos/keyboard_brightness_controller.cc", + "common/system/chromeos/keyboard_brightness_controller.h", + "common/system/chromeos/media_security/multi_profile_media_tray_item.cc", + "common/system/chromeos/media_security/multi_profile_media_tray_item.h", + "common/system/chromeos/network/network_detailed_view.h", + "common/system/chromeos/network/network_icon.cc", + "common/system/chromeos/network/network_icon.h", + "common/system/chromeos/network/network_icon_animation.cc", + "common/system/chromeos/network/network_icon_animation.h", + "common/system/chromeos/network/network_icon_animation_observer.h", + "common/system/chromeos/network/network_info.cc", + "common/system/chromeos/network/network_info.h", + "common/system/chromeos/network/network_list.cc", + "common/system/chromeos/network/network_list.h", + "common/system/chromeos/network/network_list_delegate.h", + "common/system/chromeos/network/network_list_md.cc", + "common/system/chromeos/network/network_list_md.h", + "common/system/chromeos/network/network_list_view_base.cc", + "common/system/chromeos/network/network_list_view_base.h", + "common/system/chromeos/network/network_observer.h", + "common/system/chromeos/network/network_portal_detector_observer.h", + "common/system/chromeos/network/network_state_list_detailed_view.cc", + "common/system/chromeos/network/network_state_list_detailed_view.h", + "common/system/chromeos/network/sms_observer.cc", + "common/system/chromeos/network/sms_observer.h", + "common/system/chromeos/network/tray_network.cc", + "common/system/chromeos/network/tray_network.h", + "common/system/chromeos/network/tray_network_state_observer.cc", + "common/system/chromeos/network/tray_network_state_observer.h", + "common/system/chromeos/network/tray_vpn.cc", + "common/system/chromeos/network/tray_vpn.h", + "common/system/chromeos/network/vpn_list.cc", + "common/system/chromeos/network/vpn_list.h", + "common/system/chromeos/network/vpn_list_view.cc", + "common/system/chromeos/network/vpn_list_view.h", + "common/system/chromeos/palette/common_palette_tool.cc", + "common/system/chromeos/palette/common_palette_tool.h", + "common/system/chromeos/palette/palette_ids.cc", + "common/system/chromeos/palette/palette_ids.h", + "common/system/chromeos/palette/palette_tool.cc", + "common/system/chromeos/palette/palette_tool.h", + "common/system/chromeos/palette/palette_tool_manager.cc", + "common/system/chromeos/palette/palette_tool_manager.h", + "common/system/chromeos/palette/palette_tray.cc", + "common/system/chromeos/palette/palette_tray.h", + "common/system/chromeos/palette/palette_utils.cc", + "common/system/chromeos/palette/palette_utils.h", + "common/system/chromeos/palette/tools/capture_region_mode.cc", + "common/system/chromeos/palette/tools/capture_region_mode.h", + "common/system/chromeos/palette/tools/capture_screen_action.cc", + "common/system/chromeos/palette/tools/capture_screen_action.h", + "common/system/chromeos/palette/tools/create_note_action.cc", + "common/system/chromeos/palette/tools/create_note_action.h", + "common/system/chromeos/palette/tools/laser_pointer_mode.cc", + "common/system/chromeos/palette/tools/laser_pointer_mode.h", + "common/system/chromeos/palette/tools/magnifier_mode.cc", + "common/system/chromeos/palette/tools/magnifier_mode.h", + "common/system/chromeos/power/battery_notification.cc", + "common/system/chromeos/power/battery_notification.h", + "common/system/chromeos/power/dual_role_notification.cc", + "common/system/chromeos/power/dual_role_notification.h", + "common/system/chromeos/power/power_status.cc", + "common/system/chromeos/power/power_status.h", + "common/system/chromeos/power/power_status_view.cc", + "common/system/chromeos/power/power_status_view.h", + "common/system/chromeos/power/tray_power.cc", + "common/system/chromeos/power/tray_power.h", + "common/system/chromeos/screen_security/screen_capture_observer.h", + "common/system/chromeos/screen_security/screen_capture_tray_item.cc", + "common/system/chromeos/screen_security/screen_capture_tray_item.h", + "common/system/chromeos/screen_security/screen_share_observer.h", + "common/system/chromeos/screen_security/screen_share_tray_item.cc", + "common/system/chromeos/screen_security/screen_share_tray_item.h", + "common/system/chromeos/screen_security/screen_tray_item.cc", + "common/system/chromeos/screen_security/screen_tray_item.h", + "common/system/chromeos/session/last_window_closed_observer.h", + "common/system/chromeos/session/logout_button_observer.h", + "common/system/chromeos/session/logout_button_tray.cc", + "common/system/chromeos/session/logout_button_tray.h", + "common/system/chromeos/session/logout_confirmation_controller.cc", + "common/system/chromeos/session/logout_confirmation_controller.h", + "common/system/chromeos/session/logout_confirmation_dialog.cc", + "common/system/chromeos/session/logout_confirmation_dialog.h", + "common/system/chromeos/session/session_length_limit_observer.h", + "common/system/chromeos/session/tray_session_length_limit.cc", + "common/system/chromeos/session/tray_session_length_limit.h", + "common/system/chromeos/settings/tray_settings.cc", + "common/system/chromeos/settings/tray_settings.h", + "common/system/chromeos/supervised/custodian_info_tray_observer.h", + "common/system/chromeos/supervised/tray_supervised_user.cc", + "common/system/chromeos/supervised/tray_supervised_user.h", + "common/system/chromeos/system_clock_observer.cc", + "common/system/chromeos/system_clock_observer.h", + "common/system/chromeos/tray_caps_lock.cc", + "common/system/chromeos/tray_caps_lock.h", + "common/system/chromeos/tray_tracing.cc", + "common/system/chromeos/tray_tracing.h", + "common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h", + "common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc", + "common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.h", + "common/system/date/clock_observer.h", + "common/system/date/date_default_view.cc", + "common/system/date/date_default_view.h", + "common/system/date/date_view.cc", + "common/system/date/date_view.h", + "common/system/date/system_info_default_view.cc", + "common/system/date/system_info_default_view.h", + "common/system/date/tray_date.cc", + "common/system/date/tray_date.h", + "common/system/date/tray_system_info.cc", + "common/system/date/tray_system_info.h", + "common/system/ime/ime_observer.h", + "common/system/ime/tray_ime_chromeos.cc", + "common/system/ime/tray_ime_chromeos.h", + "common/system/keyboard_brightness_control_delegate.h", + "common/system/locale/locale_notification_controller.cc", + "common/system/locale/locale_notification_controller.h", + "common/system/networking_config_delegate.cc", + "common/system/networking_config_delegate.h", + "common/system/overview/overview_button_tray.cc", + "common/system/overview/overview_button_tray.h", + "common/system/status_area_layout_manager.cc", + "common/system/status_area_layout_manager.h", + "common/system/status_area_widget.cc", + "common/system/status_area_widget.h", + "common/system/status_area_widget_delegate.cc", + "common/system/status_area_widget_delegate.h", + "common/system/system_notifier.cc", + "common/system/system_notifier.h", + "common/system/tiles/tiles_default_view.cc", + "common/system/tiles/tiles_default_view.h", + "common/system/tiles/tray_tiles.cc", + "common/system/tiles/tray_tiles.h", + "common/system/toast/toast_data.cc", + "common/system/toast/toast_data.h", + "common/system/toast/toast_manager.cc", + "common/system/toast/toast_manager.h", + "common/system/toast/toast_overlay.cc", + "common/system/toast/toast_overlay.h", + "common/system/tray/actionable_view.cc", + "common/system/tray/actionable_view.h", + "common/system/tray/default_system_tray_delegate.cc", + "common/system/tray/default_system_tray_delegate.h", + "common/system/tray/fixed_sized_image_view.cc", + "common/system/tray/fixed_sized_image_view.h", + "common/system/tray/hover_highlight_view.cc", + "common/system/tray/hover_highlight_view.h", + "common/system/tray/ime_info.cc", + "common/system/tray/ime_info.h", + "common/system/tray/label_tray_view.cc", + "common/system/tray/label_tray_view.h", + "common/system/tray/size_range_layout.cc", + "common/system/tray/size_range_layout.h", + "common/system/tray/special_popup_row.cc", + "common/system/tray/special_popup_row.h", + "common/system/tray/system_menu_button.cc", + "common/system/tray/system_menu_button.h", + "common/system/tray/system_tray.cc", + "common/system/tray/system_tray.h", + "common/system/tray/system_tray_bubble.cc", + "common/system/tray/system_tray_bubble.h", + "common/system/tray/system_tray_controller.cc", + "common/system/tray/system_tray_controller.h", + "common/system/tray/system_tray_delegate.cc", + "common/system/tray/system_tray_delegate.h", + "common/system/tray/system_tray_item.cc", + "common/system/tray/system_tray_item.h", + "common/system/tray/system_tray_notifier.cc", + "common/system/tray/system_tray_notifier.h", + "common/system/tray/throbber_view.cc", + "common/system/tray/throbber_view.h", + "common/system/tray/tray_background_view.cc", + "common/system/tray/tray_background_view.h", + "common/system/tray/tray_bubble_wrapper.cc", + "common/system/tray/tray_bubble_wrapper.h", + "common/system/tray/tray_constants.cc", + "common/system/tray/tray_constants.h", + "common/system/tray/tray_details_view.cc", + "common/system/tray/tray_details_view.h", + "common/system/tray/tray_event_filter.cc", + "common/system/tray/tray_event_filter.h", + "common/system/tray/tray_image_item.cc", + "common/system/tray/tray_image_item.h", + "common/system/tray/tray_item_more.cc", + "common/system/tray/tray_item_more.h", + "common/system/tray/tray_item_view.cc", + "common/system/tray/tray_item_view.h", + "common/system/tray/tray_notification_view.cc", + "common/system/tray/tray_notification_view.h", + "common/system/tray/tray_popup_header_button.cc", + "common/system/tray/tray_popup_header_button.h", + "common/system/tray/tray_popup_ink_drop_style.h", + "common/system/tray/tray_popup_item_container.cc", + "common/system/tray/tray_popup_item_container.h", + "common/system/tray/tray_popup_item_style.cc", + "common/system/tray/tray_popup_item_style.h", + "common/system/tray/tray_popup_utils.cc", + "common/system/tray/tray_popup_utils.h", + "common/system/tray/tray_utils.cc", + "common/system/tray/tray_utils.h", + "common/system/tray/tri_view.cc", + "common/system/tray/tri_view.h", + "common/system/tray/view_click_listener.h", + "common/system/tray_accessibility.cc", + "common/system/tray_accessibility.h", + "common/system/update/tray_update.cc", + "common/system/update/tray_update.h", + "common/system/user/button_from_view.cc", + "common/system/user/button_from_view.h", + "common/system/user/login_status.cc", + "common/system/user/login_status.h", + "common/system/user/rounded_image_view.cc", + "common/system/user/rounded_image_view.h", + "common/system/user/tray_user.cc", + "common/system/user/tray_user.h", + "common/system/user/user_card_view.cc", + "common/system/user/user_card_view.h", + "common/system/user/user_observer.h", + "common/system/user/user_view.cc", + "common/system/user/user_view.h", + "common/system/web_notification/ash_popup_alignment_delegate.cc", + "common/system/web_notification/ash_popup_alignment_delegate.h", + "common/system/web_notification/web_notification_tray.cc", + "common/system/web_notification/web_notification_tray.h", "common/wallpaper/wallpaper_controller.cc", "common/wallpaper/wallpaper_controller.h", "common/wallpaper/wallpaper_controller_observer.h", @@ -121,6 +455,130 @@ "common/wallpaper/wallpaper_view.h", "common/wallpaper/wallpaper_widget_controller.cc", "common/wallpaper/wallpaper_widget_controller.h", + "common/wm/always_on_top_controller.cc", + "common/wm/always_on_top_controller.h", + "common/wm/container_finder.cc", + "common/wm/container_finder.h", + "common/wm/default_state.cc", + "common/wm/default_state.h", + "common/wm/default_window_resizer.cc", + "common/wm/default_window_resizer.h", + "common/wm/dock/docked_window_layout_manager.cc", + "common/wm/dock/docked_window_layout_manager.h", + "common/wm/dock/docked_window_layout_manager_observer.h", + "common/wm/dock/docked_window_resizer.cc", + "common/wm/dock/docked_window_resizer.h", + "common/wm/drag_details.cc", + "common/wm/drag_details.h", + "common/wm/focus_rules.cc", + "common/wm/focus_rules.h", + "common/wm/fullscreen_window_finder.cc", + "common/wm/fullscreen_window_finder.h", + "common/wm/immersive_context_ash.cc", + "common/wm/immersive_context_ash.h", + "common/wm/lock_layout_manager.cc", + "common/wm/lock_layout_manager.h", + "common/wm/lock_state_observer.h", + "common/wm/lock_window_state.cc", + "common/wm/lock_window_state.h", + "common/wm/maximize_mode/maximize_mode_controller.cc", + "common/wm/maximize_mode/maximize_mode_controller.h", + "common/wm/maximize_mode/maximize_mode_event_handler.cc", + "common/wm/maximize_mode/maximize_mode_event_handler.h", + "common/wm/maximize_mode/maximize_mode_window_manager.cc", + "common/wm/maximize_mode/maximize_mode_window_manager.h", + "common/wm/maximize_mode/maximize_mode_window_state.cc", + "common/wm/maximize_mode/maximize_mode_window_state.h", + "common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h", + "common/wm/maximize_mode/workspace_backdrop_delegate.cc", + "common/wm/maximize_mode/workspace_backdrop_delegate.h", + "common/wm/mru_window_tracker.cc", + "common/wm/mru_window_tracker.h", + "common/wm/overview/cleanup_animation_observer.cc", + "common/wm/overview/cleanup_animation_observer.h", + "common/wm/overview/overview_animation_type.h", + "common/wm/overview/scoped_overview_animation_settings.h", + "common/wm/overview/scoped_overview_animation_settings_factory.cc", + "common/wm/overview/scoped_overview_animation_settings_factory.h", + "common/wm/overview/scoped_transform_overview_window.cc", + "common/wm/overview/scoped_transform_overview_window.h", + "common/wm/overview/window_grid.cc", + "common/wm/overview/window_grid.h", + "common/wm/overview/window_selector.cc", + "common/wm/overview/window_selector.h", + "common/wm/overview/window_selector_controller.cc", + "common/wm/overview/window_selector_controller.h", + "common/wm/overview/window_selector_item.cc", + "common/wm/overview/window_selector_item.h", + "common/wm/panels/panel_frame_view.cc", + "common/wm/panels/panel_frame_view.h", + "common/wm/panels/panel_layout_manager.cc", + "common/wm/panels/panel_layout_manager.h", + "common/wm/panels/panel_window_resizer.cc", + "common/wm/panels/panel_window_resizer.h", + "common/wm/root_window_finder.cc", + "common/wm/root_window_finder.h", + "common/wm/root_window_layout_manager.cc", + "common/wm/root_window_layout_manager.h", + "common/wm/screen_dimmer.cc", + "common/wm/screen_dimmer.h", + "common/wm/switchable_windows.cc", + "common/wm/switchable_windows.h", + "common/wm/system_modal_container_layout_manager.cc", + "common/wm/system_modal_container_layout_manager.h", + "common/wm/window_animation_types.h", + "common/wm/window_cycle_controller.cc", + "common/wm/window_cycle_controller.h", + "common/wm/window_cycle_event_filter.h", + "common/wm/window_cycle_list.cc", + "common/wm/window_cycle_list.h", + "common/wm/window_dimmer.cc", + "common/wm/window_dimmer.h", + "common/wm/window_parenting_utils.cc", + "common/wm/window_parenting_utils.h", + "common/wm/window_positioner.cc", + "common/wm/window_positioner.h", + "common/wm/window_positioning_utils.cc", + "common/wm/window_positioning_utils.h", + "common/wm/window_resizer.cc", + "common/wm/window_resizer.h", + "common/wm/window_state.cc", + "common/wm/window_state.h", + "common/wm/window_state_delegate.cc", + "common/wm/window_state_delegate.h", + "common/wm/window_state_observer.h", + "common/wm/window_state_util.cc", + "common/wm/window_state_util.h", + "common/wm/wm_event.cc", + "common/wm/wm_event.h", + "common/wm/wm_screen_util.cc", + "common/wm/wm_screen_util.h", + "common/wm/wm_snap_to_pixel_layout_manager.cc", + "common/wm/wm_snap_to_pixel_layout_manager.h", + "common/wm/wm_toplevel_window_event_handler.cc", + "common/wm/wm_toplevel_window_event_handler.h", + "common/wm/wm_types.cc", + "common/wm/wm_types.h", + "common/wm/wm_window_animations.cc", + "common/wm/wm_window_animations.h", + "common/wm/workspace/magnetism_matcher.cc", + "common/wm/workspace/magnetism_matcher.h", + "common/wm/workspace/multi_window_resize_controller.cc", + "common/wm/workspace/multi_window_resize_controller.h", + "common/wm/workspace/phantom_window_controller.cc", + "common/wm/workspace/phantom_window_controller.h", + "common/wm/workspace/two_step_edge_cycler.cc", + "common/wm/workspace/two_step_edge_cycler.h", + "common/wm/workspace/workspace_event_handler.cc", + "common/wm/workspace/workspace_event_handler.h", + "common/wm/workspace/workspace_layout_manager.cc", + "common/wm/workspace/workspace_layout_manager.h", + "common/wm/workspace/workspace_layout_manager_backdrop_delegate.h", + "common/wm/workspace/workspace_types.h", + "common/wm/workspace/workspace_window_resizer.cc", + "common/wm/workspace/workspace_window_resizer.h", + "common/wm/workspace_controller.cc", + "common/wm/workspace_controller.h", "common/wm_activation_observer.h", "common/wm_display_observer.h", "common/wm_layout_manager.h", @@ -185,33 +643,12 @@ "drag_drop/drag_drop_controller.h", "drag_drop/drag_drop_tracker.cc", "drag_drop/drag_drop_tracker.h", - "drag_drop/drag_image_view.cc", - "drag_drop/drag_image_view.h", "first_run/desktop_cleaner.cc", "first_run/desktop_cleaner.h", "first_run/first_run_helper.cc", "first_run/first_run_helper.h", "first_run/first_run_helper_impl.cc", "first_run/first_run_helper_impl.h", - "frame/caption_buttons/caption_button_types.h", - "frame/caption_buttons/frame_caption_button.cc", - "frame/caption_buttons/frame_caption_button.h", - "frame/caption_buttons/frame_caption_button_container_view.cc", - "frame/caption_buttons/frame_caption_button_container_view.h", - "frame/caption_buttons/frame_size_button.cc", - "frame/caption_buttons/frame_size_button.h", - "frame/caption_buttons/frame_size_button_delegate.h", - "frame/custom_frame_view_ash.cc", - "frame/custom_frame_view_ash.h", - "frame/default_header_painter.cc", - "frame/default_header_painter.h", - "frame/frame_border_hit_test.cc", - "frame/frame_border_hit_test.h", - "frame/header_painter.h", - "frame/header_painter_util.cc", - "frame/header_painter_util.h", - "frame/header_view.cc", - "frame/header_view.h", "high_contrast/high_contrast_controller.cc", "high_contrast/high_contrast_controller.h", "host/ash_window_tree_host.cc", @@ -246,14 +683,10 @@ "magnifier/partial_magnification_controller.h", "metrics/desktop_task_switch_metric_recorder.cc", "metrics/desktop_task_switch_metric_recorder.h", - "metrics/gesture_action_type.h", - "metrics/pointer_metrics_recorder.cc", - "metrics/pointer_metrics_recorder.h", "metrics/task_switch_metrics_recorder.cc", "metrics/task_switch_metrics_recorder.h", "metrics/task_switch_time_tracker.cc", "metrics/task_switch_time_tracker.h", - "metrics/user_metrics_action.h", "metrics/user_metrics_recorder.cc", "metrics/user_metrics_recorder.h", "root_window_controller.cc", @@ -280,64 +713,10 @@ "shared/immersive_handler_factory.h", "shared/immersive_revealed_lock.cc", "shared/immersive_revealed_lock.h", - "shelf/app_list_button.cc", - "shelf/app_list_button.h", - "shelf/app_list_shelf_item_delegate.cc", - "shelf/app_list_shelf_item_delegate.h", - "shelf/ink_drop_button_listener.h", - "shelf/overflow_bubble.cc", - "shelf/overflow_bubble.h", - "shelf/overflow_bubble_view.cc", - "shelf/overflow_bubble_view.h", - "shelf/overflow_button.cc", - "shelf/overflow_button.h", - "shelf/shelf_alignment_menu.cc", - "shelf/shelf_alignment_menu.h", - "shelf/shelf_application_menu_model.cc", - "shelf/shelf_application_menu_model.h", - "shelf/shelf_background_animator.cc", - "shelf/shelf_background_animator.h", - "shelf/shelf_background_animator_observer.h", "shelf/shelf_bezel_event_handler.cc", "shelf/shelf_bezel_event_handler.h", - "shelf/shelf_button.cc", - "shelf/shelf_button.h", - "shelf/shelf_button_pressed_metric_tracker.cc", - "shelf/shelf_button_pressed_metric_tracker.h", - "shelf/shelf_constants.cc", - "shelf/shelf_constants.h", - "shelf/shelf_controller.cc", - "shelf/shelf_controller.h", - "shelf/shelf_delegate.h", - "shelf/shelf_item_delegate.cc", - "shelf/shelf_item_delegate.h", - "shelf/shelf_item_types.cc", - "shelf/shelf_item_types.h", - "shelf/shelf_layout_manager.cc", - "shelf/shelf_layout_manager.h", - "shelf/shelf_layout_manager_observer.h", - "shelf/shelf_locking_manager.cc", - "shelf/shelf_locking_manager.h", - "shelf/shelf_model.cc", - "shelf/shelf_model.h", - "shelf/shelf_model_observer.h", - "shelf/shelf_tooltip_manager.cc", - "shelf/shelf_tooltip_manager.h", - "shelf/shelf_view.cc", - "shelf/shelf_view.h", - "shelf/shelf_widget.cc", - "shelf/shelf_widget.h", "shelf/shelf_window_targeter.cc", "shelf/shelf_window_targeter.h", - "shelf/shelf_window_watcher.cc", - "shelf/shelf_window_watcher.h", - "shelf/shelf_window_watcher_item_delegate.cc", - "shelf/shelf_window_watcher_item_delegate.h", - "shelf/wm_shelf.cc", - "shelf/wm_shelf.h", - "shelf/wm_shelf_observer.h", - "shelf/wm_shelf_util.cc", - "shelf/wm_shelf_util.h", "shell.cc", "shell.h", "shell_init_params.h", @@ -346,271 +725,16 @@ "sticky_keys/sticky_keys_overlay.cc", "sticky_keys/sticky_keys_overlay.h", "sticky_keys/sticky_keys_state.h", - "system/accessibility_observer.h", - "system/audio/audio_detailed_view.cc", - "system/audio/audio_detailed_view.h", - "system/audio/tray_audio.cc", - "system/audio/tray_audio.h", - "system/audio/tray_audio_delegate.h", - "system/audio/tray_audio_delegate_chromeos.cc", - "system/audio/tray_audio_delegate_chromeos.h", - "system/audio/volume_view.cc", - "system/audio/volume_view.h", - "system/bluetooth/bluetooth_notification_controller.cc", - "system/bluetooth/bluetooth_notification_controller.h", - "system/bluetooth/bluetooth_observer.h", - "system/bluetooth/tray_bluetooth.cc", - "system/bluetooth/tray_bluetooth.h", - "system/brightness/brightness_controller_chromeos.cc", - "system/brightness/brightness_controller_chromeos.h", - "system/brightness/tray_brightness.cc", - "system/brightness/tray_brightness.h", - "system/brightness_control_delegate.h", - "system/cast/tray_cast.cc", - "system/cast/tray_cast.h", - "system/date/clock_observer.h", - "system/date/date_default_view.cc", - "system/date/date_default_view.h", - "system/date/date_view.cc", - "system/date/date_view.h", - "system/date/system_info_default_view.cc", - "system/date/system_info_default_view.h", - "system/date/tray_date.cc", - "system/date/tray_date.h", - "system/date/tray_system_info.cc", - "system/date/tray_system_info.h", - "system/devicetype_utils.cc", - "system/devicetype_utils.h", - "system/enterprise/enterprise_domain_observer.h", - "system/enterprise/tray_enterprise.cc", - "system/enterprise/tray_enterprise.h", - "system/ime/ime_observer.h", - "system/ime/tray_ime_chromeos.cc", - "system/ime/tray_ime_chromeos.h", - "system/ime_menu/ime_list_view.cc", - "system/ime_menu/ime_list_view.h", - "system/ime_menu/ime_menu_tray.cc", - "system/ime_menu/ime_menu_tray.h", - "system/keyboard_brightness_control_delegate.h", - "system/keyboard_brightness_controller.cc", - "system/keyboard_brightness_controller.h", - "system/locale/locale_notification_controller.cc", - "system/locale/locale_notification_controller.h", - "system/media_security/multi_profile_media_tray_item.cc", - "system/media_security/multi_profile_media_tray_item.h", - "system/network/network_detailed_view.h", - "system/network/network_icon.cc", - "system/network/network_icon.h", - "system/network/network_icon_animation.cc", - "system/network/network_icon_animation.h", - "system/network/network_icon_animation_observer.h", - "system/network/network_info.cc", - "system/network/network_info.h", - "system/network/network_list.cc", - "system/network/network_list.h", - "system/network/network_list_delegate.h", - "system/network/network_list_md.cc", - "system/network/network_list_md.h", - "system/network/network_list_view_base.cc", - "system/network/network_list_view_base.h", - "system/network/network_observer.h", - "system/network/network_portal_detector_observer.h", - "system/network/network_state_list_detailed_view.cc", - "system/network/network_state_list_detailed_view.h", - "system/network/sms_observer.cc", - "system/network/sms_observer.h", - "system/network/tray_network.cc", - "system/network/tray_network.h", - "system/network/tray_network_state_observer.cc", - "system/network/tray_network_state_observer.h", - "system/network/tray_vpn.cc", - "system/network/tray_vpn.h", - "system/network/vpn_list.cc", - "system/network/vpn_list.h", - "system/network/vpn_list_view.cc", - "system/network/vpn_list_view.h", - "system/networking_config_delegate.cc", - "system/networking_config_delegate.h", - "system/overview/overview_button_tray.cc", - "system/overview/overview_button_tray.h", - "system/palette/common_palette_tool.cc", - "system/palette/common_palette_tool.h", - "system/palette/palette_ids.cc", - "system/palette/palette_ids.h", - "system/palette/palette_tool.cc", - "system/palette/palette_tool.h", - "system/palette/palette_tool_manager.cc", - "system/palette/palette_tool_manager.h", - "system/palette/palette_tray.cc", - "system/palette/palette_tray.h", - "system/palette/palette_utils.cc", - "system/palette/palette_utils.h", - "system/palette/tools/capture_region_mode.cc", - "system/palette/tools/capture_region_mode.h", - "system/palette/tools/capture_screen_action.cc", - "system/palette/tools/capture_screen_action.h", - "system/palette/tools/create_note_action.cc", - "system/palette/tools/create_note_action.h", - "system/palette/tools/laser_pointer_mode.cc", - "system/palette/tools/laser_pointer_mode.h", - "system/palette/tools/magnifier_mode.cc", - "system/palette/tools/magnifier_mode.h", - "system/power/battery_notification.cc", - "system/power/battery_notification.h", - "system/power/dual_role_notification.cc", - "system/power/dual_role_notification.h", - "system/power/power_event_observer.cc", - "system/power/power_event_observer.h", - "system/power/power_status.cc", - "system/power/power_status.h", - "system/power/power_status_view.cc", - "system/power/power_status_view.h", - "system/power/tablet_power_button_controller.cc", - "system/power/tablet_power_button_controller.h", - "system/power/tray_power.cc", - "system/power/tray_power.h", - "system/power/video_activity_notifier.cc", - "system/power/video_activity_notifier.h", - "system/rotation/tray_rotation_lock.cc", - "system/rotation/tray_rotation_lock.h", - "system/screen_layout_observer.cc", - "system/screen_layout_observer.h", - "system/screen_security/screen_capture_observer.h", - "system/screen_security/screen_capture_tray_item.cc", - "system/screen_security/screen_capture_tray_item.h", - "system/screen_security/screen_share_observer.h", - "system/screen_security/screen_share_tray_item.cc", - "system/screen_security/screen_share_tray_item.h", - "system/screen_security/screen_tray_item.cc", - "system/screen_security/screen_tray_item.h", - "system/session/last_window_closed_observer.h", - "system/session/logout_button_observer.h", - "system/session/logout_button_tray.cc", - "system/session/logout_button_tray.h", - "system/session/logout_confirmation_controller.cc", - "system/session/logout_confirmation_controller.h", - "system/session/logout_confirmation_dialog.cc", - "system/session/logout_confirmation_dialog.h", - "system/session/session_length_limit_observer.h", - "system/session/tray_session_length_limit.cc", - "system/session/tray_session_length_limit.h", - "system/settings/tray_settings.cc", - "system/settings/tray_settings.h", - "system/status_area_layout_manager.cc", - "system/status_area_layout_manager.h", - "system/status_area_widget.cc", - "system/status_area_widget.h", - "system/status_area_widget_delegate.cc", - "system/status_area_widget_delegate.h", - "system/supervised/custodian_info_tray_observer.h", - "system/supervised/tray_supervised_user.cc", - "system/supervised/tray_supervised_user.h", - "system/system_clock_observer.cc", - "system/system_clock_observer.h", - "system/system_notifier.cc", - "system/system_notifier.h", - "system/tiles/tiles_default_view.cc", - "system/tiles/tiles_default_view.h", - "system/tiles/tray_tiles.cc", - "system/tiles/tray_tiles.h", - "system/toast/toast_data.cc", - "system/toast/toast_data.h", - "system/toast/toast_manager.cc", - "system/toast/toast_manager.h", - "system/toast/toast_overlay.cc", - "system/toast/toast_overlay.h", - "system/tray/actionable_view.cc", - "system/tray/actionable_view.h", - "system/tray/default_system_tray_delegate.cc", - "system/tray/default_system_tray_delegate.h", - "system/tray/fixed_sized_image_view.cc", - "system/tray/fixed_sized_image_view.h", - "system/tray/hover_highlight_view.cc", - "system/tray/hover_highlight_view.h", - "system/tray/ime_info.cc", - "system/tray/ime_info.h", - "system/tray/label_tray_view.cc", - "system/tray/label_tray_view.h", - "system/tray/size_range_layout.cc", - "system/tray/size_range_layout.h", - "system/tray/special_popup_row.cc", - "system/tray/special_popup_row.h", - "system/tray/system_menu_button.cc", - "system/tray/system_menu_button.h", - "system/tray/system_tray.cc", - "system/tray/system_tray.h", - "system/tray/system_tray_bubble.cc", - "system/tray/system_tray_bubble.h", - "system/tray/system_tray_controller.cc", - "system/tray/system_tray_controller.h", - "system/tray/system_tray_delegate.cc", - "system/tray/system_tray_delegate.h", - "system/tray/system_tray_item.cc", - "system/tray/system_tray_item.h", - "system/tray/system_tray_notifier.cc", - "system/tray/system_tray_notifier.h", - "system/tray/throbber_view.cc", - "system/tray/throbber_view.h", - "system/tray/tray_background_view.cc", - "system/tray/tray_background_view.h", - "system/tray/tray_bubble_wrapper.cc", - "system/tray/tray_bubble_wrapper.h", - "system/tray/tray_constants.cc", - "system/tray/tray_constants.h", - "system/tray/tray_details_view.cc", - "system/tray/tray_details_view.h", - "system/tray/tray_event_filter.cc", - "system/tray/tray_event_filter.h", - "system/tray/tray_image_item.cc", - "system/tray/tray_image_item.h", - "system/tray/tray_item_more.cc", - "system/tray/tray_item_more.h", - "system/tray/tray_item_view.cc", - "system/tray/tray_item_view.h", - "system/tray/tray_notification_view.cc", - "system/tray/tray_notification_view.h", - "system/tray/tray_popup_header_button.cc", - "system/tray/tray_popup_header_button.h", - "system/tray/tray_popup_ink_drop_style.h", - "system/tray/tray_popup_item_container.cc", - "system/tray/tray_popup_item_container.h", - "system/tray/tray_popup_item_style.cc", - "system/tray/tray_popup_item_style.h", - "system/tray/tray_popup_utils.cc", - "system/tray/tray_popup_utils.h", - "system/tray/tray_utils.cc", - "system/tray/tray_utils.h", - "system/tray/tri_view.cc", - "system/tray/tri_view.h", - "system/tray/view_click_listener.h", - "system/tray_accessibility.cc", - "system/tray_accessibility.h", - "system/tray_caps_lock.cc", - "system/tray_caps_lock.h", - "system/tray_tracing.cc", - "system/tray_tracing.h", - "system/update/tray_update.cc", - "system/update/tray_update.h", - "system/user/button_from_view.cc", - "system/user/button_from_view.h", - "system/user/login_status.cc", - "system/user/login_status.h", - "system/user/rounded_image_view.cc", - "system/user/rounded_image_view.h", - "system/user/tray_user.cc", - "system/user/tray_user.h", - "system/user/user_card_view.cc", - "system/user/user_card_view.h", - "system/user/user_observer.h", - "system/user/user_view.cc", - "system/user/user_view.h", - "system/virtual_keyboard/virtual_keyboard_observer.h", - "system/virtual_keyboard/virtual_keyboard_tray.cc", - "system/virtual_keyboard/virtual_keyboard_tray.h", - "system/web_notification/ash_popup_alignment_delegate.cc", - "system/web_notification/ash_popup_alignment_delegate.h", - "system/web_notification/web_notification_tray.cc", - "system/web_notification/web_notification_tray.h", + "system/chromeos/power/power_event_observer.cc", + "system/chromeos/power/power_event_observer.h", + "system/chromeos/power/tablet_power_button_controller.cc", + "system/chromeos/power/tablet_power_button_controller.h", + "system/chromeos/power/video_activity_notifier.cc", + "system/chromeos/power/video_activity_notifier.h", + "system/chromeos/rotation/tray_rotation_lock.cc", + "system/chromeos/rotation/tray_rotation_lock.h", + "system/chromeos/screen_layout_observer.cc", + "system/chromeos/screen_layout_observer.h", "touch/ash_touch_transform_controller.cc", "touch/ash_touch_transform_controller.h", "touch/touch_hud_debug.cc", @@ -625,107 +749,46 @@ "utility/screenshot_controller.h", "virtual_keyboard_controller.cc", "virtual_keyboard_controller.h", - "wm/always_on_top_controller.cc", - "wm/always_on_top_controller.h", "wm/ash_focus_rules.cc", "wm/ash_focus_rules.h", "wm/ash_native_cursor_manager.cc", "wm/ash_native_cursor_manager.h", "wm/boot_splash_screen_chromeos.cc", "wm/boot_splash_screen_chromeos.h", - "wm/container_finder.cc", - "wm/container_finder.h", "wm/cursor_manager_chromeos.cc", "wm/cursor_manager_chromeos.h", - "wm/default_state.cc", - "wm/default_state.h", - "wm/default_window_resizer.cc", - "wm/default_window_resizer.h", - "wm/dock/docked_window_layout_manager.cc", - "wm/dock/docked_window_layout_manager.h", - "wm/dock/docked_window_layout_manager_observer.h", - "wm/dock/docked_window_resizer.cc", - "wm/dock/docked_window_resizer.h", - "wm/drag_details.cc", - "wm/drag_details.h", "wm/drag_window_controller.cc", "wm/drag_window_controller.h", "wm/drag_window_resizer.cc", "wm/drag_window_resizer.h", "wm/event_client_impl.cc", "wm/event_client_impl.h", - "wm/focus_rules.cc", - "wm/focus_rules.h", - "wm/fullscreen_window_finder.cc", - "wm/fullscreen_window_finder.h", "wm/gestures/overview_gesture_handler.cc", "wm/gestures/overview_gesture_handler.h", - "wm/immersive_context_ash.cc", - "wm/immersive_context_ash.h", "wm/immersive_focus_watcher_aura.cc", "wm/immersive_focus_watcher_aura.h", "wm/immersive_gesture_handler_aura.cc", "wm/immersive_gesture_handler_aura.h", "wm/immersive_handler_factory_ash.cc", "wm/immersive_handler_factory_ash.h", - "wm/lock_layout_manager.cc", - "wm/lock_layout_manager.h", "wm/lock_state_controller.cc", "wm/lock_state_controller.h", - "wm/lock_state_observer.h", - "wm/lock_window_state.cc", - "wm/lock_window_state.h", - "wm/maximize_mode/maximize_mode_controller.cc", - "wm/maximize_mode/maximize_mode_controller.h", - "wm/maximize_mode/maximize_mode_event_handler.cc", - "wm/maximize_mode/maximize_mode_event_handler.h", "wm/maximize_mode/maximize_mode_event_handler_aura.cc", "wm/maximize_mode/maximize_mode_event_handler_aura.h", - "wm/maximize_mode/maximize_mode_window_manager.cc", - "wm/maximize_mode/maximize_mode_window_manager.h", - "wm/maximize_mode/maximize_mode_window_state.cc", - "wm/maximize_mode/maximize_mode_window_state.h", - "wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h", "wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.cc", "wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h", "wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.cc", "wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h", - "wm/maximize_mode/workspace_backdrop_delegate.cc", - "wm/maximize_mode/workspace_backdrop_delegate.h", - "wm/mru_window_tracker.cc", - "wm/mru_window_tracker.h", "wm/overlay_event_filter.cc", "wm/overlay_event_filter.h", - "wm/overview/cleanup_animation_observer.cc", - "wm/overview/cleanup_animation_observer.h", - "wm/overview/overview_animation_type.h", - "wm/overview/scoped_overview_animation_settings.h", "wm/overview/scoped_overview_animation_settings_aura.cc", "wm/overview/scoped_overview_animation_settings_aura.h", - "wm/overview/scoped_overview_animation_settings_factory.cc", - "wm/overview/scoped_overview_animation_settings_factory.h", "wm/overview/scoped_overview_animation_settings_factory_aura.cc", "wm/overview/scoped_overview_animation_settings_factory_aura.h", - "wm/overview/scoped_transform_overview_window.cc", - "wm/overview/scoped_transform_overview_window.h", - "wm/overview/window_grid.cc", - "wm/overview/window_grid.h", - "wm/overview/window_selector.cc", - "wm/overview/window_selector.h", - "wm/overview/window_selector_controller.cc", - "wm/overview/window_selector_controller.h", - "wm/overview/window_selector_item.cc", - "wm/overview/window_selector_item.h", "wm/panels/attached_panel_window_targeter.cc", "wm/panels/attached_panel_window_targeter.h", - "wm/panels/panel_frame_view.cc", - "wm/panels/panel_frame_view.h", - "wm/panels/panel_layout_manager.cc", - "wm/panels/panel_layout_manager.h", "wm/panels/panel_window_event_handler.cc", "wm/panels/panel_window_event_handler.h", - "wm/panels/panel_window_resizer.cc", - "wm/panels/panel_window_resizer.h", "wm/power_button_controller.cc", "wm/power_button_controller.h", "wm/resize_handle_window_targeter.cc", @@ -734,12 +797,6 @@ "wm/resize_shadow.h", "wm/resize_shadow_controller.cc", "wm/resize_shadow_controller.h", - "wm/root_window_finder.cc", - "wm/root_window_finder.h", - "wm/root_window_layout_manager.cc", - "wm/root_window_layout_manager.h", - "wm/screen_dimmer.cc", - "wm/screen_dimmer.h", "wm/screen_pinning_controller.cc", "wm/screen_pinning_controller.h", "wm/session_state_animator.cc", @@ -748,88 +805,31 @@ "wm/session_state_animator_impl.h", "wm/stacking_controller.cc", "wm/stacking_controller.h", - "wm/switchable_windows.cc", - "wm/switchable_windows.h", "wm/system_gesture_event_filter.cc", "wm/system_gesture_event_filter.h", "wm/system_modal_container_event_filter.cc", "wm/system_modal_container_event_filter.h", "wm/system_modal_container_event_filter_delegate.h", - "wm/system_modal_container_layout_manager.cc", - "wm/system_modal_container_layout_manager.h", "wm/system_wallpaper_controller.cc", "wm/system_wallpaper_controller.h", "wm/toplevel_window_event_handler.cc", "wm/toplevel_window_event_handler.h", "wm/video_detector.cc", "wm/video_detector.h", - "wm/window_animation_types.h", "wm/window_animations.cc", "wm/window_animations.h", - "wm/window_cycle_controller.cc", - "wm/window_cycle_controller.h", - "wm/window_cycle_event_filter.h", "wm/window_cycle_event_filter_aura.cc", "wm/window_cycle_event_filter_aura.h", - "wm/window_cycle_list.cc", - "wm/window_cycle_list.h", - "wm/window_dimmer.cc", - "wm/window_dimmer.h", "wm/window_mirror_view.cc", "wm/window_mirror_view.h", - "wm/window_parenting_utils.cc", - "wm/window_parenting_utils.h", - "wm/window_positioner.cc", - "wm/window_positioner.h", - "wm/window_positioning_utils.cc", - "wm/window_positioning_utils.h", "wm/window_properties.cc", "wm/window_properties.h", - "wm/window_resizer.cc", - "wm/window_resizer.h", - "wm/window_state.cc", - "wm/window_state.h", "wm/window_state_aura.cc", "wm/window_state_aura.h", - "wm/window_state_delegate.cc", - "wm/window_state_delegate.h", - "wm/window_state_observer.h", - "wm/window_state_util.cc", - "wm/window_state_util.h", "wm/window_util.cc", "wm/window_util.h", - "wm/wm_event.cc", - "wm/wm_event.h", - "wm/wm_screen_util.cc", - "wm/wm_screen_util.h", - "wm/wm_snap_to_pixel_layout_manager.cc", - "wm/wm_snap_to_pixel_layout_manager.h", - "wm/wm_toplevel_window_event_handler.cc", - "wm/wm_toplevel_window_event_handler.h", - "wm/wm_types.cc", - "wm/wm_types.h", - "wm/wm_window_animations.cc", - "wm/wm_window_animations.h", - "wm/workspace/magnetism_matcher.cc", - "wm/workspace/magnetism_matcher.h", - "wm/workspace/multi_window_resize_controller.cc", - "wm/workspace/multi_window_resize_controller.h", - "wm/workspace/phantom_window_controller.cc", - "wm/workspace/phantom_window_controller.h", - "wm/workspace/two_step_edge_cycler.cc", - "wm/workspace/two_step_edge_cycler.h", - "wm/workspace/workspace_event_handler.cc", - "wm/workspace/workspace_event_handler.h", "wm/workspace/workspace_event_handler_aura.cc", "wm/workspace/workspace_event_handler_aura.h", - "wm/workspace/workspace_layout_manager.cc", - "wm/workspace/workspace_layout_manager.h", - "wm/workspace/workspace_layout_manager_backdrop_delegate.h", - "wm/workspace/workspace_types.h", - "wm/workspace/workspace_window_resizer.cc", - "wm/workspace/workspace_window_resizer.h", - "wm/workspace_controller.cc", - "wm/workspace_controller.h", ] configs += [ "//build/config:precompiled_headers" ] @@ -1153,96 +1153,96 @@ sources = [ "accelerators/accelerator_controller_unittest.cc", "accelerators/accelerator_filter_unittest.cc", - "accelerators/accelerator_table_unittest.cc", "accelerators/spoken_feedback_toggler_unittest.cc", "ash_touch_exploration_manager_chromeos_unittest.cc", "autoclick/autoclick_unittest.cc", + "common/accelerators/accelerator_table_unittest.cc", "common/devtools/ash_devtools_unittest.cc", + "common/drag_drop/drag_image_view_unittest.cc", + "common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc", + "common/frame/custom_frame_view_ash_unittest.cc", + "common/frame/default_header_painter_unittest.cc", + "common/metrics/pointer_metrics_recorder_unittest.cc", "common/mus_property_mirror_ash_unittest.cc", "common/session/session_controller_unittest.cc", + "common/shelf/shelf_application_menu_model_unittest.cc", + "common/shelf/shelf_background_animator_unittest.cc", + "common/shelf/shelf_button_pressed_metric_tracker_unittest.cc", + "common/shelf/shelf_locking_manager_unittest.cc", + "common/shelf/shelf_model_unittest.cc", + "common/shelf/shelf_tooltip_manager_unittest.cc", + "common/shelf/shelf_window_watcher_unittest.cc", + "common/system/chromeos/audio/tray_audio_unittest.cc", + "common/system/chromeos/brightness/tray_brightness_unittest.cc", + "common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc", + "common/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc", + "common/system/chromeos/network/sms_observer_unittest.cc", + "common/system/chromeos/network/vpn_list_unittest.cc", + "common/system/chromeos/palette/mock_palette_tool_delegate.cc", + "common/system/chromeos/palette/mock_palette_tool_delegate.h", + "common/system/chromeos/palette/palette_tool_manager_unittest.cc", + "common/system/chromeos/palette/tools/create_note_unittest.cc", + "common/system/chromeos/palette/tools/screenshot_unittest.cc", + "common/system/chromeos/power/power_status_unittest.cc", + "common/system/chromeos/power/power_status_view_unittest.cc", + "common/system/chromeos/power/tray_power_unittest.cc", + "common/system/chromeos/screen_security/screen_tray_item_unittest.cc", + "common/system/chromeos/session/logout_confirmation_controller_unittest.cc", + "common/system/chromeos/session/tray_session_length_limit_unittest.cc", + "common/system/chromeos/supervised/tray_supervised_user_unittest.cc", + "common/system/date/date_view_unittest.cc", + "common/system/date/system_info_default_view_unittest.cc", + "common/system/ime/tray_ime_chromeos_unittest.cc", + "common/system/tiles/tray_tiles_unittest.cc", + "common/system/tray/size_range_layout_unittest.cc", + "common/system/tray/system_tray_unittest.cc", + "common/system/tray/tray_details_view_unittest.cc", + "common/system/tray/tri_view_unittest.cc", + "common/system/update/tray_update_unittest.cc", + "common/system/user/tray_user_unittest.cc", "common/wallpaper/wallpaper_controller_unittest.cc", + "common/wm/container_finder_unittest.cc", + "common/wm/mru_window_tracker_unittest.cc", + "common/wm/overview/cleanup_animation_observer_unittest.cc", + "common/wm/workspace/workspace_layout_manager_unittest.cc", "common/wm_window_unittest.cc", "common/wm_window_user_data_unittest.cc", - "drag_drop/drag_image_view_unittest.cc", "first_run/first_run_helper_unittest.cc", "focus_cycler_unittest.cc", - "frame/caption_buttons/frame_caption_button_container_view_unittest.cc", "frame/caption_buttons/frame_size_button_unittest.cc", - "frame/custom_frame_view_ash_unittest.cc", - "frame/default_header_painter_unittest.cc", "laser/laser_pointer_controller_unittest.cc", "laser/laser_pointer_points_unittest.cc", "laser/laser_segment_utils_unittest.cc", "metrics/desktop_task_switch_metric_recorder_unittest.cc", - "metrics/pointer_metrics_recorder_unittest.cc", "metrics/task_switch_metrics_recorder_unittest.cc", "metrics/task_switch_time_tracker_unittest.cc", "metrics/user_metrics_recorder_unittest.cc", "root_window_controller_unittest.cc", "rotator/screen_rotation_animation_unittest.cc", "screen_util_unittest.cc", - "shelf/shelf_application_menu_model_unittest.cc", - "shelf/shelf_background_animator_unittest.cc", - "shelf/shelf_button_pressed_metric_tracker_unittest.cc", "shelf/shelf_layout_manager_unittest.cc", - "shelf/shelf_locking_manager_unittest.cc", - "shelf/shelf_model_unittest.cc", - "shelf/shelf_tooltip_manager_unittest.cc", "shelf/shelf_unittest.cc", "shelf/shelf_view_unittest.cc", "shelf/shelf_widget_unittest.cc", - "shelf/shelf_window_watcher_unittest.cc", "shell_unittest.cc", "sticky_keys/sticky_keys_overlay_unittest.cc", "sticky_keys/sticky_keys_unittest.cc", - "system/audio/tray_audio_unittest.cc", - "system/brightness/tray_brightness_unittest.cc", - "system/date/date_view_unittest.cc", - "system/date/system_info_default_view_unittest.cc", - "system/ime/tray_ime_chromeos_unittest.cc", - "system/ime_menu/ime_menu_tray_unittest.cc", - "system/media_security/multi_profile_media_tray_item_unittest.cc", - "system/network/sms_observer_unittest.cc", - "system/network/vpn_list_unittest.cc", + "system/chromeos/power/power_event_observer_unittest.cc", + "system/chromeos/power/tablet_power_button_controller_unittest.cc", + "system/chromeos/power/video_activity_notifier_unittest.cc", "system/overview/overview_button_tray_unittest.cc", - "system/palette/mock_palette_tool_delegate.cc", - "system/palette/mock_palette_tool_delegate.h", - "system/palette/palette_tool_manager_unittest.cc", - "system/palette/tools/create_note_unittest.cc", - "system/palette/tools/screenshot_unittest.cc", - "system/power/power_event_observer_unittest.cc", - "system/power/power_status_unittest.cc", - "system/power/power_status_view_unittest.cc", - "system/power/tablet_power_button_controller_unittest.cc", - "system/power/tray_power_unittest.cc", - "system/power/video_activity_notifier_unittest.cc", - "system/screen_security/screen_tray_item_unittest.cc", - "system/session/logout_confirmation_controller_unittest.cc", - "system/session/tray_session_length_limit_unittest.cc", - "system/supervised/tray_supervised_user_unittest.cc", - "system/tiles/tray_tiles_unittest.cc", "system/toast/toast_manager_unittest.cc", - "system/tray/size_range_layout_unittest.cc", - "system/tray/system_tray_unittest.cc", - "system/tray/tray_details_view_unittest.cc", - "system/tray/tri_view_unittest.cc", - "system/update/tray_update_unittest.cc", - "system/user/tray_user_unittest.cc", "system/web_notification/ash_popup_alignment_delegate_unittest.cc", "system/web_notification/web_notification_tray_unittest.cc", "test/ash_test_helper_unittest.cc", "tooltips/tooltip_controller_unittest.cc", "wm/ash_focus_rules_unittest.cc", - "wm/container_finder_unittest.cc", "wm/dock/docked_window_layout_manager_unittest.cc", "wm/dock/docked_window_resizer_unittest.cc", "wm/immersive_fullscreen_controller_unittest.cc", "wm/lock_state_controller_unittest.cc", "wm/maximize_mode/accelerometer_test_data_literals.cc", "wm/maximize_mode/maximize_mode_window_manager_unittest.cc", - "wm/mru_window_tracker_unittest.cc", - "wm/overview/cleanup_animation_observer_unittest.cc", - "wm/workspace/workspace_layout_manager_unittest.cc", ] deps = [ "//ash", @@ -1331,11 +1331,11 @@ "magnifier/partial_magnification_controller_unittest.cc", # TODO: investigate failure in mash, http://crbug.com/695887. - "system/rotation/tray_rotation_lock_unittest.cc", + "system/chromeos/rotation/tray_rotation_lock_unittest.cc", # TODO: fails as ScreenLayoutObserver is not installed in mash, # http://crbug.com/696752. - "system/screen_layout_observer_unittest.cc", + "system/chromeos/screen_layout_observer_unittest.cc", "test/ash_test_suite.cc", "test/ash_test_suite.h", "test/ash_unittests.cc",
diff --git a/ash/accelerators/accelerator_commands.cc b/ash/accelerators/accelerator_commands.cc deleted file mode 100644 index 7c34110..0000000 --- a/ash/accelerators/accelerator_commands.cc +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/accelerator_commands.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "base/metrics/user_metrics.h" - -namespace ash { -namespace accelerators { - -bool ToggleMinimized() { - WmWindow* window = WmShell::Get()->GetActiveWindow(); - // Attempt to restore the window that would be cycled through next from - // the launcher when there is no active window. - if (!window) { - MruWindowTracker::WindowList mru_windows( - WmShell::Get()->mru_window_tracker()->BuildMruWindowList()); - if (!mru_windows.empty()) - mru_windows.front()->GetWindowState()->Activate(); - return true; - } - wm::WindowState* window_state = window->GetWindowState(); - if (!window_state->CanMinimize()) - return false; - window_state->Minimize(); - return true; -} - -void ToggleMaximized() { - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - if (!active_window) - return; - base::RecordAction(base::UserMetricsAction("Accel_Toggle_Maximized")); - wm::WMEvent event(wm::WM_EVENT_TOGGLE_MAXIMIZE); - active_window->GetWindowState()->OnWMEvent(&event); -} - -void ToggleFullscreen() { - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - if (!active_window) - return; - const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); - active_window->GetWindowState()->OnWMEvent(&event); -} - -} // namespace accelerators -} // namespace ash
diff --git a/ash/accelerators/accelerator_commands.h b/ash/accelerators/accelerator_commands.h deleted file mode 100644 index df576ba..0000000 --- a/ash/accelerators/accelerator_commands.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_ACCELERATOR_COMMANDS_H_ -#define ASH_ACCELERATORS_ACCELERATOR_COMMANDS_H_ - -#include "ash/ash_export.h" - -// This file contains implementations of commands that are bound to keyboard -// shortcuts in Ash or in the embedding application (e.g. Chrome). -namespace ash { -namespace accelerators { - -// Minimizes the active window, if present. If no windows are active, restores -// the first unminimized window. Returns true if a window was minimized or -// restored. -ASH_EXPORT bool ToggleMinimized(); - -// Toggles the maxmized state. If the window is in fulllscreen, it exits -// fullscreen mode. -ASH_EXPORT void ToggleMaximized(); - -// Toggles the fullscreen state. The behavior can be overridden -// by WindowStateDelegate::ToggleFullscreen(). -ASH_EXPORT void ToggleFullscreen(); - -} // namespace accelerators -} // namespace ash - -#endif // ASH_ACCELERATORS_ACCELERATOR_COMMANDS_H_
diff --git a/ash/accelerators/accelerator_commands_aura.cc b/ash/accelerators/accelerator_commands_aura.cc index e78f996..88ad889 100644 --- a/ash/accelerators/accelerator_commands_aura.cc +++ b/ash/accelerators/accelerator_commands_aura.cc
@@ -4,10 +4,10 @@ #include "ash/accelerators/accelerator_commands_aura.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/shell.h" #include "ash/wm/screen_pinning_controller.h" -#include "ash/wm/window_state.h" #include "base/metrics/user_metrics.h" #include "ui/display/manager/display_manager.h" #include "ui/display/manager/managed_display_info.h"
diff --git a/ash/accelerators/accelerator_commands_unittest.cc b/ash/accelerators/accelerator_commands_unittest.cc index 8c56ef3..04661ab 100644 --- a/ash/accelerators/accelerator_commands_unittest.cc +++ b/ash/accelerators/accelerator_commands_unittest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_commands.h" +#include "ash/common/accelerators/accelerator_commands.h" #include <memory> #include "ash/accelerators/accelerator_commands_aura.h" +#include "ash/common/wm/window_state.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "ui/aura/window.h"
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc deleted file mode 100644 index 21eda7d2..0000000 --- a/ash/accelerators/accelerator_controller.cc +++ /dev/null
@@ -1,1173 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/accelerator_controller.h" - -#include <utility> - -#include "ash/accelerators/accelerator_commands.h" -#include "ash/accelerators/accelerator_controller_delegate.h" -#include "ash/accelerators/debug_commands.h" -#include "ash/common/accessibility_delegate.h" -#include "ash/common/accessibility_types.h" -#include "ash/common/focus_cycler.h" -#include "ash/common/ime_control_delegate.h" -#include "ash/common/media_controller.h" -#include "ash/common/multi_profile_uma.h" -#include "ash/common/new_window_controller.h" -#include "ash/common/palette_delegate.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/brightness_control_delegate.h" -#include "ash/system/ime_menu/ime_menu_tray.h" -#include "ash/system/keyboard_brightness_control_delegate.h" -#include "ash/system/palette/palette_tray.h" -#include "ash/system/palette/palette_utils.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/web_notification/web_notification_tray.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/window_cycle_controller.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/user_metrics.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/base/accelerators/accelerator_manager.h" -#include "ui/base/ime/chromeos/ime_keyboard.h" -#include "ui/base/ime/chromeos/input_method_manager.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/message_center/message_center.h" - -namespace ash { -namespace { - -using base::UserMetricsAction; -using message_center::Notification; - -// Identifier for the high contrast toggle accelerator notification. -const char kHighContrastToggleAccelNotificationId[] = - "chrome://settings/accessibility/highcontrast"; - -ui::Accelerator CreateAccelerator(ui::KeyboardCode keycode, - int modifiers, - bool trigger_on_press) { - ui::Accelerator accelerator(keycode, modifiers); - accelerator.set_type(trigger_on_press ? ui::ET_KEY_PRESSED - : ui::ET_KEY_RELEASED); - return accelerator; -} - -void RecordUmaHistogram(const char* histogram_name, - DeprecatedAcceleratorUsage sample) { - auto* histogram = base::LinearHistogram::FactoryGet( - histogram_name, 1, DEPRECATED_USAGE_COUNT, DEPRECATED_USAGE_COUNT + 1, - base::HistogramBase::kUmaTargetedHistogramFlag); - histogram->Add(sample); -} - -void HandleCycleBackwardMRU(const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_TAB) - base::RecordAction(base::UserMetricsAction("Accel_PrevWindow_Tab")); - - WmShell::Get()->window_cycle_controller()->HandleCycleWindow( - WindowCycleController::BACKWARD); -} - -void HandleCycleForwardMRU(const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_TAB) - base::RecordAction(base::UserMetricsAction("Accel_NextWindow_Tab")); - - WmShell::Get()->window_cycle_controller()->HandleCycleWindow( - WindowCycleController::FORWARD); -} - -void HandleRotatePaneFocus(FocusCycler::Direction direction) { - switch (direction) { - // TODO(stevet): Not sure if this is the same as IDC_FOCUS_NEXT_PANE. - case FocusCycler::FORWARD: { - base::RecordAction(UserMetricsAction("Accel_Focus_Next_Pane")); - break; - } - case FocusCycler::BACKWARD: { - base::RecordAction(UserMetricsAction("Accel_Focus_Previous_Pane")); - break; - } - } - WmShell::Get()->focus_cycler()->RotateFocus(direction); -} - -void HandleFocusShelf() { - base::RecordAction(UserMetricsAction("Accel_Focus_Shelf")); - // TODO(jamescook): Should this be GetRootWindowForNewWindows()? - WmShelf* shelf = WmShelf::ForWindow(WmShell::Get()->GetPrimaryRootWindow()); - WmShell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget()); -} - -void HandleLaunchAppN(int n) { - base::RecordAction(UserMetricsAction("Accel_Launch_App")); - WmShelf::LaunchShelfItem(n); -} - -void HandleLaunchLastApp() { - base::RecordAction(UserMetricsAction("Accel_Launch_Last_App")); - WmShelf::LaunchShelfItem(-1); -} - -void HandleMediaNextTrack() { - WmShell::Get()->media_controller()->HandleMediaNextTrack(); -} - -void HandleMediaPlayPause() { - WmShell::Get()->media_controller()->HandleMediaPlayPause(); -} - -void HandleMediaPrevTrack() { - WmShell::Get()->media_controller()->HandleMediaPrevTrack(); -} - -bool CanHandleNewIncognitoWindow() { - return WmShell::Get()->delegate()->IsIncognitoAllowed(); -} - -void HandleNewIncognitoWindow() { - base::RecordAction(UserMetricsAction("Accel_New_Incognito_Window")); - WmShell::Get()->new_window_controller()->NewWindow(true /* is_incognito */); -} - -void HandleNewTab(const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_T) - base::RecordAction(UserMetricsAction("Accel_NewTab_T")); - WmShell::Get()->new_window_controller()->NewTab(); -} - -void HandleNewWindow() { - base::RecordAction(UserMetricsAction("Accel_New_Window")); - WmShell::Get()->new_window_controller()->NewWindow(false /* is_incognito */); -} - -bool CanHandleNextIme(ImeControlDelegate* ime_control_delegate) { - return ime_control_delegate && ime_control_delegate->CanCycleIme(); -} - -bool CanHandleCycleMru(const ui::Accelerator& accelerator) { - // Don't do anything when Alt+Tab is hit while a virtual keyboard is showing. - // Touchscreen users have better window switching options. It would be - // preferable if we could tell whether this event actually came from a virtual - // keyboard, but there's no easy way to do so, thus we block Alt+Tab when the - // virtual keyboard is showing, even if it came from a real keyboard. See - // http://crbug.com/638269 - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - return !(keyboard_controller && keyboard_controller->keyboard_visible()); -} - -void HandleNextIme(ImeControlDelegate* ime_control_delegate) { - base::RecordAction(UserMetricsAction("Accel_Next_Ime")); - ime_control_delegate->HandleNextIme(); -} - -void HandleOpenFeedbackPage() { - base::RecordAction(UserMetricsAction("Accel_Open_Feedback_Page")); - WmShell::Get()->new_window_controller()->OpenFeedbackPage(); -} - -bool CanHandlePreviousIme(ImeControlDelegate* ime_control_delegate) { - return ime_control_delegate && ime_control_delegate->CanCycleIme(); -} - -void HandlePreviousIme(ImeControlDelegate* ime_control_delegate, - const ui::Accelerator& accelerator) { - base::RecordAction(UserMetricsAction("Accel_Previous_Ime")); - if (accelerator.type() == ui::ET_KEY_PRESSED) - ime_control_delegate->HandlePreviousIme(); - // Else: consume the Ctrl+Space ET_KEY_RELEASED event but do not do anything. -} - -void HandleRestoreTab() { - base::RecordAction(UserMetricsAction("Accel_Restore_Tab")); - WmShell::Get()->new_window_controller()->RestoreTab(); -} - -void HandleShowKeyboardOverlay() { - base::RecordAction(UserMetricsAction("Accel_Show_Keyboard_Overlay")); - WmShell::Get()->new_window_controller()->ShowKeyboardOverlay(); -} - -bool CanHandleShowMessageCenterBubble() { - WmWindow* target_root = WmShell::Get()->GetRootWindowForNewWindows(); - StatusAreaWidget* status_area_widget = - WmShelf::ForWindow(target_root)->shelf_widget()->status_area_widget(); - return status_area_widget && - status_area_widget->web_notification_tray()->visible(); -} - -void HandleShowMessageCenterBubble() { - base::RecordAction(UserMetricsAction("Accel_Show_Message_Center_Bubble")); - WmWindow* target_root = WmShell::Get()->GetRootWindowForNewWindows(); - StatusAreaWidget* status_area_widget = - WmShelf::ForWindow(target_root)->shelf_widget()->status_area_widget(); - if (status_area_widget) { - WebNotificationTray* notification_tray = - status_area_widget->web_notification_tray(); - if (notification_tray->visible()) - notification_tray->ShowMessageCenterBubble(); - } -} - -void HandleShowTaskManager() { - base::RecordAction(UserMetricsAction("Accel_Show_Task_Manager")); - WmShell::Get()->new_window_controller()->ShowTaskManager(); -} - -bool CanHandleSwitchIme(ImeControlDelegate* ime_control_delegate, - const ui::Accelerator& accelerator) { - return ime_control_delegate && - ime_control_delegate->CanSwitchIme(accelerator); -} - -void HandleSwitchIme(ImeControlDelegate* ime_control_delegate, - const ui::Accelerator& accelerator) { - base::RecordAction(UserMetricsAction("Accel_Switch_Ime")); - ime_control_delegate->HandleSwitchIme(accelerator); -} - -bool CanHandleToggleAppList(const ui::Accelerator& accelerator, - const ui::Accelerator& previous_accelerator) { - if (accelerator.key_code() == ui::VKEY_LWIN) { - // If something else was pressed between the Search key (LWIN) - // being pressed and released, then ignore the release of the - // Search key. - if (previous_accelerator.type() != ui::ET_KEY_PRESSED || - previous_accelerator.key_code() != ui::VKEY_LWIN) { - return false; - } - - // When spoken feedback is enabled, we should neither toggle the list nor - // consume the key since Search+Shift is one of the shortcuts the a11y - // feature uses. crbug.com/132296 - if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled()) - return false; - } - return true; -} - -void HandleToggleAppList(const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_LWIN) - base::RecordAction(UserMetricsAction("Accel_Search_LWin")); - WmShell::Get()->ToggleAppList(); -} - -void HandleToggleFullscreen(const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_MEDIA_LAUNCH_APP2) - base::RecordAction(UserMetricsAction("Accel_Fullscreen_F4")); - accelerators::ToggleFullscreen(); -} - -void HandleToggleOverview() { - base::RecordAction(base::UserMetricsAction("Accel_Overview_F5")); - WmShell::Get()->window_selector_controller()->ToggleOverview(); -} - -bool CanHandleWindowSnapOrDock() { - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - if (!active_window) - return false; - wm::WindowState* window_state = active_window->GetWindowState(); - // Disable window snapping shortcut key for full screen window due to - // http://crbug.com/135487. - return (window_state && window_state->IsUserPositionable() && - !window_state->IsFullscreen()); -} - -void HandleWindowSnapOrDock(AcceleratorAction action) { - if (action == WINDOW_CYCLE_SNAP_DOCK_LEFT) - base::RecordAction(UserMetricsAction("Accel_Window_Snap_Left")); - else - base::RecordAction(UserMetricsAction("Accel_Window_Snap_Right")); - - const wm::WMEvent event(action == WINDOW_CYCLE_SNAP_DOCK_LEFT - ? wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT - : wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT); - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - DCHECK(active_window); - active_window->GetWindowState()->OnWMEvent(&event); -} - -void HandleWindowMinimize() { - base::RecordAction(base::UserMetricsAction("Accel_Toggle_Minimized_Minus")); - accelerators::ToggleMinimized(); -} - -bool CanHandlePositionCenter() { - // Docked windows do not support centering. - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - return (active_window && !active_window->GetWindowState()->IsDocked()); -} - -void HandlePositionCenter() { - base::RecordAction(UserMetricsAction("Accel_Window_Position_Center")); - wm::CenterWindow(WmShell::Get()->GetActiveWindow()); -} - -void HandleShowImeMenuBubble() { - base::RecordAction(UserMetricsAction("Accel_Show_Ime_Menu_Bubble")); - - StatusAreaWidget* status_area_widget = - WmShelf::ForWindow(WmShell::Get()->GetPrimaryRootWindow()) - ->GetStatusAreaWidget(); - if (status_area_widget) { - ImeMenuTray* ime_menu_tray = status_area_widget->ime_menu_tray(); - if (ime_menu_tray && ime_menu_tray->visible() && - !ime_menu_tray->IsImeMenuBubbleShown()) { - ime_menu_tray->ShowImeMenuBubble(); - } - } -} - -void HandleCrosh() { - base::RecordAction(UserMetricsAction("Accel_Open_Crosh")); - - WmShell::Get()->new_window_controller()->OpenCrosh(); -} - -bool CanHandleDisableCapsLock(const ui::Accelerator& previous_accelerator) { - ui::KeyboardCode previous_key_code = previous_accelerator.key_code(); - if (previous_accelerator.type() == ui::ET_KEY_RELEASED || - (previous_key_code != ui::VKEY_LSHIFT && - previous_key_code != ui::VKEY_SHIFT && - previous_key_code != ui::VKEY_RSHIFT)) { - // If something else was pressed between the Shift key being pressed - // and released, then ignore the release of the Shift key. - return false; - } - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - chromeos::input_method::ImeKeyboard* keyboard = - ime ? ime->GetImeKeyboard() : NULL; - return (keyboard && keyboard->CapsLockIsEnabled()); -} - -void HandleDisableCapsLock() { - base::RecordAction(UserMetricsAction("Accel_Disable_Caps_Lock")); - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - ime->GetImeKeyboard()->SetCapsLockEnabled(false); -} - -void HandleFileManager() { - base::RecordAction(UserMetricsAction("Accel_Open_File_Manager")); - - WmShell::Get()->new_window_controller()->OpenFileManager(); -} - -void HandleGetHelp() { - WmShell::Get()->new_window_controller()->OpenGetHelp(); -} - -bool CanHandleLock() { - return WmShell::Get()->GetSessionStateDelegate()->CanLockScreen(); -} - -void HandleLock() { - base::RecordAction(UserMetricsAction("Accel_LockScreen_L")); - WmShell::Get()->GetSessionStateDelegate()->LockScreen(); -} - -void HandleShowStylusTools() { - base::RecordAction(UserMetricsAction("Accel_Show_Stylus_Tools")); - - RootWindowController* root_window_controller = - WmShell::Get()->GetRootWindowForNewWindows()->GetRootWindowController(); - PaletteTray* palette_tray = - root_window_controller->GetShelf()->GetStatusAreaWidget()->palette_tray(); - palette_tray->ShowPalette(); -} - -bool CanHandleShowStylusTools() { - return WmShell::Get()->palette_delegate() && - WmShell::Get()->palette_delegate()->ShouldShowPalette(); -} - -void HandleSuspend() { - base::RecordAction(UserMetricsAction("Accel_Suspend")); - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestSuspend(); -} - -bool CanHandleCycleUser() { - return WmShell::Get()->delegate()->IsMultiProfilesEnabled() && - WmShell::Get()->GetSessionStateDelegate()->NumberOfLoggedInUsers() > 1; -} - -void HandleCycleUser(CycleUserDirection direction) { - MultiProfileUMA::RecordSwitchActiveUser( - MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR); - switch (direction) { - case CycleUserDirection::NEXT: - base::RecordAction(UserMetricsAction("Accel_Switch_To_Next_User")); - break; - case CycleUserDirection::PREVIOUS: - base::RecordAction(UserMetricsAction("Accel_Switch_To_Previous_User")); - break; - } - WmShell::Get()->GetSessionStateDelegate()->CycleActiveUser(direction); -} - -bool CanHandleToggleCapsLock(const ui::Accelerator& accelerator, - const ui::Accelerator& previous_accelerator) { - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - - // This shortcust is set to be trigger on release. Either the current - // accelerator is a Search release or Alt release. - if (accelerator.key_code() == ui::VKEY_LWIN && - accelerator.type() == ui::ET_KEY_RELEASED) { - // The previous must be either an Alt press or Search press: - // 1. Press Alt, Press Search, Release Search, Release Alt. - // 2. Press Search, Press Alt, Release Search, Release Alt. - if (previous_accelerator.type() == ui::ET_KEY_PRESSED && - (previous_accelerator.key_code() == ui::VKEY_LWIN || - previous_accelerator.key_code() == ui::VKEY_MENU)) { - return ime && ime->GetImeKeyboard(); - } - } - - // Alt release. - if (accelerator.key_code() == ui::VKEY_MENU && - accelerator.type() == ui::ET_KEY_RELEASED) { - // The previous must be either an Alt press or Search press: - // 3. Press Alt, Press Search, Release Alt, Release Search. - // 4. Press Search, Press Alt, Release Alt, Release Search. - if (previous_accelerator.type() == ui::ET_KEY_PRESSED && - (previous_accelerator.key_code() == ui::VKEY_LWIN || - previous_accelerator.key_code() == ui::VKEY_MENU)) { - return ime && ime->GetImeKeyboard(); - } - } - - return false; -} - -void HandleToggleCapsLock() { - base::RecordAction(UserMetricsAction("Accel_Toggle_Caps_Lock")); - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - chromeos::input_method::ImeKeyboard* keyboard = ime->GetImeKeyboard(); - keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled()); -} - -void HandleToggleHighContrast() { - base::RecordAction(UserMetricsAction("Accel_Toggle_High_Contrast")); - - // Show a notification so the user knows that this accelerator toggled - // high contrast mode, and that they can press it again to toggle back. - // The message center automatically only shows this once per session. - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, - kHighContrastToggleAccelNotificationId, base::string16() /* title */, - l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_ACCEL_MSG), - gfx::Image(CreateVectorIcon(kSystemMenuAccessibilityIcon, SK_ColorBLACK)), - base::string16() /* display source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierAccessibility), - message_center::RichNotificationData(), nullptr)); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); - - WmShell::Get()->accessibility_delegate()->ToggleHighContrast(); -} - -void HandleToggleSpokenFeedback() { - base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback")); - - WmShell::Get()->accessibility_delegate()->ToggleSpokenFeedback( - A11Y_NOTIFICATION_SHOW); -} - -void HandleVolumeDown(mojom::VolumeController* volume_controller, - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_VOLUME_DOWN) - base::RecordAction(UserMetricsAction("Accel_VolumeDown_F9")); - - if (volume_controller) - volume_controller->VolumeDown(); -} - -void HandleVolumeMute(mojom::VolumeController* volume_controller, - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_VOLUME_MUTE) - base::RecordAction(UserMetricsAction("Accel_VolumeMute_F8")); - - if (volume_controller) - volume_controller->VolumeMute(); -} - -void HandleVolumeUp(mojom::VolumeController* volume_controller, - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_VOLUME_UP) - base::RecordAction(UserMetricsAction("Accel_VolumeUp_F10")); - - if (volume_controller) - volume_controller->VolumeUp(); -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// -// AcceleratorController, public: - -AcceleratorController::AcceleratorController( - AcceleratorControllerDelegate* delegate, - ui::AcceleratorManagerDelegate* manager_delegate) - : delegate_(delegate), - accelerator_manager_(new ui::AcceleratorManager(manager_delegate)), - accelerator_history_(new ui::AcceleratorHistory) { - Init(); -} - -AcceleratorController::~AcceleratorController() {} - -void AcceleratorController::Register( - const std::vector<ui::Accelerator>& accelerators, - ui::AcceleratorTarget* target) { - accelerator_manager_->Register( - accelerators, ui::AcceleratorManager::kNormalPriority, target); -} - -void AcceleratorController::Unregister(const ui::Accelerator& accelerator, - ui::AcceleratorTarget* target) { - accelerator_manager_->Unregister(accelerator, target); -} - -void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) { - accelerator_manager_->UnregisterAll(target); -} - -bool AcceleratorController::Process(const ui::Accelerator& accelerator) { - return accelerator_manager_->Process(accelerator); -} - -bool AcceleratorController::IsRegistered( - const ui::Accelerator& accelerator) const { - return accelerator_manager_->IsRegistered(accelerator); -} - -bool AcceleratorController::IsPreferred( - const ui::Accelerator& accelerator) const { - std::map<ui::Accelerator, AcceleratorAction>::const_iterator iter = - accelerators_.find(accelerator); - if (iter == accelerators_.end()) - return false; // not an accelerator. - - return preferred_actions_.find(iter->second) != preferred_actions_.end(); -} - -bool AcceleratorController::IsReserved( - const ui::Accelerator& accelerator) const { - std::map<ui::Accelerator, AcceleratorAction>::const_iterator iter = - accelerators_.find(accelerator); - if (iter == accelerators_.end()) - return false; // not an accelerator. - - return reserved_actions_.find(iter->second) != reserved_actions_.end(); -} - -bool AcceleratorController::IsDeprecated( - const ui::Accelerator& accelerator) const { - return deprecated_accelerators_.count(accelerator) != 0; -} - -bool AcceleratorController::PerformActionIfEnabled(AcceleratorAction action) { - if (CanPerformAction(action, ui::Accelerator())) { - PerformAction(action, ui::Accelerator()); - return true; - } - return false; -} - -AcceleratorController::AcceleratorProcessingRestriction -AcceleratorController::GetCurrentAcceleratorRestriction() { - return GetAcceleratorProcessingRestriction(-1); -} - -void AcceleratorController::SetImeControlDelegate( - std::unique_ptr<ImeControlDelegate> ime_control_delegate) { - ime_control_delegate_ = std::move(ime_control_delegate); -} - -bool AcceleratorController::ShouldCloseMenuAndRepostAccelerator( - const ui::Accelerator& accelerator) const { - auto itr = accelerators_.find(accelerator); - if (itr == accelerators_.end()) - return false; // Menu shouldn't be closed for an invalid accelerator. - - AcceleratorAction action = itr->second; - return actions_keeping_menu_open_.count(action) == 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// AcceleratorController, ui::AcceleratorTarget implementation: - -bool AcceleratorController::AcceleratorPressed( - const ui::Accelerator& accelerator) { - std::map<ui::Accelerator, AcceleratorAction>::const_iterator it = - accelerators_.find(accelerator); - DCHECK(it != accelerators_.end()); - AcceleratorAction action = it->second; - if (!CanPerformAction(action, accelerator)) - return false; - - // Handling the deprecated accelerators (if any) only if action can be - // performed. - if (MaybeDeprecatedAcceleratorPressed(action, accelerator) == - AcceleratorProcessingStatus::STOP) { - return false; - } - - PerformAction(action, accelerator); - return ShouldActionConsumeKeyEvent(action); -} - -bool AcceleratorController::CanHandleAccelerators() const { - return true; -} - -void AcceleratorController::BindRequest( - mojom::AcceleratorControllerRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void AcceleratorController::SetVolumeController( - mojom::VolumeControllerPtr controller) { - volume_controller_ = std::move(controller); -} - -/////////////////////////////////////////////////////////////////////////////// -// AcceleratorController, private: - -void AcceleratorController::Init() { - for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { - actions_allowed_at_login_screen_.insert( - kActionsAllowedAtLoginOrLockScreen[i]); - actions_allowed_at_lock_screen_.insert( - kActionsAllowedAtLoginOrLockScreen[i]); - } - for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) - actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]); - for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) - actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]); - for (size_t i = 0; i < kPreferredActionsLength; ++i) - preferred_actions_.insert(kPreferredActions[i]); - for (size_t i = 0; i < kReservedActionsLength; ++i) - reserved_actions_.insert(kReservedActions[i]); - for (size_t i = 0; i < kRepeatableActionsLength; ++i) - repeatable_actions_.insert(kRepeatableActions[i]); - for (size_t i = 0; i < kActionsAllowedInAppModeOrPinnedModeLength; ++i) { - actions_allowed_in_app_mode_.insert( - kActionsAllowedInAppModeOrPinnedMode[i]); - actions_allowed_in_pinned_mode_.insert( - kActionsAllowedInAppModeOrPinnedMode[i]); - } - for (size_t i = 0; i < kActionsAllowedInPinnedModeLength; ++i) - actions_allowed_in_pinned_mode_.insert(kActionsAllowedInPinnedMode[i]); - for (size_t i = 0; i < kActionsNeedingWindowLength; ++i) - actions_needing_window_.insert(kActionsNeedingWindow[i]); - for (size_t i = 0; i < kActionsKeepingMenuOpenLength; ++i) - actions_keeping_menu_open_.insert(kActionsKeepingMenuOpen[i]); - - RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength); - - RegisterDeprecatedAccelerators(); - - if (debug::DebugAcceleratorsEnabled()) { - RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength); - // All debug accelerators are reserved. - for (size_t i = 0; i < kDebugAcceleratorDataLength; ++i) - reserved_actions_.insert(kDebugAcceleratorData[i].action); - } - - if (debug::DeveloperAcceleratorsEnabled()) { - RegisterAccelerators(kDeveloperAcceleratorData, - kDeveloperAcceleratorDataLength); - // Developer accelerators are also reserved. - for (size_t i = 0; i < kDeveloperAcceleratorDataLength; ++i) - reserved_actions_.insert(kDeveloperAcceleratorData[i].action); - } -} - -void AcceleratorController::RegisterAccelerators( - const AcceleratorData accelerators[], - size_t accelerators_length) { - std::vector<ui::Accelerator> ui_accelerators; - for (size_t i = 0; i < accelerators_length; ++i) { - ui::Accelerator accelerator = - CreateAccelerator(accelerators[i].keycode, accelerators[i].modifiers, - accelerators[i].trigger_on_press); - ui_accelerators.push_back(accelerator); - accelerators_.insert(std::make_pair(accelerator, accelerators[i].action)); - } - Register(ui_accelerators, this); -} - -void AcceleratorController::RegisterDeprecatedAccelerators() { - for (size_t i = 0; i < kDeprecatedAcceleratorsDataLength; ++i) { - const DeprecatedAcceleratorData* data = &kDeprecatedAcceleratorsData[i]; - actions_with_deprecations_[data->action] = data; - } - - std::vector<ui::Accelerator> ui_accelerators; - for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) { - const AcceleratorData& accelerator_data = kDeprecatedAccelerators[i]; - const ui::Accelerator deprecated_accelerator = - CreateAccelerator(accelerator_data.keycode, accelerator_data.modifiers, - accelerator_data.trigger_on_press); - - ui_accelerators.push_back(deprecated_accelerator); - accelerators_[deprecated_accelerator] = accelerator_data.action; - deprecated_accelerators_.insert(deprecated_accelerator); - } - Register(ui_accelerators, this); -} - -bool AcceleratorController::CanPerformAction( - AcceleratorAction action, - const ui::Accelerator& accelerator) { - if (accelerator.IsRepeat() && !repeatable_actions_.count(action)) - return false; - - AcceleratorProcessingRestriction restriction = - GetAcceleratorProcessingRestriction(action); - if (restriction != RESTRICTION_NONE) - return restriction == RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; - - const ui::Accelerator& previous_accelerator = - accelerator_history_->previous_accelerator(); - - // True should be returned if running |action| does something. Otherwise, - // false should be returned to give the web contents a chance at handling the - // accelerator. - switch (action) { - case CYCLE_BACKWARD_MRU: - case CYCLE_FORWARD_MRU: - return CanHandleCycleMru(accelerator); - case DEBUG_PRINT_LAYER_HIERARCHY: - case DEBUG_PRINT_VIEW_HIERARCHY: - case DEBUG_PRINT_WINDOW_HIERARCHY: - case DEBUG_SHOW_TOAST: - case DEBUG_TOGGLE_TOUCH_PAD: - case DEBUG_TOGGLE_TOUCH_SCREEN: - case DEBUG_TOGGLE_TOUCH_VIEW: - case DEBUG_TOGGLE_WALLPAPER_MODE: - case DEBUG_TRIGGER_CRASH: - return debug::DebugAcceleratorsEnabled(); - case DISABLE_CAPS_LOCK: - return CanHandleDisableCapsLock(previous_accelerator); - case LOCK_SCREEN: - return CanHandleLock(); - case NEW_INCOGNITO_WINDOW: - return CanHandleNewIncognitoWindow(); - case NEXT_IME: - return CanHandleNextIme(ime_control_delegate_.get()); - case PREVIOUS_IME: - return CanHandlePreviousIme(ime_control_delegate_.get()); - case SHOW_MESSAGE_CENTER_BUBBLE: - return CanHandleShowMessageCenterBubble(); - case SHOW_STYLUS_TOOLS: - return CanHandleShowStylusTools(); - case SWITCH_IME: - return CanHandleSwitchIme(ime_control_delegate_.get(), accelerator); - case SWITCH_TO_PREVIOUS_USER: - case SWITCH_TO_NEXT_USER: - return CanHandleCycleUser(); - case TOGGLE_APP_LIST: - return CanHandleToggleAppList(accelerator, previous_accelerator); - case TOGGLE_CAPS_LOCK: - return CanHandleToggleCapsLock(accelerator, previous_accelerator); - case WINDOW_CYCLE_SNAP_DOCK_LEFT: - case WINDOW_CYCLE_SNAP_DOCK_RIGHT: - return CanHandleWindowSnapOrDock(); - case WINDOW_POSITION_CENTER: - return CanHandlePositionCenter(); - - // The following are always enabled. - case BRIGHTNESS_DOWN: - case BRIGHTNESS_UP: - case EXIT: - case FOCUS_NEXT_PANE: - case FOCUS_PREVIOUS_PANE: - case FOCUS_SHELF: - case KEYBOARD_BRIGHTNESS_DOWN: - case KEYBOARD_BRIGHTNESS_UP: - case LAUNCH_APP_0: - case LAUNCH_APP_1: - case LAUNCH_APP_2: - case LAUNCH_APP_3: - case LAUNCH_APP_4: - case LAUNCH_APP_5: - case LAUNCH_APP_6: - case LAUNCH_APP_7: - case LAUNCH_LAST_APP: - case MEDIA_NEXT_TRACK: - case MEDIA_PLAY_PAUSE: - case MEDIA_PREV_TRACK: - case NEW_TAB: - case NEW_WINDOW: - case OPEN_CROSH: - case OPEN_FEEDBACK_PAGE: - case OPEN_FILE_MANAGER: - case OPEN_GET_HELP: - case PRINT_UI_HIERARCHIES: - case RESTORE_TAB: - case SHOW_IME_MENU_BUBBLE: - case SHOW_KEYBOARD_OVERLAY: - case SHOW_TASK_MANAGER: - case SUSPEND: - case TOGGLE_FULLSCREEN: - case TOGGLE_HIGH_CONTRAST: - case TOGGLE_MAXIMIZED: - case TOGGLE_OVERVIEW: - case TOGGLE_SPOKEN_FEEDBACK: - case TOGGLE_WIFI: - case VOLUME_DOWN: - case VOLUME_MUTE: - case VOLUME_UP: - case WINDOW_MINIMIZE: - return true; - - default: - // Default switch is temporary until mash transition complete. Needed as - // some actions don't yet work with mash. - break; - } - return delegate_ && delegate_->HandlesAction(action) && - delegate_->CanPerformAction(action, accelerator, previous_accelerator); -} - -void AcceleratorController::PerformAction(AcceleratorAction action, - const ui::Accelerator& accelerator) { - AcceleratorProcessingRestriction restriction = - GetAcceleratorProcessingRestriction(action); - if (restriction != RESTRICTION_NONE) - return; - - // If your accelerator invokes more than one line of code, please either - // implement it in your module's controller code or pull it into a HandleFoo() - // function above. - switch (action) { - case BRIGHTNESS_DOWN: { - BrightnessControlDelegate* delegate = - WmShell::Get()->brightness_control_delegate(); - if (delegate) - delegate->HandleBrightnessDown(accelerator); - break; - } - case BRIGHTNESS_UP: { - BrightnessControlDelegate* delegate = - WmShell::Get()->brightness_control_delegate(); - if (delegate) - delegate->HandleBrightnessUp(accelerator); - break; - } - case CYCLE_BACKWARD_MRU: - HandleCycleBackwardMRU(accelerator); - break; - case CYCLE_FORWARD_MRU: - HandleCycleForwardMRU(accelerator); - break; - case DEBUG_PRINT_LAYER_HIERARCHY: - case DEBUG_PRINT_VIEW_HIERARCHY: - case DEBUG_PRINT_WINDOW_HIERARCHY: - case DEBUG_SHOW_TOAST: - case DEBUG_TOGGLE_TOUCH_PAD: - case DEBUG_TOGGLE_TOUCH_SCREEN: - case DEBUG_TOGGLE_TOUCH_VIEW: - case DEBUG_TOGGLE_WALLPAPER_MODE: - case DEBUG_TRIGGER_CRASH: - debug::PerformDebugActionIfEnabled(action); - break; - case DISABLE_CAPS_LOCK: - HandleDisableCapsLock(); - break; - case EXIT: - // UMA metrics are recorded in the handler. - exit_warning_handler_.HandleAccelerator(); - break; - case FOCUS_NEXT_PANE: - HandleRotatePaneFocus(FocusCycler::FORWARD); - break; - case FOCUS_PREVIOUS_PANE: - HandleRotatePaneFocus(FocusCycler::BACKWARD); - break; - case FOCUS_SHELF: - HandleFocusShelf(); - break; - case KEYBOARD_BRIGHTNESS_DOWN: { - KeyboardBrightnessControlDelegate* delegate = - WmShell::Get()->keyboard_brightness_control_delegate(); - if (delegate) - delegate->HandleKeyboardBrightnessDown(accelerator); - break; - } - case KEYBOARD_BRIGHTNESS_UP: { - KeyboardBrightnessControlDelegate* delegate = - WmShell::Get()->keyboard_brightness_control_delegate(); - if (delegate) - delegate->HandleKeyboardBrightnessUp(accelerator); - break; - } - case LAUNCH_APP_0: - HandleLaunchAppN(0); - break; - case LAUNCH_APP_1: - HandleLaunchAppN(1); - break; - case LAUNCH_APP_2: - HandleLaunchAppN(2); - break; - case LAUNCH_APP_3: - HandleLaunchAppN(3); - break; - case LAUNCH_APP_4: - HandleLaunchAppN(4); - break; - case LAUNCH_APP_5: - HandleLaunchAppN(5); - break; - case LAUNCH_APP_6: - HandleLaunchAppN(6); - break; - case LAUNCH_APP_7: - HandleLaunchAppN(7); - break; - case LAUNCH_LAST_APP: - HandleLaunchLastApp(); - break; - case LOCK_SCREEN: - HandleLock(); - break; - case MEDIA_NEXT_TRACK: - HandleMediaNextTrack(); - break; - case MEDIA_PLAY_PAUSE: - HandleMediaPlayPause(); - break; - case MEDIA_PREV_TRACK: - HandleMediaPrevTrack(); - break; - case NEW_INCOGNITO_WINDOW: - HandleNewIncognitoWindow(); - break; - case NEW_TAB: - HandleNewTab(accelerator); - break; - case NEW_WINDOW: - HandleNewWindow(); - break; - case NEXT_IME: - HandleNextIme(ime_control_delegate_.get()); - break; - case OPEN_CROSH: - HandleCrosh(); - break; - case OPEN_FEEDBACK_PAGE: - HandleOpenFeedbackPage(); - break; - case OPEN_FILE_MANAGER: - HandleFileManager(); - break; - case OPEN_GET_HELP: - HandleGetHelp(); - break; - case PREVIOUS_IME: - HandlePreviousIme(ime_control_delegate_.get(), accelerator); - break; - case PRINT_UI_HIERARCHIES: - debug::PrintUIHierarchies(); - break; - case RESTORE_TAB: - HandleRestoreTab(); - break; - case SHOW_IME_MENU_BUBBLE: - HandleShowImeMenuBubble(); - break; - case SHOW_KEYBOARD_OVERLAY: - HandleShowKeyboardOverlay(); - break; - case SHOW_MESSAGE_CENTER_BUBBLE: - HandleShowMessageCenterBubble(); - break; - case SHOW_STYLUS_TOOLS: - HandleShowStylusTools(); - break; - case SHOW_TASK_MANAGER: - HandleShowTaskManager(); - break; - case SUSPEND: - HandleSuspend(); - break; - case SWITCH_IME: - HandleSwitchIme(ime_control_delegate_.get(), accelerator); - break; - case SWITCH_TO_NEXT_USER: - HandleCycleUser(CycleUserDirection::NEXT); - break; - case SWITCH_TO_PREVIOUS_USER: - HandleCycleUser(CycleUserDirection::PREVIOUS); - break; - case TOGGLE_APP_LIST: - HandleToggleAppList(accelerator); - break; - case TOGGLE_CAPS_LOCK: - HandleToggleCapsLock(); - break; - case TOGGLE_FULLSCREEN: - HandleToggleFullscreen(accelerator); - break; - case TOGGLE_HIGH_CONTRAST: - HandleToggleHighContrast(); - break; - case TOGGLE_MAXIMIZED: - accelerators::ToggleMaximized(); - break; - case TOGGLE_OVERVIEW: - HandleToggleOverview(); - break; - case TOGGLE_SPOKEN_FEEDBACK: - HandleToggleSpokenFeedback(); - break; - case TOGGLE_WIFI: - WmShell::Get()->system_tray_notifier()->NotifyRequestToggleWifi(); - break; - case VOLUME_DOWN: - HandleVolumeDown(volume_controller_.get(), accelerator); - break; - case VOLUME_MUTE: - HandleVolumeMute(volume_controller_.get(), accelerator); - break; - case VOLUME_UP: - HandleVolumeUp(volume_controller_.get(), accelerator); - break; - case WINDOW_CYCLE_SNAP_DOCK_LEFT: - case WINDOW_CYCLE_SNAP_DOCK_RIGHT: - HandleWindowSnapOrDock(action); - break; - case WINDOW_MINIMIZE: - HandleWindowMinimize(); - break; - case WINDOW_POSITION_CENTER: - HandlePositionCenter(); - break; - default: - // Temporary until mash transition complete. Needed as some actions - // don't yet work with mash. - DCHECK(delegate_ && delegate_->HandlesAction(action)); - delegate_->PerformAction(action, accelerator); - break; - } -} - -bool AcceleratorController::ShouldActionConsumeKeyEvent( - AcceleratorAction action) { - // Adding new exceptions is *STRONGLY* discouraged. - return true; -} - -AcceleratorController::AcceleratorProcessingRestriction -AcceleratorController::GetAcceleratorProcessingRestriction(int action) { - WmShell* wm_shell = WmShell::Get(); - if (wm_shell->IsPinned() && - actions_allowed_in_pinned_mode_.find(action) == - actions_allowed_in_pinned_mode_.end()) { - return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; - } - // TODO(xiyuan): Replace with SessionController. http://crbug.com/648964 - if (!wm_shell->GetSessionStateDelegate()->IsActiveUserSessionStarted() && - actions_allowed_at_login_screen_.find(action) == - actions_allowed_at_login_screen_.end()) { - return RESTRICTION_PREVENT_PROCESSING; - } - if (wm_shell->GetSessionStateDelegate()->IsScreenLocked() && - actions_allowed_at_lock_screen_.find(action) == - actions_allowed_at_lock_screen_.end()) { - return RESTRICTION_PREVENT_PROCESSING; - } - if (wm_shell->delegate()->IsRunningInForcedAppMode() && - actions_allowed_in_app_mode_.find(action) == - actions_allowed_in_app_mode_.end()) { - return RESTRICTION_PREVENT_PROCESSING; - } - if (WmShell::Get()->IsSystemModalWindowOpen() && - actions_allowed_at_modal_window_.find(action) == - actions_allowed_at_modal_window_.end()) { - // Note we prevent the shortcut from propagating so it will not - // be passed to the modal window. This is important for things like - // Alt+Tab that would cause an undesired effect in the modal window by - // cycling through its window elements. - return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; - } - if (wm_shell->mru_window_tracker()->BuildMruWindowList().empty() && - actions_needing_window_.find(action) != actions_needing_window_.end()) { - wm_shell->accessibility_delegate()->TriggerAccessibilityAlert( - A11Y_ALERT_WINDOW_NEEDED); - return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; - } - return RESTRICTION_NONE; -} - -AcceleratorController::AcceleratorProcessingStatus -AcceleratorController::MaybeDeprecatedAcceleratorPressed( - AcceleratorAction action, - const ui::Accelerator& accelerator) const { - auto itr = actions_with_deprecations_.find(action); - if (itr == actions_with_deprecations_.end()) { - // The action is not associated with any deprecated accelerators, and hence - // should be performed normally. - return AcceleratorProcessingStatus::PROCEED; - } - - // This action is associated with new and deprecated accelerators, find which - // one is |accelerator|. - const DeprecatedAcceleratorData* data = itr->second; - if (!deprecated_accelerators_.count(accelerator)) { - // This is a new accelerator replacing the old deprecated one. - // Record UMA stats and proceed normally to perform it. - RecordUmaHistogram(data->uma_histogram_name, NEW_USED); - return AcceleratorProcessingStatus::PROCEED; - } - - // This accelerator has been deprecated and should be treated according - // to its |DeprecatedAcceleratorData|. - - // Record UMA stats. - RecordUmaHistogram(data->uma_histogram_name, DEPRECATED_USED); - - if (delegate_) { - // We always display the notification as long as this |data| entry exists. - delegate_->ShowDeprecatedAcceleratorNotification( - data->uma_histogram_name, data->notification_message_id, - data->old_shortcut_id, data->new_shortcut_id); - } - - if (!data->deprecated_enabled) - return AcceleratorProcessingStatus::STOP; - - return AcceleratorProcessingStatus::PROCEED; -} - -} // namespace ash
diff --git a/ash/accelerators/accelerator_controller.h b/ash/accelerators/accelerator_controller.h deleted file mode 100644 index 4be34b7f5..0000000 --- a/ash/accelerators/accelerator_controller.h +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_H_ -#define ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_H_ - -#include <stddef.h> - -#include <map> -#include <memory> -#include <set> -#include <vector> - -#include "ash/accelerators/accelerator_table.h" -#include "ash/accelerators/exit_warning_handler.h" -#include "ash/ash_export.h" -#include "ash/public/interfaces/accelerator_controller.mojom.h" -#include "base/compiler_specific.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/base/accelerators/accelerator_history.h" - -namespace ui { -class AcceleratorManager; -class AcceleratorManagerDelegate; -} - -namespace ash { - -struct AcceleratorData; -class AcceleratorControllerDelegate; -class ExitWarningHandler; -class ImeControlDelegate; - -// AcceleratorController provides functions for registering or unregistering -// global keyboard accelerators, which are handled earlier than any windows. It -// also implements several handlers as an accelerator target. -class ASH_EXPORT AcceleratorController - : public ui::AcceleratorTarget, - NON_EXPORTED_BASE(public mojom::AcceleratorController) { - public: - AcceleratorController(AcceleratorControllerDelegate* delegate, - ui::AcceleratorManagerDelegate* manager_delegate); - ~AcceleratorController() override; - - // A list of possible ways in which an accelerator should be restricted before - // processing. Any target registered with this controller should respect - // restrictions by calling |GetCurrentAcceleratorRestriction| during - // processing. - enum AcceleratorProcessingRestriction { - // Process the accelerator normally. - RESTRICTION_NONE, - - // Don't process the accelerator. - RESTRICTION_PREVENT_PROCESSING, - - // Don't process the accelerator and prevent propagation to other targets. - RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION - }; - - // Registers global keyboard accelerators for the specified target. If - // multiple targets are registered for any given accelerator, a target - // registered later has higher priority. - void Register(const std::vector<ui::Accelerator>& accelerators, - ui::AcceleratorTarget* target); - - // Unregisters the specified keyboard accelerator for the specified target. - void Unregister(const ui::Accelerator& accelerator, - ui::AcceleratorTarget* target); - - // Unregisters all keyboard accelerators for the specified target. - void UnregisterAll(ui::AcceleratorTarget* target); - - // Activates the target associated with the specified accelerator. - // First, AcceleratorPressed handler of the most recently registered target - // is called, and if that handler processes the event (i.e. returns true), - // this method immediately returns. If not, we do the same thing on the next - // target, and so on. - // Returns true if an accelerator was activated. - bool Process(const ui::Accelerator& accelerator); - - // Returns true if the |accelerator| is registered. - bool IsRegistered(const ui::Accelerator& accelerator) const; - - // Returns true if the |accelerator| is preferred. A preferred accelerator - // is handled before being passed to an window/web contents, unless - // the window is in fullscreen state. - bool IsPreferred(const ui::Accelerator& accelerator) const; - - // Returns true if the |accelerator| is reserved. A reserved accelerator - // is always handled and will never be passed to an window/web contents. - bool IsReserved(const ui::Accelerator& accelerator) const; - - // Returns true if the |accelerator| is deprecated. Deprecated accelerators - // can be consumed by web contents if needed. - bool IsDeprecated(const ui::Accelerator& accelerator) const; - - // Performs the specified action if it is enabled. Returns whether the action - // was performed successfully. - bool PerformActionIfEnabled(AcceleratorAction action); - - // Returns the restriction for the current context. - AcceleratorProcessingRestriction GetCurrentAcceleratorRestriction(); - - void SetImeControlDelegate( - std::unique_ptr<ImeControlDelegate> ime_control_delegate); - - // Provides access to the ExitWarningHandler for testing. - ExitWarningHandler* GetExitWarningHandlerForTest() { - return &exit_warning_handler_; - } - - // Returns true if the menu should close in order to perform the accelerator. - bool ShouldCloseMenuAndRepostAccelerator( - const ui::Accelerator& accelerator) const; - - ui::AcceleratorHistory* accelerator_history() { - return accelerator_history_.get(); - } - - // Overridden from ui::AcceleratorTarget: - bool AcceleratorPressed(const ui::Accelerator& accelerator) override; - bool CanHandleAccelerators() const override; - - // Binds the mojom::AcceleratorController interface to this object. - void BindRequest(mojom::AcceleratorControllerRequest request); - - // mojom::AcceleratorController: - void SetVolumeController(mojom::VolumeControllerPtr controller) override; - - private: - FRIEND_TEST_ALL_PREFIXES(AcceleratorControllerTest, GlobalAccelerators); - FRIEND_TEST_ALL_PREFIXES(AcceleratorControllerTest, - DontRepeatToggleFullscreen); - FRIEND_TEST_ALL_PREFIXES(DeprecatedAcceleratorTester, - TestDeprecatedAcceleratorsBehavior); - - // Initializes the accelerators this class handles as a target. - void Init(); - - // Registers the specified accelerators. - void RegisterAccelerators(const AcceleratorData accelerators[], - size_t accelerators_length); - - // Registers the deprecated accelerators and their replacing new ones. - void RegisterDeprecatedAccelerators(); - - // Returns whether |action| can be performed. The |accelerator| may provide - // additional data the action needs. - bool CanPerformAction(AcceleratorAction action, - const ui::Accelerator& accelerator); - - // Performs the specified action. The |accelerator| may provide additional - // data the action needs. - void PerformAction(AcceleratorAction action, - const ui::Accelerator& accelerator); - - // Returns whether performing |action| should consume the key event. - bool ShouldActionConsumeKeyEvent(AcceleratorAction action); - - // Get the accelerator restriction for the given action. Supply an |action| - // of -1 to get restrictions that apply for the current context. - AcceleratorProcessingRestriction GetAcceleratorProcessingRestriction( - int action); - - // If |accelerator| is a deprecated accelerator, it performs the appropriate - // deprecated accelerator pre-handling. - // Returns PROCEED if the accelerator's action should be performed (i.e. if - // |accelerator| is not a deprecated accelerator, or it's an enabled - // deprecated accelerator), and STOP otherwise (if the accelerator is a - // disabled deprecated accelerator). - enum class AcceleratorProcessingStatus { PROCEED, STOP }; - AcceleratorProcessingStatus MaybeDeprecatedAcceleratorPressed( - AcceleratorAction action, - const ui::Accelerator& accelerator) const; - - AcceleratorControllerDelegate* delegate_; - - std::unique_ptr<ui::AcceleratorManager> accelerator_manager_; - - // A tracker for the current and previous accelerators. - std::unique_ptr<ui::AcceleratorHistory> accelerator_history_; - - std::unique_ptr<ImeControlDelegate> ime_control_delegate_; - - // Handles the exit accelerator which requires a double press to exit and - // shows a popup with an explanation. - ExitWarningHandler exit_warning_handler_; - - // A map from accelerators to the AcceleratorAction values, which are used in - // the implementation. - std::map<ui::Accelerator, AcceleratorAction> accelerators_; - - std::map<AcceleratorAction, const DeprecatedAcceleratorData*> - actions_with_deprecations_; - std::set<ui::Accelerator> deprecated_accelerators_; - - // Bindings for the mojom::AcceleratorController interface. - mojo::BindingSet<mojom::AcceleratorController> bindings_; - - // Volume controller interface in chrome browser. May be null in tests. Exists - // because chrome owns the CrasAudioHandler dbus communication. - mojom::VolumeControllerPtr volume_controller_; - - // Actions allowed when the user is not signed in. - std::set<int> actions_allowed_at_login_screen_; - // Actions allowed when the screen is locked. - std::set<int> actions_allowed_at_lock_screen_; - // Actions allowed when a modal window is up. - std::set<int> actions_allowed_at_modal_window_; - // Preferred actions. See accelerator_table.h for details. - std::set<int> preferred_actions_; - // Reserved actions. See accelerator_table.h for details. - std::set<int> reserved_actions_; - // Actions which will be repeated while holding the accelerator key. - std::set<int> repeatable_actions_; - // Actions allowed in app mode. - std::set<int> actions_allowed_in_app_mode_; - // Actions allowed in pinned mode. - std::set<int> actions_allowed_in_pinned_mode_; - // Actions disallowed if there are no windows. - std::set<int> actions_needing_window_; - // Actions that can be performed without closing the menu (if one is present). - std::set<int> actions_keeping_menu_open_; - - DISALLOW_COPY_AND_ASSIGN(AcceleratorController); -}; - -} // namespace ash - -#endif // ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_H_
diff --git a/ash/accelerators/accelerator_controller_delegate.h b/ash/accelerators/accelerator_controller_delegate.h deleted file mode 100644 index 81c06e4..0000000 --- a/ash/accelerators/accelerator_controller_delegate.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_H_ -#define ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_H_ - -#include "ash/accelerators/accelerator_table.h" -#include "ash/ash_export.h" - -namespace ui { -class Accelerator; -} - -namespace ash { - -// Used by AcceleratorController to handle environment specific commands. This -// file is temporary while ash supports both mus and aura. -class ASH_EXPORT AcceleratorControllerDelegate { - public: - // Returns true if the delegate is responsible for handling |action|. This - // should not return whether the action may be enabled, only if this delegate - // handles the action. - virtual bool HandlesAction(AcceleratorAction action) = 0; - - // Returns true if the delegate can perform the action at this time. Only - // invoked if HandlesAction() returns true. - virtual bool CanPerformAction( - AcceleratorAction action, - const ui::Accelerator& accelerator, - const ui::Accelerator& previous_accelerator) = 0; - - // Performs the specified action. - virtual void PerformAction(AcceleratorAction action, - const ui::Accelerator& accelerator) = 0; - - // Shows a warning the user is using a deprecated accelerator. - virtual void ShowDeprecatedAcceleratorNotification( - const char* const notification_id, - int message_id, - int old_shortcut_id, - int new_shortcut_id) = 0; - - protected: - virtual ~AcceleratorControllerDelegate() {} -}; - -} // namespace ash - -#endif // ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_H_
diff --git a/ash/accelerators/accelerator_controller_delegate_aura.cc b/ash/accelerators/accelerator_controller_delegate_aura.cc index 9fddcad..451ffe05 100644 --- a/ash/accelerators/accelerator_controller_delegate_aura.cc +++ b/ash/accelerators/accelerator_controller_delegate_aura.cc
@@ -10,10 +10,16 @@ #include <utility> #include "ash/accelerators/accelerator_commands_aura.h" -#include "ash/accelerators/debug_commands.h" +#include "ash/common/accelerators/debug_commands.h" #include "ash/common/accessibility_types.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/shell_delegate.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/debug.h" #include "ash/display/display_configuration_controller.h" @@ -24,18 +30,12 @@ #include "ash/root_window_controller.h" #include "ash/rotator/window_rotation.h" #include "ash/screenshot_delegate.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray.h" #include "ash/touch/touch_hud_debug.h" #include "ash/utility/screenshot_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/power_button_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h"
diff --git a/ash/accelerators/accelerator_controller_delegate_aura.h b/ash/accelerators/accelerator_controller_delegate_aura.h index 2338dd9..3f68382 100644 --- a/ash/accelerators/accelerator_controller_delegate_aura.h +++ b/ash/accelerators/accelerator_controller_delegate_aura.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/accelerators/accelerator_controller_delegate.h" +#include "ash/common/accelerators/accelerator_controller_delegate.h" #include "base/macros.h" namespace ash {
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index c8b88b7c..784cc02c 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -2,33 +2,33 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" -#include "ash/accelerators/accelerator_table.h" +#include "ash/common/accelerators/accelerator_table.h" #include "ash/common/accessibility_delegate.h" #include "ash/common/accessibility_types.h" #include "ash/common/ash_switches.h" #include "ash/common/ime_control_delegate.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/brightness_control_delegate.h" +#include "ash/common/system/keyboard_brightness_control_delegate.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/system/brightness_control_delegate.h" -#include "ash/system/keyboard_brightness_control_delegate.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" #include "ash/test/lock_state_controller_test_api.h" #include "ash/test/test_screenshot_delegate.h" #include "ash/test/test_session_state_animator.h" -#include "ash/test/test_shelf_delegate.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/command_line.h" #include "base/test/user_action_tester.cc" #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
diff --git a/ash/accelerators/accelerator_delegate.cc b/ash/accelerators/accelerator_delegate.cc index 3a87b0e..679813f 100644 --- a/ash/accelerators/accelerator_delegate.cc +++ b/ash/accelerators/accelerator_delegate.cc
@@ -4,7 +4,7 @@ #include "ash/accelerators/accelerator_delegate.h" -#include "ash/accelerators/accelerator_router.h" +#include "ash/common/accelerators/accelerator_router.h" #include "ash/common/wm_window.h" #include "ui/aura/window.h" #include "ui/events/event.h"
diff --git a/ash/accelerators/accelerator_filter_unittest.cc b/ash/accelerators/accelerator_filter_unittest.cc index 2b1b55da..f19204b8 100644 --- a/ash/accelerators/accelerator_filter_unittest.cc +++ b/ash/accelerators/accelerator_filter_unittest.cc
@@ -6,16 +6,16 @@ #include <memory> -#include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_delegate.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test/test_screenshot_delegate.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc index 30332fc..69755878 100644 --- a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc +++ b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/shell_observer.h" +#include "ash/common/system/chromeos/network/network_observer.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/network/network_observer.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" #include "ash/test/ash_interactive_ui_test_base.h" #include "ash/test/test_screenshot_delegate.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/run_loop.h"
diff --git a/ash/accelerators/accelerator_router.cc b/ash/accelerators/accelerator_router.cc deleted file mode 100644 index 36fc6d8..0000000 --- a/ash/accelerators/accelerator_router.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/accelerator_router.h" - -#include "ash/accelerators/accelerator_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/window_state.h" -#include "base/metrics/histogram_macros.h" -#include "base/stl_util.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/events/event.h" - -namespace ash { - -namespace { - -// Returns true if |key_code| is a key usually handled directly by the shell. -bool IsSystemKey(ui::KeyboardCode key_code) { - switch (key_code) { - case ui::VKEY_MEDIA_LAUNCH_APP2: // Fullscreen button. - case ui::VKEY_MEDIA_LAUNCH_APP1: // Overview button. - case ui::VKEY_BRIGHTNESS_DOWN: - case ui::VKEY_BRIGHTNESS_UP: - case ui::VKEY_KBD_BRIGHTNESS_DOWN: - case ui::VKEY_KBD_BRIGHTNESS_UP: - case ui::VKEY_VOLUME_MUTE: - case ui::VKEY_VOLUME_DOWN: - case ui::VKEY_VOLUME_UP: - case ui::VKEY_POWER: - return true; - default: - return false; - } -} - -} // namespace - -AcceleratorRouter::AcceleratorRouter() {} - -AcceleratorRouter::~AcceleratorRouter() {} - -bool AcceleratorRouter::ProcessAccelerator(WmWindow* target, - const ui::KeyEvent& key_event, - const ui::Accelerator& accelerator) { - // Callers should never supply null. - DCHECK(target); - RecordSearchKeyStats(accelerator); - // Special hardware keys like brightness and volume are handled in - // special way. However, some windows can override this behavior - // (e.g. Chrome v1 apps by default and Chrome v2 apps with - // permission) by setting a window property. - if (IsSystemKey(key_event.key_code()) && - !CanConsumeSystemKeys(target, key_event)) { - // System keys are always consumed regardless of whether they trigger an - // accelerator to prevent windows from seeing unexpected key up events. - WmShell::Get()->accelerator_controller()->Process(accelerator); - return true; - } - if (!ShouldProcessAcceleratorNow(target, key_event, accelerator)) - return false; - return WmShell::Get()->accelerator_controller()->Process(accelerator); -} - -void AcceleratorRouter::RecordSearchKeyStats( - const ui::Accelerator& accelerator) { - if (accelerator.IsCmdDown()) { - if (search_key_state_ == RELEASED) { - search_key_state_ = PRESSED; - search_key_pressed_timestamp_ = base::TimeTicks::Now(); - } - - if (accelerator.key_code() != ui::KeyboardCode::VKEY_COMMAND && - search_key_state_ == PRESSED) { - search_key_state_ = RECORDED; - UMA_HISTOGRAM_TIMES( - "Keyboard.Shortcuts.CrosSearchKeyDelay", - base::TimeTicks::Now() - search_key_pressed_timestamp_); - } - } else { - search_key_state_ = RELEASED; - } -} - -bool AcceleratorRouter::CanConsumeSystemKeys(WmWindow* target, - const ui::KeyEvent& event) { - // Uses the top level window so if the target is a web contents window the - // containing parent window will be checked for the property. - WmWindow* top_level = target->GetToplevelWindowForFocus(); - return top_level && top_level->GetWindowState()->can_consume_system_keys(); -} - -bool AcceleratorRouter::ShouldProcessAcceleratorNow( - WmWindow* target, - const ui::KeyEvent& event, - const ui::Accelerator& accelerator) { - // Callers should never supply null. - DCHECK(target); - // On ChromeOS, If the accelerator is Search+<key(s)> then it must never be - // intercepted by apps or windows. - if (accelerator.IsCmdDown()) - return true; - - if (base::ContainsValue(WmShell::Get()->GetAllRootWindows(), target)) - return true; - - AcceleratorController* accelerator_controller = - WmShell::Get()->accelerator_controller(); - - // Reserved accelerators (such as Power button) always have a prority. - if (accelerator_controller->IsReserved(accelerator)) - return true; - - // A full screen window has a right to handle all key events including the - // reserved ones. - WmWindow* top_level = target->GetToplevelWindowForFocus(); - if (top_level && top_level->GetWindowState()->IsFullscreen()) { - // On ChromeOS, fullscreen windows are either browser or apps, which - // send key events to a web content first, then will process keys - // if the web content didn't consume them. - return false; - } - - // Handle preferred accelerators (such as ALT-TAB) before sending - // to the target. - if (accelerator_controller->IsPreferred(accelerator)) - return true; - - return WmShell::Get()->GetAppListTargetVisibility(); -} - -} // namespace ash
diff --git a/ash/accelerators/accelerator_table.cc b/ash/accelerators/accelerator_table.cc deleted file mode 100644 index bda1e1d..0000000 --- a/ash/accelerators/accelerator_table.cc +++ /dev/null
@@ -1,503 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/accelerator_table.h" - -#include "ash/strings/grit/ash_strings.h" -#include "base/macros.h" - -namespace ash { - -const int kDebugModifier = - ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN; - -const AcceleratorData kAcceleratorData[] = { - {true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, PREVIOUS_IME}, - {false, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, PREVIOUS_IME}, - // Shortcuts for Japanese IME. - {true, ui::VKEY_CONVERT, ui::EF_NONE, SWITCH_IME}, - {true, ui::VKEY_NONCONVERT, ui::EF_NONE, SWITCH_IME}, - {true, ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE, SWITCH_IME}, - {true, ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE, SWITCH_IME}, - // Shortcut for Koren IME. - {true, ui::VKEY_HANGUL, ui::EF_NONE, SWITCH_IME}, - - {true, ui::VKEY_TAB, ui::EF_ALT_DOWN, CYCLE_FORWARD_MRU}, - {true, ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, - CYCLE_BACKWARD_MRU}, - {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE, TOGGLE_OVERVIEW}, - {true, ui::VKEY_BROWSER_SEARCH, ui::EF_NONE, TOGGLE_APP_LIST}, - {true, ui::VKEY_WLAN, ui::EF_NONE, TOGGLE_WIFI}, - {true, ui::VKEY_KBD_BRIGHTNESS_DOWN, ui::EF_NONE, KEYBOARD_BRIGHTNESS_DOWN}, - {true, ui::VKEY_KBD_BRIGHTNESS_UP, ui::EF_NONE, KEYBOARD_BRIGHTNESS_UP}, - // Maximize button. - {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_CONTROL_DOWN, TOGGLE_MIRROR_MODE}, - {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_ALT_DOWN, SWAP_PRIMARY_DISPLAY}, - // Cycle windows button. - {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN, TAKE_SCREENSHOT}, - {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, - TAKE_PARTIAL_SCREENSHOT}, - {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, - TAKE_WINDOW_SCREENSHOT}, - {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_NONE, BRIGHTNESS_DOWN}, - {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_ALT_DOWN, KEYBOARD_BRIGHTNESS_DOWN}, - {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_NONE, BRIGHTNESS_UP}, - {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_ALT_DOWN, KEYBOARD_BRIGHTNESS_UP}, - {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - MAGNIFY_SCREEN_ZOOM_OUT}, - {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - MAGNIFY_SCREEN_ZOOM_IN}, - {true, ui::VKEY_L, ui::EF_COMMAND_DOWN, LOCK_SCREEN}, - {true, ui::VKEY_L, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, SUSPEND}, - // The lock key on Chrome OS keyboards produces F13 scancodes. - {true, ui::VKEY_F13, ui::EF_NONE, LOCK_PRESSED}, - {false, ui::VKEY_F13, ui::EF_NONE, LOCK_RELEASED}, - // Generic keyboards can use VKEY_SLEEP to mimic ChromeOS keyboard's lock - // key. - {true, ui::VKEY_SLEEP, ui::EF_NONE, LOCK_PRESSED}, - {false, ui::VKEY_SLEEP, ui::EF_NONE, LOCK_RELEASED}, - {true, ui::VKEY_POWER, ui::EF_NONE, POWER_PRESSED}, - {false, ui::VKEY_POWER, ui::EF_NONE, POWER_RELEASED}, - {true, ui::VKEY_M, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, OPEN_FILE_MANAGER}, - {true, ui::VKEY_OEM_2, ui::EF_CONTROL_DOWN, OPEN_GET_HELP}, - {true, ui::VKEY_OEM_2, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, - OPEN_GET_HELP}, - {true, ui::VKEY_T, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, OPEN_CROSH}, - {true, ui::VKEY_I, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - TOUCH_HUD_MODE_CHANGE}, - {true, ui::VKEY_I, - ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN, - TOUCH_HUD_CLEAR}, - {true, ui::VKEY_P, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - TOUCH_HUD_PROJECTION_TOGGLE}, - {true, ui::VKEY_H, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, - TOGGLE_HIGH_CONTRAST}, - {true, ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - TOGGLE_SPOKEN_FEEDBACK}, - {true, ui::VKEY_OEM_COMMA, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - SWITCH_TO_PREVIOUS_USER}, - {true, ui::VKEY_OEM_PERIOD, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - SWITCH_TO_NEXT_USER}, - // Single shift release turns off caps lock. - {false, ui::VKEY_LSHIFT, ui::EF_NONE, DISABLE_CAPS_LOCK}, - {false, ui::VKEY_SHIFT, ui::EF_NONE, DISABLE_CAPS_LOCK}, - {false, ui::VKEY_RSHIFT, ui::EF_NONE, DISABLE_CAPS_LOCK}, - // Accelerators to toggle Caps Lock. - // The following is triggered when Search is released while Alt is still - // down. The key_code here is LWIN (for search) and Alt is a modifier. - {false, ui::VKEY_LWIN, ui::EF_ALT_DOWN, TOGGLE_CAPS_LOCK}, - // The following is triggered when Alt is released while search is still - // down. The key_code here is MENU (for Alt) and Search is a modifier - // (EF_COMMAND_DOWN is used for Search as a modifier). - {false, ui::VKEY_MENU, ui::EF_COMMAND_DOWN, TOGGLE_CAPS_LOCK}, - {true, ui::VKEY_VOLUME_MUTE, ui::EF_NONE, VOLUME_MUTE}, - {true, ui::VKEY_VOLUME_DOWN, ui::EF_NONE, VOLUME_DOWN}, - {true, ui::VKEY_VOLUME_UP, ui::EF_NONE, VOLUME_UP}, - {true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN, SHOW_TASK_MANAGER}, - {true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, NEXT_IME}, - {true, ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, OPEN_FEEDBACK_PAGE}, - {true, ui::VKEY_Q, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, EXIT}, - {true, ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, - NEW_INCOGNITO_WINDOW}, - {true, ui::VKEY_N, ui::EF_CONTROL_DOWN, NEW_WINDOW}, - {true, ui::VKEY_T, ui::EF_CONTROL_DOWN, NEW_TAB}, - {true, ui::VKEY_OEM_MINUS, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, - SCALE_UI_UP}, - {true, ui::VKEY_OEM_PLUS, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, - SCALE_UI_DOWN}, - {true, ui::VKEY_0, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, SCALE_UI_RESET}, - {true, ui::VKEY_BROWSER_REFRESH, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, - ROTATE_SCREEN}, - {true, ui::VKEY_BROWSER_REFRESH, - ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, ROTATE_WINDOW}, - {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, RESTORE_TAB}, - {true, ui::VKEY_PRINT, ui::EF_NONE, TAKE_SCREENSHOT}, - // On Chrome OS, Search key is mapped to LWIN. The Search key binding should - // act on release instead of press when using Search as a modifier key for - // extended keyboard shortcuts. - {false, ui::VKEY_LWIN, ui::EF_NONE, TOGGLE_APP_LIST}, - {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_NONE, TOGGLE_FULLSCREEN}, - {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_SHIFT_DOWN, TOGGLE_FULLSCREEN}, - {true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN, UNPIN}, - {true, ui::VKEY_L, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, FOCUS_SHELF}, - {true, ui::VKEY_HELP, ui::EF_NONE, SHOW_KEYBOARD_OVERLAY}, - {true, ui::VKEY_OEM_2, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - SHOW_KEYBOARD_OVERLAY}, - {true, ui::VKEY_OEM_2, - ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - SHOW_KEYBOARD_OVERLAY}, - {true, ui::VKEY_F14, ui::EF_NONE, SHOW_KEYBOARD_OVERLAY}, - {true, ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, - SHOW_MESSAGE_CENTER_BUBBLE}, - {true, ui::VKEY_P, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, SHOW_STYLUS_TOOLS}, - {true, ui::VKEY_S, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, - SHOW_SYSTEM_TRAY_BUBBLE}, - {true, ui::VKEY_K, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, - SHOW_IME_MENU_BUBBLE}, - {true, ui::VKEY_1, ui::EF_ALT_DOWN, LAUNCH_APP_0}, - {true, ui::VKEY_2, ui::EF_ALT_DOWN, LAUNCH_APP_1}, - {true, ui::VKEY_3, ui::EF_ALT_DOWN, LAUNCH_APP_2}, - {true, ui::VKEY_4, ui::EF_ALT_DOWN, LAUNCH_APP_3}, - {true, ui::VKEY_5, ui::EF_ALT_DOWN, LAUNCH_APP_4}, - {true, ui::VKEY_6, ui::EF_ALT_DOWN, LAUNCH_APP_5}, - {true, ui::VKEY_7, ui::EF_ALT_DOWN, LAUNCH_APP_6}, - {true, ui::VKEY_8, ui::EF_ALT_DOWN, LAUNCH_APP_7}, - {true, ui::VKEY_9, ui::EF_ALT_DOWN, LAUNCH_LAST_APP}, - - // Window management shortcuts. - {true, ui::VKEY_OEM_4, ui::EF_ALT_DOWN, WINDOW_CYCLE_SNAP_DOCK_LEFT}, - {true, ui::VKEY_OEM_6, ui::EF_ALT_DOWN, WINDOW_CYCLE_SNAP_DOCK_RIGHT}, - {true, ui::VKEY_OEM_MINUS, ui::EF_ALT_DOWN, WINDOW_MINIMIZE}, - {true, ui::VKEY_OEM_PLUS, ui::EF_ALT_DOWN, TOGGLE_MAXIMIZED}, - {true, ui::VKEY_OEM_PLUS, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, - WINDOW_POSITION_CENTER}, - {true, ui::VKEY_BROWSER_FORWARD, ui::EF_CONTROL_DOWN, FOCUS_NEXT_PANE}, - {true, ui::VKEY_BROWSER_BACK, ui::EF_CONTROL_DOWN, FOCUS_PREVIOUS_PANE}, - - // Media Player shortcuts. - {true, ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE, MEDIA_NEXT_TRACK}, - {true, ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE, MEDIA_PLAY_PAUSE}, - {true, ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE, MEDIA_PREV_TRACK}, - - // Debugging shortcuts that need to be available to end-users in - // release builds. - {true, ui::VKEY_U, kDebugModifier, PRINT_UI_HIERARCHIES}, - - // TODO(yusukes): Handle VKEY_MEDIA_STOP, and - // VKEY_MEDIA_LAUNCH_MAIL. -}; - -const size_t kAcceleratorDataLength = arraysize(kAcceleratorData); - -// Instructions for how to deprecate and replace an Accelerator: -// -// 1- Replace the old deprecated accelerator from the above list with the new -// accelerator that will take its place. -// 2- Add an entry for it in the following |kDeprecatedAccelerators| list. -// 3- Add another entry in the |kDeprecatedAcceleratorsData|. -// 4- That entry should contain the following: -// - The action that the deprecated accelerator maps to. -// - Define a histogram for this action in |histograms.xml| in the form -// "Ash.Accelerators.Deprecated.{ActionName}" and include the name of this -// histogram in this entry. This name will be used as the ID of the -// notification to be shown to the user. This is to prevent duplication of -// same notification. -// - The ID of the localized notification message to give the users telling -// them about the deprecation (Add one in |ash_strings.grd|. Search for -// the comment <!-- Deprecated Accelerators Messages -->). -// - The IDs of the localized old and new shortcut text to be used to fill -// the notification text. Also found in |ash_strings.grd|. -// - {true or false} whether the deprecated accelerator is still enabled (we -// don't disable a deprecated accelerator abruptly). -// 5- Don't forget to update the keyboard overlay. Find 'shortcut' in the file -// keyboard_overlay_data.js. -const AcceleratorData kDeprecatedAccelerators[] = { - {true, ui::VKEY_L, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, LOCK_SCREEN}, - {true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN, SHOW_TASK_MANAGER}}; - -const size_t kDeprecatedAcceleratorsLength = arraysize(kDeprecatedAccelerators); - -const DeprecatedAcceleratorData kDeprecatedAcceleratorsData[] = { - { - LOCK_SCREEN, "Ash.Accelerators.Deprecated.LockScreen", - IDS_DEPRECATED_LOCK_SCREEN_MSG, IDS_SHORTCUT_LOCK_SCREEN_OLD, - IDS_SHORTCUT_LOCK_SCREEN_NEW, - false // Old accelerator was disabled in M56. - }, - {SHOW_TASK_MANAGER, "Ash.Accelerators.Deprecated.ShowTaskManager", - IDS_DEPRECATED_SHOW_TASK_MANAGER_MSG, IDS_SHORTCUT_TASK_MANAGER_OLD, - IDS_SHORTCUT_TASK_MANAGER_NEW, true}}; - -const size_t kDeprecatedAcceleratorsDataLength = - arraysize(kDeprecatedAcceleratorsData); - -const AcceleratorData kDebugAcceleratorData[] = { - {true, ui::VKEY_N, kDebugModifier, TOGGLE_WIFI}, - {true, ui::VKEY_O, kDebugModifier, DEBUG_SHOW_TOAST}, - {true, ui::VKEY_P, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, - DEBUG_TOGGLE_TOUCH_PAD}, - {true, ui::VKEY_T, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, - DEBUG_TOGGLE_TOUCH_SCREEN}, - {true, ui::VKEY_T, kDebugModifier, DEBUG_TOGGLE_TOUCH_VIEW}, - {true, ui::VKEY_B, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, - DEBUG_TOGGLE_WALLPAPER_MODE}, - {true, ui::VKEY_L, kDebugModifier, DEBUG_PRINT_LAYER_HIERARCHY}, - {true, ui::VKEY_V, kDebugModifier, DEBUG_PRINT_VIEW_HIERARCHY}, - {true, ui::VKEY_W, kDebugModifier, DEBUG_PRINT_WINDOW_HIERARCHY}, - {true, ui::VKEY_D, kDebugModifier, DEBUG_TOGGLE_DEVICE_SCALE_FACTOR}, - {true, ui::VKEY_B, kDebugModifier, DEBUG_TOGGLE_SHOW_DEBUG_BORDERS}, - {true, ui::VKEY_F, kDebugModifier, DEBUG_TOGGLE_SHOW_FPS_COUNTER}, - {true, ui::VKEY_P, kDebugModifier, DEBUG_TOGGLE_SHOW_PAINT_RECTS}, - {true, ui::VKEY_K, kDebugModifier, DEBUG_TRIGGER_CRASH}, -}; - -const size_t kDebugAcceleratorDataLength = arraysize(kDebugAcceleratorData); - -const AcceleratorData kDeveloperAcceleratorData[] = { - // Extra shortcut for debug build to control magnifier on Linux desktop. - {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_CONTROL_DOWN, - MAGNIFY_SCREEN_ZOOM_OUT}, - {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_CONTROL_DOWN, MAGNIFY_SCREEN_ZOOM_IN}, - // Extra shortcuts to lock the screen on Linux desktop. - {true, ui::VKEY_L, ui::EF_ALT_DOWN, LOCK_PRESSED}, - {false, ui::VKEY_L, ui::EF_ALT_DOWN, LOCK_RELEASED}, - {true, ui::VKEY_P, ui::EF_ALT_DOWN, POWER_PRESSED}, - {false, ui::VKEY_P, ui::EF_ALT_DOWN, POWER_RELEASED}, - {true, ui::VKEY_POWER, ui::EF_SHIFT_DOWN, LOCK_PRESSED}, - {false, ui::VKEY_POWER, ui::EF_SHIFT_DOWN, LOCK_RELEASED}, - {true, ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, - DEV_ADD_REMOVE_DISPLAY}, - {true, ui::VKEY_J, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, - DEV_TOGGLE_UNIFIED_DESKTOP}, - {true, ui::VKEY_M, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, - TOGGLE_MIRROR_MODE}, - {true, ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, TOGGLE_WIFI}, - // Extra shortcut for display swapping as Alt-F4 is taken on Linux desktop. - {true, ui::VKEY_S, kDebugModifier, SWAP_PRIMARY_DISPLAY}, - // Extra shortcut to rotate/scale up/down the screen on Linux desktop. - {true, ui::VKEY_R, kDebugModifier, ROTATE_SCREEN}, - // For testing on systems where Alt-Tab is already mapped. - {true, ui::VKEY_W, ui::EF_ALT_DOWN, CYCLE_FORWARD_MRU}, - {true, ui::VKEY_F11, ui::EF_CONTROL_DOWN, - DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN}, - {true, ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU}, - {true, ui::VKEY_F, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, - TOGGLE_FULLSCREEN}, -}; - -const size_t kDeveloperAcceleratorDataLength = - arraysize(kDeveloperAcceleratorData); - -const AcceleratorAction kPreferredActions[] = { - // Window cycling accelerators. - CYCLE_BACKWARD_MRU, // Shift+Alt+Tab - CYCLE_FORWARD_MRU, // Alt+Tab -}; - -const size_t kPreferredActionsLength = arraysize(kPreferredActions); - -const AcceleratorAction kReservedActions[] = { - POWER_PRESSED, POWER_RELEASED, SUSPEND, -}; - -const size_t kReservedActionsLength = arraysize(kReservedActions); - -const AcceleratorAction kActionsAllowedAtLoginOrLockScreen[] = { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - DEBUG_PRINT_LAYER_HIERARCHY, - DEBUG_PRINT_VIEW_HIERARCHY, - DEBUG_PRINT_WINDOW_HIERARCHY, - DEBUG_TOGGLE_TOUCH_PAD, - DEBUG_TOGGLE_TOUCH_SCREEN, - DEBUG_TOGGLE_TOUCH_VIEW, - DEV_ADD_REMOVE_DISPLAY, - DISABLE_CAPS_LOCK, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - MAGNIFY_SCREEN_ZOOM_IN, // Control+F7 - MAGNIFY_SCREEN_ZOOM_OUT, // Control+F6 - NEXT_IME, - PREVIOUS_IME, - PRINT_UI_HIERARCHIES, - ROTATE_SCREEN, - SCALE_UI_DOWN, - SCALE_UI_RESET, - SCALE_UI_UP, - SHOW_IME_MENU_BUBBLE, - SHOW_SYSTEM_TRAY_BUBBLE, - SWITCH_IME, // Switch to another IME depending on the accelerator. - TAKE_PARTIAL_SCREENSHOT, - TAKE_SCREENSHOT, - TAKE_WINDOW_SCREENSHOT, - TOGGLE_CAPS_LOCK, - TOGGLE_HIGH_CONTRAST, - TOGGLE_MIRROR_MODE, - TOGGLE_SPOKEN_FEEDBACK, - TOGGLE_WIFI, - TOUCH_HUD_CLEAR, - VOLUME_DOWN, - VOLUME_MUTE, - VOLUME_UP, -#if !defined(NDEBUG) - POWER_PRESSED, - POWER_RELEASED, -#endif // !defined(NDEBUG) -}; - -const size_t kActionsAllowedAtLoginOrLockScreenLength = - arraysize(kActionsAllowedAtLoginOrLockScreen); - -const AcceleratorAction kActionsAllowedAtLockScreen[] = { - EXIT, SUSPEND, -}; - -const size_t kActionsAllowedAtLockScreenLength = - arraysize(kActionsAllowedAtLockScreen); - -const AcceleratorAction kActionsAllowedAtModalWindow[] = { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - DEBUG_TOGGLE_TOUCH_PAD, - DEBUG_TOGGLE_TOUCH_SCREEN, - DEV_ADD_REMOVE_DISPLAY, - DISABLE_CAPS_LOCK, - EXIT, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - LOCK_SCREEN, - MAGNIFY_SCREEN_ZOOM_IN, - MAGNIFY_SCREEN_ZOOM_OUT, - MEDIA_NEXT_TRACK, - MEDIA_PLAY_PAUSE, - MEDIA_PREV_TRACK, - NEXT_IME, - OPEN_FEEDBACK_PAGE, - POWER_PRESSED, - POWER_RELEASED, - PREVIOUS_IME, - PRINT_UI_HIERARCHIES, - ROTATE_SCREEN, - SCALE_UI_DOWN, - SCALE_UI_RESET, - SCALE_UI_UP, - SHOW_IME_MENU_BUBBLE, - SHOW_KEYBOARD_OVERLAY, - SUSPEND, - SWAP_PRIMARY_DISPLAY, - SWITCH_IME, - TAKE_PARTIAL_SCREENSHOT, - TAKE_SCREENSHOT, - TAKE_WINDOW_SCREENSHOT, - TOGGLE_CAPS_LOCK, - TOGGLE_HIGH_CONTRAST, - TOGGLE_MIRROR_MODE, - TOGGLE_SPOKEN_FEEDBACK, - TOGGLE_WIFI, - VOLUME_DOWN, - VOLUME_MUTE, - VOLUME_UP, -}; - -const size_t kActionsAllowedAtModalWindowLength = - arraysize(kActionsAllowedAtModalWindow); - -const AcceleratorAction kRepeatableActions[] = { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - FOCUS_NEXT_PANE, - FOCUS_PREVIOUS_PANE, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - MAGNIFY_SCREEN_ZOOM_IN, - MAGNIFY_SCREEN_ZOOM_OUT, - MEDIA_NEXT_TRACK, - MEDIA_PREV_TRACK, - RESTORE_TAB, - VOLUME_DOWN, - VOLUME_UP, -}; - -const size_t kRepeatableActionsLength = arraysize(kRepeatableActions); - -const AcceleratorAction kActionsAllowedInAppModeOrPinnedMode[] = { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - DEBUG_PRINT_LAYER_HIERARCHY, - DEBUG_PRINT_VIEW_HIERARCHY, - DEBUG_PRINT_WINDOW_HIERARCHY, - DEBUG_TOGGLE_TOUCH_PAD, - DEBUG_TOGGLE_TOUCH_SCREEN, - DEV_ADD_REMOVE_DISPLAY, - DISABLE_CAPS_LOCK, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - MAGNIFY_SCREEN_ZOOM_IN, // Control+F7 - MAGNIFY_SCREEN_ZOOM_OUT, // Control+F6 - MEDIA_NEXT_TRACK, - MEDIA_PLAY_PAUSE, - MEDIA_PREV_TRACK, - NEXT_IME, - POWER_PRESSED, - POWER_RELEASED, - PREVIOUS_IME, - PRINT_UI_HIERARCHIES, - ROTATE_SCREEN, - SCALE_UI_DOWN, - SCALE_UI_RESET, - SCALE_UI_UP, - SWAP_PRIMARY_DISPLAY, - SWITCH_IME, // Switch to another IME depending on the accelerator. - TOGGLE_CAPS_LOCK, - TOGGLE_HIGH_CONTRAST, - TOGGLE_MIRROR_MODE, - TOGGLE_SPOKEN_FEEDBACK, - TOGGLE_WIFI, - TOUCH_HUD_CLEAR, - VOLUME_DOWN, - VOLUME_MUTE, - VOLUME_UP, -}; - -const size_t kActionsAllowedInAppModeOrPinnedModeLength = - arraysize(kActionsAllowedInAppModeOrPinnedMode); - -const AcceleratorAction kActionsAllowedInPinnedMode[] = { - LOCK_SCREEN, - SUSPEND, - TAKE_PARTIAL_SCREENSHOT, - TAKE_SCREENSHOT, - TAKE_WINDOW_SCREENSHOT, - UNPIN, -}; - -const size_t kActionsAllowedInPinnedModeLength = - arraysize(kActionsAllowedInPinnedMode); - -const AcceleratorAction kActionsNeedingWindow[] = { - CYCLE_BACKWARD_MRU, - CYCLE_FORWARD_MRU, - TOGGLE_OVERVIEW, - WINDOW_CYCLE_SNAP_DOCK_LEFT, - WINDOW_CYCLE_SNAP_DOCK_RIGHT, - WINDOW_MINIMIZE, - TOGGLE_FULLSCREEN, - TOGGLE_MAXIMIZED, - WINDOW_POSITION_CENTER, - ROTATE_WINDOW, -}; - -const size_t kActionsNeedingWindowLength = arraysize(kActionsNeedingWindow); - -const AcceleratorAction kActionsKeepingMenuOpen[] = { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - DEBUG_TOGGLE_TOUCH_PAD, - DEBUG_TOGGLE_TOUCH_SCREEN, - DISABLE_CAPS_LOCK, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - MEDIA_NEXT_TRACK, - MEDIA_PLAY_PAUSE, - MEDIA_PREV_TRACK, - NEXT_IME, - PREVIOUS_IME, - PRINT_UI_HIERARCHIES, - SWITCH_IME, - TAKE_PARTIAL_SCREENSHOT, - TAKE_SCREENSHOT, - TAKE_WINDOW_SCREENSHOT, - TOGGLE_APP_LIST, - TOGGLE_CAPS_LOCK, - TOGGLE_HIGH_CONTRAST, - TOGGLE_SPOKEN_FEEDBACK, - TOGGLE_WIFI, - VOLUME_DOWN, - VOLUME_MUTE, - VOLUME_UP, -}; - -const size_t kActionsKeepingMenuOpenLength = arraysize(kActionsKeepingMenuOpen); - -} // namespace ash
diff --git a/ash/accelerators/accelerator_table.h b/ash/accelerators/accelerator_table.h deleted file mode 100644 index 34b8476..0000000 --- a/ash/accelerators/accelerator_table.h +++ /dev/null
@@ -1,264 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_ACCELERATOR_TABLE_H_ -#define ASH_ACCELERATORS_ACCELERATOR_TABLE_H_ - -#include <stddef.h> - -#include "ash/ash_export.h" -#include "ui/events/event_constants.h" -#include "ui/events/keycodes/keyboard_codes.h" - -namespace ash { - -// There are five classes of accelerators in Ash: -// -// Ash (OS) reserved: -// * Neither packaged apps nor web pages can cancel. -// * For example, power button. -// * See kReservedActions below. -// -// Ash (OS) preferred: -// * Fullscreen window can consume, but normal window can't. -// * For example, Alt-Tab window cycling. -// * See kPreferredActions below. -// -// Chrome OS system keys: -// * For legacy reasons, v1 apps can process and cancel. Otherwise handled -// directly by Ash. -// * Brightness, volume control, etc. -// * See IsSystemKey() in ash/accelerators/accelerator_filter.cc. -// -// Browser reserved: -// * Packaged apps can cancel but web pages cannot. -// * For example, browser back and forward from first-row function keys. -// * See IsReservedCommandOrKey() in -// chrome/browser/ui/browser_command_controller.cc. -// -// Browser non-reserved: -// * Both packaged apps and web pages can cancel. -// * For example, selecting tabs by number with Ctrl-1 to Ctrl-9. -// * See kAcceleratorMap in chrome/browser/ui/views/accelerator_table.cc. -// -// In particular, there is not an accelerator processing pass for Ash after -// the browser gets the accelerator. See crbug.com/285308 for details. -// -// There are also various restrictions on accelerators allowed at the login -// screen, when running in "forced app mode" (like a kiosk), etc. See the -// various kActionsAllowed* below. -// -// Please put if/def sections at the end of the bare section and keep the list -// within each section in alphabetical order. -enum AcceleratorAction { - BRIGHTNESS_DOWN, - BRIGHTNESS_UP, - CYCLE_BACKWARD_MRU, - CYCLE_FORWARD_MRU, - DEBUG_PRINT_LAYER_HIERARCHY, - DEBUG_PRINT_VIEW_HIERARCHY, - DEBUG_PRINT_WINDOW_HIERARCHY, - DEBUG_SHOW_TOAST, - DEBUG_TOGGLE_DEVICE_SCALE_FACTOR, - DEBUG_TOGGLE_SHOW_DEBUG_BORDERS, - DEBUG_TOGGLE_SHOW_FPS_COUNTER, - DEBUG_TOGGLE_SHOW_PAINT_RECTS, - DEBUG_TOGGLE_TOUCH_PAD, - DEBUG_TOGGLE_TOUCH_SCREEN, - DEBUG_TOGGLE_TOUCH_VIEW, - DEBUG_TOGGLE_WALLPAPER_MODE, - DEBUG_TRIGGER_CRASH, // Intentionally crash the ash process. - DEV_ADD_REMOVE_DISPLAY, - DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN, - DEV_TOGGLE_UNIFIED_DESKTOP, - DISABLE_CAPS_LOCK, - EXIT, - FOCUS_NEXT_PANE, - FOCUS_PREVIOUS_PANE, - FOCUS_SHELF, - KEYBOARD_BRIGHTNESS_DOWN, - KEYBOARD_BRIGHTNESS_UP, - LAUNCH_APP_0, - LAUNCH_APP_1, - LAUNCH_APP_2, - LAUNCH_APP_3, - LAUNCH_APP_4, - LAUNCH_APP_5, - LAUNCH_APP_6, - LAUNCH_APP_7, - LAUNCH_LAST_APP, - LOCK_PRESSED, - LOCK_RELEASED, - LOCK_SCREEN, - MAGNIFY_SCREEN_ZOOM_IN, - MAGNIFY_SCREEN_ZOOM_OUT, - MEDIA_NEXT_TRACK, - MEDIA_PLAY_PAUSE, - MEDIA_PREV_TRACK, - NEW_INCOGNITO_WINDOW, - NEW_TAB, - NEW_WINDOW, - NEXT_IME, - OPEN_CROSH, - OPEN_FEEDBACK_PAGE, - OPEN_FILE_MANAGER, - OPEN_GET_HELP, - POWER_PRESSED, - POWER_RELEASED, - PREVIOUS_IME, - PRINT_UI_HIERARCHIES, - RESTORE_TAB, - ROTATE_SCREEN, - ROTATE_WINDOW, - SCALE_UI_DOWN, - SCALE_UI_RESET, - SCALE_UI_UP, - SHOW_IME_MENU_BUBBLE, - SHOW_KEYBOARD_OVERLAY, - SHOW_MESSAGE_CENTER_BUBBLE, - SHOW_STYLUS_TOOLS, - SHOW_SYSTEM_TRAY_BUBBLE, - SHOW_TASK_MANAGER, - SUSPEND, - SWAP_PRIMARY_DISPLAY, - SWITCH_IME, // Switch to another IME depending on the accelerator. - SWITCH_TO_NEXT_USER, - SWITCH_TO_PREVIOUS_USER, - TAKE_PARTIAL_SCREENSHOT, - TAKE_SCREENSHOT, - TAKE_WINDOW_SCREENSHOT, - TOGGLE_APP_LIST, - TOGGLE_CAPS_LOCK, - TOGGLE_FULLSCREEN, - TOGGLE_HIGH_CONTRAST, - TOGGLE_MAXIMIZED, - TOGGLE_MIRROR_MODE, - TOGGLE_OVERVIEW, - TOGGLE_SPOKEN_FEEDBACK, - TOGGLE_WIFI, - TOUCH_HUD_CLEAR, - TOUCH_HUD_MODE_CHANGE, - TOUCH_HUD_PROJECTION_TOGGLE, - UNPIN, - VOLUME_DOWN, - VOLUME_MUTE, - VOLUME_UP, - WINDOW_CYCLE_SNAP_DOCK_LEFT, - WINDOW_CYCLE_SNAP_DOCK_RIGHT, - WINDOW_MINIMIZE, - WINDOW_POSITION_CENTER, -}; - -struct AcceleratorData { - bool trigger_on_press; - ui::KeyboardCode keycode; - int modifiers; - AcceleratorAction action; -}; - -// Gathers the needed data to handle deprecated accelerators. -struct DeprecatedAcceleratorData { - // The action that has deprecated accelerators. - AcceleratorAction action; - - // The name of the UMA histogram that will be used to measure the deprecated - // v.s. new accelerator usage. - const char* uma_histogram_name; - - // The ID of the localized notification message to show to users informing - // them about the deprecation. - int notification_message_id; - - // The ID of the localized old deprecated shortcut key. - int old_shortcut_id; - - // The ID of the localized new shortcut key. - int new_shortcut_id; - - // Specifies whether the deprecated accelerator is still enabled to do its - // associated action. - bool deprecated_enabled; -}; - -// This will be used for the UMA stats to measure the how many users are using -// the old v.s. new accelerators. -enum DeprecatedAcceleratorUsage { - DEPRECATED_USED = 0, // The deprecated accelerator is used. - NEW_USED, // The new accelerator is used. - DEPRECATED_USAGE_COUNT, // Maximum value of this enum for histogram use. -}; - -// Accelerators handled by AcceleratorController. -ASH_EXPORT extern const AcceleratorData kAcceleratorData[]; -ASH_EXPORT extern const size_t kAcceleratorDataLength; - -// The list of the deprecated accelerators. -ASH_EXPORT extern const AcceleratorData kDeprecatedAccelerators[]; -ASH_EXPORT extern const size_t kDeprecatedAcceleratorsLength; - -// The list of the actions with deprecated accelerators and the needed data to -// handle them. -ASH_EXPORT extern const DeprecatedAcceleratorData kDeprecatedAcceleratorsData[]; -ASH_EXPORT extern const size_t kDeprecatedAcceleratorsDataLength; - -// Debug accelerators. Debug accelerators are only enabled when the "Debugging -// keyboard shortcuts" flag (--ash-debug-shortcuts) is enabled. Debug actions -// are always run (similar to reserved actions). Debug accelerators can be -// enabled in about:flags. -ASH_EXPORT extern const AcceleratorData kDebugAcceleratorData[]; -ASH_EXPORT extern const size_t kDebugAcceleratorDataLength; - -// Developer accelerators that are enabled only with the command-line switch -// --ash-dev-shortcuts. They are always run similar to reserved actions. -ASH_EXPORT extern const AcceleratorData kDeveloperAcceleratorData[]; -ASH_EXPORT extern const size_t kDeveloperAcceleratorDataLength; - -// Actions that should be handled very early in Ash unless the current target -// window is full-screen. -ASH_EXPORT extern const AcceleratorAction kPreferredActions[]; -ASH_EXPORT extern const size_t kPreferredActionsLength; - -// Actions that are always handled in Ash. -ASH_EXPORT extern const AcceleratorAction kReservedActions[]; -ASH_EXPORT extern const size_t kReservedActionsLength; - -// Actions allowed while user is not signed in or screen is locked. -ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtLoginOrLockScreen[]; -ASH_EXPORT extern const size_t kActionsAllowedAtLoginOrLockScreenLength; - -// Actions allowed while screen is locked (in addition to -// kActionsAllowedAtLoginOrLockScreen). -ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtLockScreen[]; -ASH_EXPORT extern const size_t kActionsAllowedAtLockScreenLength; - -// Actions allowed while a modal window is up. -ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtModalWindow[]; -ASH_EXPORT extern const size_t kActionsAllowedAtModalWindowLength; - -// Actions which may be repeated by holding an accelerator key. -ASH_EXPORT extern const AcceleratorAction kRepeatableActions[]; -ASH_EXPORT extern const size_t kRepeatableActionsLength; - -// Actions allowed in app mode or pinned mode. -ASH_EXPORT extern const AcceleratorAction - kActionsAllowedInAppModeOrPinnedMode[]; -ASH_EXPORT extern const size_t kActionsAllowedInAppModeOrPinnedModeLength; - -// Actions that can be performed in pinned mode. -// In pinned mode, the action listed this or "in app mode or pinned mode" table -// can be performed. -ASH_EXPORT extern const AcceleratorAction kActionsAllowedInPinnedMode[]; -ASH_EXPORT extern const size_t kActionsAllowedInPinnedModeLength; - -// Actions that require at least 1 window. -ASH_EXPORT extern const AcceleratorAction kActionsNeedingWindow[]; -ASH_EXPORT extern const size_t kActionsNeedingWindowLength; - -// Actions that can be performed while keeping the menu open. -ASH_EXPORT extern const AcceleratorAction kActionsKeepingMenuOpen[]; -ASH_EXPORT extern const size_t kActionsKeepingMenuOpenLength; - -} // namespace ash - -#endif // ASH_ACCELERATORS_ACCELERATOR_TABLE_H_
diff --git a/ash/accelerators/accelerator_table_unittest.cc b/ash/accelerators/accelerator_table_unittest.cc deleted file mode 100644 index 927165f..0000000 --- a/ash/accelerators/accelerator_table_unittest.cc +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <set> - -#include "ash/accelerators/accelerator_table.h" -#include "base/strings/string_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace ash { - -namespace { - -struct Cmp { - bool operator()(const AcceleratorData& lhs, const AcceleratorData& rhs) { - if (lhs.trigger_on_press != rhs.trigger_on_press) - return lhs.trigger_on_press < rhs.trigger_on_press; - if (lhs.keycode != rhs.keycode) - return lhs.keycode < rhs.keycode; - return lhs.modifiers < rhs.modifiers; - // Do not check |action|. - } -}; - -} // namespace - -TEST(AcceleratorTableTest, CheckDuplicatedAccelerators) { - std::set<AcceleratorData, Cmp> accelerators; - for (size_t i = 0; i < kAcceleratorDataLength; ++i) { - const AcceleratorData& entry = kAcceleratorData[i]; - EXPECT_TRUE(accelerators.insert(entry).second) - << "Duplicated accelerator: " << entry.trigger_on_press << ", " - << entry.keycode << ", " << (entry.modifiers & ui::EF_SHIFT_DOWN) - << ", " << (entry.modifiers & ui::EF_CONTROL_DOWN) << ", " - << (entry.modifiers & ui::EF_ALT_DOWN); - } -} - -TEST(AcceleratorTableTest, CheckDuplicatedReservedActions) { - std::set<AcceleratorAction> actions; - for (size_t i = 0; i < kReservedActionsLength; ++i) { - EXPECT_TRUE(actions.insert(kReservedActions[i]).second) - << "Duplicated action: " << kReservedActions[i]; - } -} - -TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtLoginOrLockScreen) { - std::set<AcceleratorAction> actions; - for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { - EXPECT_TRUE(actions.insert(kActionsAllowedAtLoginOrLockScreen[i]).second) - << "Duplicated action: " << kActionsAllowedAtLoginOrLockScreen[i]; - } - for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) { - EXPECT_TRUE(actions.insert(kActionsAllowedAtLockScreen[i]).second) - << "Duplicated action: " << kActionsAllowedAtLockScreen[i]; - } -} - -TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtModalWindow) { - std::set<AcceleratorAction> actions; - for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) { - EXPECT_TRUE(actions.insert(kActionsAllowedAtModalWindow[i]).second) - << "Duplicated action: " << kActionsAllowedAtModalWindow[i] - << " at index: " << i; - } -} - -TEST(AcceleratorTableTest, CheckDuplicatedRepeatableActions) { - std::set<AcceleratorAction> actions; - for (size_t i = 0; i < kRepeatableActionsLength; ++i) { - EXPECT_TRUE(actions.insert(kRepeatableActions[i]).second) - << "Duplicated action: " << kRepeatableActions[i] << " at index: " << i; - } -} - -TEST(AcceleratorTableTest, CheckDeprecatedAccelerators) { - std::set<AcceleratorData, Cmp> deprecated_actions; - for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) { - // A deprecated action can never appear twice in the list. - const AcceleratorData& entry = kDeprecatedAccelerators[i]; - EXPECT_TRUE(deprecated_actions.insert(entry).second) - << "Duplicate deprecated accelerator: " << entry.trigger_on_press - << ", " << entry.keycode << ", " - << (entry.modifiers & ui::EF_SHIFT_DOWN) << ", " - << (entry.modifiers & ui::EF_CONTROL_DOWN) << ", " - << (entry.modifiers & ui::EF_ALT_DOWN); - } - - std::set<AcceleratorAction> actions; - for (size_t i = 0; i < kDeprecatedAcceleratorsDataLength; ++i) { - // There must never be any duplicated actions. - const DeprecatedAcceleratorData& data = kDeprecatedAcceleratorsData[i]; - EXPECT_TRUE(actions.insert(data.action).second) << "Deprecated action: " - << data.action; - - // The UMA histogram name must be of the format "Ash.Accelerators.*" - std::string uma_histogram(data.uma_histogram_name); - EXPECT_TRUE(base::StartsWith(uma_histogram, "Ash.Accelerators.", - base::CompareCase::SENSITIVE)); - } -} - -} // namespace ash
diff --git a/ash/accelerators/ash_focus_manager_factory.cc b/ash/accelerators/ash_focus_manager_factory.cc deleted file mode 100644 index 596a8d2..0000000 --- a/ash/accelerators/ash_focus_manager_factory.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/ash_focus_manager_factory.h" - -#include "ash/accelerators/accelerator_controller.h" -#include "ash/common/wm_shell.h" -#include "base/memory/ptr_util.h" -#include "ui/views/focus/focus_manager.h" - -namespace ash { - -AshFocusManagerFactory::AshFocusManagerFactory() {} -AshFocusManagerFactory::~AshFocusManagerFactory() {} - -views::FocusManager* AshFocusManagerFactory::CreateFocusManager( - views::Widget* widget, - bool desktop_widget) { - return new views::FocusManager( - widget, - desktop_widget ? nullptr : base::WrapUnique<Delegate>(new Delegate)); -} - -bool AshFocusManagerFactory::Delegate::ProcessAccelerator( - const ui::Accelerator& accelerator) { - AcceleratorController* controller = WmShell::Get()->accelerator_controller(); - if (controller) - return controller->Process(accelerator); - return false; -} - -} // namespace ash
diff --git a/ash/accelerators/ash_focus_manager_factory.h b/ash/accelerators/ash_focus_manager_factory.h deleted file mode 100644 index 5d4ac24..0000000 --- a/ash/accelerators/ash_focus_manager_factory.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_ASH_FOCUS_MANAGER_FACTORY_H_ -#define ASH_ACCELERATORS_ASH_FOCUS_MANAGER_FACTORY_H_ - -#include "base/macros.h" -#include "ui/views/focus/focus_manager_delegate.h" -#include "ui/views/focus/focus_manager_factory.h" - -namespace ash { - -// A factory class for creating a custom views::FocusManager object which -// supports Ash shortcuts. -class AshFocusManagerFactory : public views::FocusManagerFactory { - public: - AshFocusManagerFactory(); - ~AshFocusManagerFactory() override; - - protected: - // views::FocusManagerFactory overrides: - views::FocusManager* CreateFocusManager(views::Widget* widget, - bool desktop_widget) override; - - private: - class Delegate : public views::FocusManagerDelegate { - public: - // views::FocusManagerDelegate overrides: - bool ProcessAccelerator(const ui::Accelerator& accelerator) override; - }; - - DISALLOW_COPY_AND_ASSIGN(AshFocusManagerFactory); -}; - -} // namespace ash - -#endif // ASH_ACCELERATORS_ASH_FOCUS_MANAGER_FACTORY_H_
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc deleted file mode 100644 index 94e978c0..0000000 --- a/ash/accelerators/debug_commands.cc +++ /dev/null
@@ -1,215 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/debug_commands.h" - -#include "ash/accelerators/accelerator_commands.h" -#include "ash/common/ash_switches.h" -#include "ash/common/shell_delegate.h" -#include "ash/common/wallpaper/wallpaper_controller.h" -#include "ash/common/wallpaper/wallpaper_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/system/toast/toast_data.h" -#include "ash/system/toast/toast_manager.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/window_properties.h" -#include "base/command_line.h" -#include "base/metrics/user_metrics.h" -#include "base/metrics/user_metrics_action.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/compositor/debug_utils.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/debug_utils.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace debug { -namespace { - -void HandlePrintLayerHierarchy() { - for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { - ui::Layer* layer = root->GetLayer(); - if (layer) - ui::PrintLayerHierarchy( - layer, root->GetRootWindowController()->GetLastMouseLocationInRoot()); - } -} - -void HandlePrintViewHierarchy() { - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - if (!active_window) - return; - views::Widget* widget = active_window->GetInternalWidget(); - if (!widget) - return; - views::PrintViewHierarchy(widget->GetRootView()); -} - -void PrintWindowHierarchy(const WmWindow* active_window, - WmWindow* window, - int indent, - std::ostringstream* out) { - std::string indent_str(indent, ' '); - std::string name(window->GetName()); - if (name.empty()) - name = "\"\""; - *out << indent_str << name << " (" << window << ")" - << " type=" << window->GetType() - << ((window == active_window) ? " [active] " : " ") - << (window->IsVisible() ? " visible " : " ") - << window->GetBounds().ToString() - << (window->aura_window()->GetProperty(kSnapChildrenToPixelBoundary) - ? " [snapped] " - : "") - << ", subpixel offset=" - << window->GetLayer()->subpixel_position_offset().ToString() << '\n'; - - for (WmWindow* child : window->GetChildren()) - PrintWindowHierarchy(active_window, child, indent + 3, out); -} - -void HandlePrintWindowHierarchy() { - WmWindow* active_window = WmShell::Get()->GetActiveWindow(); - WmWindow::Windows roots = WmShell::Get()->GetAllRootWindows(); - for (size_t i = 0; i < roots.size(); ++i) { - std::ostringstream out; - out << "RootWindow " << i << ":\n"; - PrintWindowHierarchy(active_window, roots[i], 0, &out); - // Error so logs can be collected from end-users. - LOG(ERROR) << out.str(); - } -} - -gfx::ImageSkia CreateWallpaperImage(SkColor fill, SkColor rect) { - // TODO(oshima): Consider adding a command line option to control wallpaper - // images for testing. The size is randomly picked. - gfx::Size image_size(1366, 768); - gfx::Canvas canvas(image_size, 1.0f, true); - canvas.DrawColor(fill); - cc::PaintFlags flags; - flags.setColor(rect); - flags.setStrokeWidth(10); - flags.setStyle(cc::PaintFlags::kStroke_Style); - flags.setBlendMode(SkBlendMode::kSrcOver); - canvas.DrawRoundRect(gfx::Rect(image_size), 100, flags); - return gfx::ImageSkia(canvas.ExtractImageRep()); -} - -void HandleToggleWallpaperMode() { - static int index = 0; - WallpaperController* wallpaper_controller = - WmShell::Get()->wallpaper_controller(); - switch (++index % 4) { - case 0: - ash::WmShell::Get()->wallpaper_delegate()->InitializeWallpaper(); - break; - case 1: - wallpaper_controller->SetWallpaperImage( - CreateWallpaperImage(SK_ColorRED, SK_ColorBLUE), - wallpaper::WALLPAPER_LAYOUT_STRETCH); - break; - case 2: - wallpaper_controller->SetWallpaperImage( - CreateWallpaperImage(SK_ColorBLUE, SK_ColorGREEN), - wallpaper::WALLPAPER_LAYOUT_CENTER); - break; - case 3: - wallpaper_controller->SetWallpaperImage( - CreateWallpaperImage(SK_ColorGREEN, SK_ColorRED), - wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED); - break; - } -} - -void HandleToggleTouchpad() { - base::RecordAction(base::UserMetricsAction("Accel_Toggle_Touchpad")); - ash::WmShell::Get()->delegate()->ToggleTouchpad(); -} - -void HandleToggleTouchscreen() { - base::RecordAction(base::UserMetricsAction("Accel_Toggle_Touchscreen")); - ShellDelegate* delegate = WmShell::Get()->delegate(); - delegate->SetTouchscreenEnabledInPrefs( - !delegate->IsTouchscreenEnabledInPrefs(false /* use_local_state */), - false /* use_local_state */); - delegate->UpdateTouchscreenStatusFromPrefs(); -} - -void HandleToggleTouchView() { - MaximizeModeController* controller = - WmShell::Get()->maximize_mode_controller(); - controller->EnableMaximizeModeWindowManager( - !controller->IsMaximizeModeWindowManagerEnabled()); -} - -void HandleTriggerCrash() { - CHECK(false) << "Intentional crash via debug accelerator."; -} - -} // namespace - -void PrintUIHierarchies() { - // This is a separate command so the user only has to hit one key to generate - // all the logs. Developers use the individual dumps repeatedly, so keep - // those as separate commands to avoid spamming their logs. - HandlePrintLayerHierarchy(); - HandlePrintWindowHierarchy(); - HandlePrintViewHierarchy(); -} - -bool DebugAcceleratorsEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshDebugShortcuts); -} - -bool DeveloperAcceleratorsEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshDeveloperShortcuts); -} - -void PerformDebugActionIfEnabled(AcceleratorAction action) { - if (!DebugAcceleratorsEnabled()) - return; - - switch (action) { - case DEBUG_PRINT_LAYER_HIERARCHY: - HandlePrintLayerHierarchy(); - break; - case DEBUG_PRINT_VIEW_HIERARCHY: - HandlePrintViewHierarchy(); - break; - case DEBUG_PRINT_WINDOW_HIERARCHY: - HandlePrintWindowHierarchy(); - break; - case DEBUG_SHOW_TOAST: - WmShell::Get()->toast_manager()->Show( - ToastData("id", base::ASCIIToUTF16("Toast"), 5000 /* duration_ms */, - base::ASCIIToUTF16("Dismiss"))); - break; - case DEBUG_TOGGLE_TOUCH_PAD: - HandleToggleTouchpad(); - break; - case DEBUG_TOGGLE_TOUCH_SCREEN: - HandleToggleTouchscreen(); - break; - case DEBUG_TOGGLE_TOUCH_VIEW: - HandleToggleTouchView(); - break; - case DEBUG_TOGGLE_WALLPAPER_MODE: - HandleToggleWallpaperMode(); - break; - case DEBUG_TRIGGER_CRASH: - HandleTriggerCrash(); - break; - default: - break; - } -} - -} // namespace debug -} // namespace ash
diff --git a/ash/accelerators/debug_commands.h b/ash/accelerators/debug_commands.h deleted file mode 100644 index e6a0bab..0000000 --- a/ash/accelerators/debug_commands.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_DEBUG_COMMANDS_H_ -#define ASH_ACCELERATORS_DEBUG_COMMANDS_H_ - -#include "ash/accelerators/accelerator_table.h" -#include "ash/ash_export.h" - -// This file contains implementations of commands that are used only when -// debugging. -// -// NOTE: these commands may be enabled in about:flags, so that they may be -// available at run time. -namespace ash { -namespace debug { - -// Print the views::View, ui::Layer and aura::Window hierarchies. This may be -// useful in debugging user reported bugs. -ASH_EXPORT void PrintUIHierarchies(); - -// Returns true if debug accelerators are enabled. -ASH_EXPORT bool DebugAcceleratorsEnabled(); - -// Returns true if developer accelerators are enabled. -ASH_EXPORT bool DeveloperAcceleratorsEnabled(); - -// Performs |action| if |action| belongs to a debug-only accelerator and debug -// accelerators are enabled. -ASH_EXPORT void PerformDebugActionIfEnabled(AcceleratorAction action); - -} // namespace debug -} // namespace ash - -#endif // ASH_ACCELERATORS_DEBUG_COMMANDS_H_
diff --git a/ash/accelerators/exit_warning_handler.cc b/ash/accelerators/exit_warning_handler.cc deleted file mode 100644 index b575066..0000000 --- a/ash/accelerators/exit_warning_handler.cc +++ /dev/null
@@ -1,175 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/accelerators/exit_warning_handler.h" - -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/text_utils.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { -namespace { - -const int64_t kTimeOutMilliseconds = 2000; -// Color of the text of the warning message. -const SkColor kTextColor = SK_ColorWHITE; -// Color of the window background. -const SkColor kWindowBackgroundColor = SkColorSetARGB(0xC0, 0x0, 0x0, 0x0); -// Radius of the rounded corners of the window. -const int kWindowCornerRadius = 2; -const int kHorizontalMarginAroundText = 100; -const int kVerticalMarginAroundText = 100; - -class ExitWarningWidgetDelegateView : public views::WidgetDelegateView { - public: - ExitWarningWidgetDelegateView() - : text_(l10n_util::GetStringUTF16(IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT)), - accessible_name_(l10n_util::GetStringUTF16( - IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT_ACCESSIBLE)), - text_width_(0), - width_(0), - height_(0) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const gfx::FontList& font_list = - rb.GetFontList(ui::ResourceBundle::LargeFont); - text_width_ = gfx::GetStringWidth(text_, font_list); - width_ = text_width_ + kHorizontalMarginAroundText; - height_ = font_list.GetHeight() + kVerticalMarginAroundText; - views::Label* label = new views::Label(); - label->SetText(text_); - label->SetHorizontalAlignment(gfx::ALIGN_CENTER); - label->SetFontList(font_list); - label->SetEnabledColor(kTextColor); - label->SetDisabledColor(kTextColor); - label->SetAutoColorReadabilityEnabled(false); - label->SetSubpixelRenderingEnabled(false); - AddChildView(label); - SetLayoutManager(new views::FillLayout); - } - - gfx::Size GetPreferredSize() const override { - return gfx::Size(width_, height_); - } - - void OnPaint(gfx::Canvas* canvas) override { - cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setColor(kWindowBackgroundColor); - canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, flags); - views::WidgetDelegateView::OnPaint(canvas); - } - - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->SetName(accessible_name_); - node_data->role = ui::AX_ROLE_ALERT; - } - - private: - base::string16 text_; - base::string16 accessible_name_; - int text_width_; - int width_; - int height_; - - DISALLOW_COPY_AND_ASSIGN(ExitWarningWidgetDelegateView); -}; - -} // namespace - -ExitWarningHandler::ExitWarningHandler() - : state_(IDLE), stub_timer_for_test_(false) {} - -ExitWarningHandler::~ExitWarningHandler() { - // Note: If a timer is outstanding, it is stopped in its destructor. - Hide(); -} - -void ExitWarningHandler::HandleAccelerator() { - switch (state_) { - case IDLE: - state_ = WAIT_FOR_DOUBLE_PRESS; - Show(); - StartTimer(); - WmShell::Get()->RecordUserMetricsAction(UMA_ACCEL_EXIT_FIRST_Q); - break; - case WAIT_FOR_DOUBLE_PRESS: - state_ = EXITING; - CancelTimer(); - Hide(); - WmShell::Get()->RecordUserMetricsAction(UMA_ACCEL_EXIT_SECOND_Q); - WmShell::Get()->delegate()->Exit(); - break; - case EXITING: - break; - } -} - -void ExitWarningHandler::TimerAction() { - Hide(); - if (state_ == WAIT_FOR_DOUBLE_PRESS) - state_ = IDLE; -} - -void ExitWarningHandler::StartTimer() { - if (stub_timer_for_test_) - return; - timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(kTimeOutMilliseconds), this, - &ExitWarningHandler::TimerAction); -} - -void ExitWarningHandler::CancelTimer() { - timer_.Stop(); -} - -void ExitWarningHandler::Show() { - if (widget_) - return; - WmWindow* root_window = WmShell::Get()->GetRootWindowForNewWindows(); - ExitWarningWidgetDelegateView* delegate = new ExitWarningWidgetDelegateView; - gfx::Size rs = root_window->GetBounds().size(); - gfx::Size ps = delegate->GetPreferredSize(); - gfx::Rect bounds((rs.width() - ps.width()) / 2, - (rs.height() - ps.height()) / 3, ps.width(), ps.height()); - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_POPUP; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.accept_events = false; - params.keep_on_top = true; - params.remove_standard_frame = true; - params.delegate = delegate; - params.bounds = bounds; - params.name = "ExitWarningWindow"; - widget_.reset(new views::Widget); - root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - widget_.get(), kShellWindowId_SettingBubbleContainer, ¶ms); - widget_->Init(params); - widget_->Show(); - - delegate->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); -} - -void ExitWarningHandler::Hide() { - widget_.reset(); -} - -} // namespace ash
diff --git a/ash/accelerators/exit_warning_handler.h b/ash/accelerators/exit_warning_handler.h deleted file mode 100644 index c678f84d..0000000 --- a/ash/accelerators/exit_warning_handler.h +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_ACCELERATORS_EXIT_WARNING_HANDLER_H_ -#define ASH_ACCELERATORS_EXIT_WARNING_HANDLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "ui/base/accelerators/accelerator.h" - -namespace views { -class Widget; -} - -namespace ash { - -// In order to avoid accidental exits when the user presses the exit shortcut by -// mistake, we require that the user press it twice within a short period of -// time. During that time we show a popup informing the user of this. -// -// Notes: -// -// The corresponding accelerator must not be repeatable (see kRepeatableActions -// in accelerator_table.cc). Otherwise, the "Double Press Exit" will be -// activated just by holding it down, i.e. probably every time. -// -// State Transition Diagrams: -// -// IDLE -// | Press -// WAIT_FOR_DOUBLE_PRESS action: show ui & start timers -// | Press (before time limit ) -// EXITING action: hide ui, stop timer, exit -// -// IDLE -// | Press -// WAIT_FOR_DOUBLE_PRESS action: show ui & start timers -// | T timer expires -// IDLE action: hide ui -// - -class AcceleratorControllerTest; - -class ASH_EXPORT ExitWarningHandler { - public: - ExitWarningHandler(); - - ~ExitWarningHandler(); - - // Handles accelerator for exit (Ctrl-Shift-Q). - void HandleAccelerator(); - - private: - friend class AcceleratorControllerTest; - - enum State { IDLE, WAIT_FOR_DOUBLE_PRESS, EXITING }; - - // Performs actions when the time limit is exceeded. - void TimerAction(); - - void StartTimer(); - void CancelTimer(); - - void Show(); - void Hide(); - - State state_; - std::unique_ptr<views::Widget> widget_; - base::OneShotTimer timer_; - - // Flag to suppress starting the timer for testing. For test we call - // TimerAction() directly to simulate the expiration of the timer. - bool stub_timer_for_test_; - - DISALLOW_COPY_AND_ASSIGN(ExitWarningHandler); -}; - -} // namespace ash - -#endif // ASH_ACCELERATORS_EXIT_WARNING_HANDLER_H_
diff --git a/ash/app_list/app_list_delegate_impl.cc b/ash/app_list/app_list_delegate_impl.cc index 79b2d89b..8f5c63b 100644 --- a/ash/app_list/app_list_delegate_impl.cc +++ b/ash/app_list/app_list_delegate_impl.cc
@@ -4,11 +4,11 @@ #include "ash/app_list/app_list_delegate_impl.h" +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ui/app_list/presenter/app_list.h" namespace ash {
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc index d252ebf0..fd56856 100644 --- a/ash/app_list/app_list_presenter_delegate.cc +++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -5,6 +5,12 @@ #include "ash/app_list/app_list_presenter_delegate.h" #include "ash/common/ash_switches.h" +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/window_tree_host_manager.h" @@ -12,13 +18,7 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/wm_screen_util.h" #include "base/command_line.h" #include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_switches.h"
diff --git a/ash/app_list/app_list_presenter_delegate.h b/ash/app_list/app_list_presenter_delegate.h index 7fd185f..964061b 100644 --- a/ash/app_list/app_list_presenter_delegate.h +++ b/ash/app_list/app_list_presenter_delegate.h
@@ -8,8 +8,8 @@ #include <stdint.h> #include "ash/ash_export.h" +#include "ash/common/shelf/wm_shelf_observer.h" #include "ash/common/shell_observer.h" -#include "ash/shelf/wm_shelf_observer.h" #include "base/macros.h" #include "ui/app_list/presenter/app_list_presenter_delegate.h" #include "ui/events/event_handler.h"
diff --git a/ash/ash_touch_exploration_manager_chromeos.cc b/ash/ash_touch_exploration_manager_chromeos.cc index 5cf171d4..1cd1ccd0 100644 --- a/ash/ash_touch_exploration_manager_chromeos.cc +++ b/ash/ash_touch_exploration_manager_chromeos.cc
@@ -5,11 +5,11 @@ #include "ash/ash_touch_exploration_manager_chromeos.h" #include "ash/common/accessibility_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_notifier.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/memory/ptr_util.h"
diff --git a/ash/ash_touch_exploration_manager_chromeos.h b/ash/ash_touch_exploration_manager_chromeos.h index 2868493b..8b2aa00 100644 --- a/ash/ash_touch_exploration_manager_chromeos.h +++ b/ash/ash_touch_exploration_manager_chromeos.h
@@ -8,7 +8,7 @@ #include <memory> #include "ash/ash_export.h" -#include "ash/system/accessibility_observer.h" +#include "ash/common/system/accessibility_observer.h" #include "base/macros.h" #include "ui/chromeos/touch_accessibility_enabler.h" #include "ui/chromeos/touch_exploration_controller.h"
diff --git a/ash/aura/wm_shell_aura.cc b/ash/aura/wm_shell_aura.cc index 4f6861852..8398546 100644 --- a/ash/aura/wm_shell_aura.cc +++ b/ash/aura/wm_shell_aura.cc
@@ -11,6 +11,9 @@ #include "ash/common/session/session_state_delegate.h" #include "ash/common/shell_delegate.h" #include "ash/common/shell_observer.h" +#include "ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_activation_observer.h" #include "ash/common/wm_display_observer.h" #include "ash/common/wm_window.h" @@ -25,9 +28,6 @@ #include "ash/virtual_keyboard_controller.h" #include "ash/wm/drag_window_resizer.h" #include "ash/wm/maximize_mode/maximize_mode_event_handler_aura.h" -#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/screen_pinning_controller.h" #include "ash/wm/window_cycle_event_filter_aura.h" #include "ash/wm/window_util.h"
diff --git a/ash/autoclick/autoclick_controller.cc b/ash/autoclick/autoclick_controller.cc index cbe9c0c9b..85bf13e 100644 --- a/ash/autoclick/autoclick_controller.cc +++ b/ash/autoclick/autoclick_controller.cc
@@ -6,10 +6,10 @@ #include "ash/autoclick/common/autoclick_controller_common.h" #include "ash/autoclick/common/autoclick_controller_common_delegate.h" +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/root_window_finder.h" #include "base/timer/timer.h" #include "ui/aura/window_observer.h" #include "ui/aura/window_tree_host.h"
diff --git a/ash/common/accelerators/accelerator_commands.cc b/ash/common/accelerators/accelerator_commands.cc new file mode 100644 index 0000000..3fe7d171 --- /dev/null +++ b/ash/common/accelerators/accelerator_commands.cc
@@ -0,0 +1,53 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/accelerator_commands.h" + +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/metrics/user_metrics.h" + +namespace ash { +namespace accelerators { + +bool ToggleMinimized() { + WmWindow* window = WmShell::Get()->GetActiveWindow(); + // Attempt to restore the window that would be cycled through next from + // the launcher when there is no active window. + if (!window) { + MruWindowTracker::WindowList mru_windows( + WmShell::Get()->mru_window_tracker()->BuildMruWindowList()); + if (!mru_windows.empty()) + mru_windows.front()->GetWindowState()->Activate(); + return true; + } + wm::WindowState* window_state = window->GetWindowState(); + if (!window_state->CanMinimize()) + return false; + window_state->Minimize(); + return true; +} + +void ToggleMaximized() { + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + if (!active_window) + return; + base::RecordAction(base::UserMetricsAction("Accel_Toggle_Maximized")); + wm::WMEvent event(wm::WM_EVENT_TOGGLE_MAXIMIZE); + active_window->GetWindowState()->OnWMEvent(&event); +} + +void ToggleFullscreen() { + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + if (!active_window) + return; + const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); + active_window->GetWindowState()->OnWMEvent(&event); +} + +} // namespace accelerators +} // namespace ash
diff --git a/ash/common/accelerators/accelerator_commands.h b/ash/common/accelerators/accelerator_commands.h new file mode 100644 index 0000000..279c59e1 --- /dev/null +++ b/ash/common/accelerators/accelerator_commands.h
@@ -0,0 +1,31 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_ACCELERATOR_COMMANDS_H_ +#define ASH_COMMON_ACCELERATORS_ACCELERATOR_COMMANDS_H_ + +#include "ash/ash_export.h" + +// This file contains implementations of commands that are bound to keyboard +// shortcuts in Ash or in the embedding application (e.g. Chrome). +namespace ash { +namespace accelerators { + +// Minimizes the active window, if present. If no windows are active, restores +// the first unminimized window. Returns true if a window was minimized or +// restored. +ASH_EXPORT bool ToggleMinimized(); + +// Toggles the maxmized state. If the window is in fulllscreen, it exits +// fullscreen mode. +ASH_EXPORT void ToggleMaximized(); + +// Toggles the fullscreen state. The behavior can be overridden +// by WindowStateDelegate::ToggleFullscreen(). +ASH_EXPORT void ToggleFullscreen(); + +} // namespace accelerators +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_ACCELERATOR_COMMANDS_H_
diff --git a/ash/common/accelerators/accelerator_controller.cc b/ash/common/accelerators/accelerator_controller.cc new file mode 100644 index 0000000..52e33dd --- /dev/null +++ b/ash/common/accelerators/accelerator_controller.cc
@@ -0,0 +1,1173 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/accelerator_controller.h" + +#include <utility> + +#include "ash/common/accelerators/accelerator_commands.h" +#include "ash/common/accelerators/accelerator_controller_delegate.h" +#include "ash/common/accelerators/debug_commands.h" +#include "ash/common/accessibility_delegate.h" +#include "ash/common/accessibility_types.h" +#include "ash/common/focus_cycler.h" +#include "ash/common/ime_control_delegate.h" +#include "ash/common/media_controller.h" +#include "ash/common/multi_profile_uma.h" +#include "ash/common/new_window_controller.h" +#include "ash/common/palette_delegate.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shell_delegate.h" +#include "ash/common/system/brightness_control_delegate.h" +#include "ash/common/system/chromeos/ime_menu/ime_menu_tray.h" +#include "ash/common/system/chromeos/palette/palette_tray.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" +#include "ash/common/system/keyboard_brightness_control_delegate.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/web_notification/web_notification_tray.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/window_cycle_controller.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/metrics/histogram_macros.h" +#include "base/metrics/user_metrics.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/accelerators/accelerator_manager.h" +#include "ui/base/ime/chromeos/ime_keyboard.h" +#include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/message_center/message_center.h" + +namespace ash { +namespace { + +using base::UserMetricsAction; +using message_center::Notification; + +// Identifier for the high contrast toggle accelerator notification. +const char kHighContrastToggleAccelNotificationId[] = + "chrome://settings/accessibility/highcontrast"; + +ui::Accelerator CreateAccelerator(ui::KeyboardCode keycode, + int modifiers, + bool trigger_on_press) { + ui::Accelerator accelerator(keycode, modifiers); + accelerator.set_type(trigger_on_press ? ui::ET_KEY_PRESSED + : ui::ET_KEY_RELEASED); + return accelerator; +} + +void RecordUmaHistogram(const char* histogram_name, + DeprecatedAcceleratorUsage sample) { + auto* histogram = base::LinearHistogram::FactoryGet( + histogram_name, 1, DEPRECATED_USAGE_COUNT, DEPRECATED_USAGE_COUNT + 1, + base::HistogramBase::kUmaTargetedHistogramFlag); + histogram->Add(sample); +} + +void HandleCycleBackwardMRU(const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_TAB) + base::RecordAction(base::UserMetricsAction("Accel_PrevWindow_Tab")); + + WmShell::Get()->window_cycle_controller()->HandleCycleWindow( + WindowCycleController::BACKWARD); +} + +void HandleCycleForwardMRU(const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_TAB) + base::RecordAction(base::UserMetricsAction("Accel_NextWindow_Tab")); + + WmShell::Get()->window_cycle_controller()->HandleCycleWindow( + WindowCycleController::FORWARD); +} + +void HandleRotatePaneFocus(FocusCycler::Direction direction) { + switch (direction) { + // TODO(stevet): Not sure if this is the same as IDC_FOCUS_NEXT_PANE. + case FocusCycler::FORWARD: { + base::RecordAction(UserMetricsAction("Accel_Focus_Next_Pane")); + break; + } + case FocusCycler::BACKWARD: { + base::RecordAction(UserMetricsAction("Accel_Focus_Previous_Pane")); + break; + } + } + WmShell::Get()->focus_cycler()->RotateFocus(direction); +} + +void HandleFocusShelf() { + base::RecordAction(UserMetricsAction("Accel_Focus_Shelf")); + // TODO(jamescook): Should this be GetRootWindowForNewWindows()? + WmShelf* shelf = WmShelf::ForWindow(WmShell::Get()->GetPrimaryRootWindow()); + WmShell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget()); +} + +void HandleLaunchAppN(int n) { + base::RecordAction(UserMetricsAction("Accel_Launch_App")); + WmShelf::LaunchShelfItem(n); +} + +void HandleLaunchLastApp() { + base::RecordAction(UserMetricsAction("Accel_Launch_Last_App")); + WmShelf::LaunchShelfItem(-1); +} + +void HandleMediaNextTrack() { + WmShell::Get()->media_controller()->HandleMediaNextTrack(); +} + +void HandleMediaPlayPause() { + WmShell::Get()->media_controller()->HandleMediaPlayPause(); +} + +void HandleMediaPrevTrack() { + WmShell::Get()->media_controller()->HandleMediaPrevTrack(); +} + +bool CanHandleNewIncognitoWindow() { + return WmShell::Get()->delegate()->IsIncognitoAllowed(); +} + +void HandleNewIncognitoWindow() { + base::RecordAction(UserMetricsAction("Accel_New_Incognito_Window")); + WmShell::Get()->new_window_controller()->NewWindow(true /* is_incognito */); +} + +void HandleNewTab(const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_T) + base::RecordAction(UserMetricsAction("Accel_NewTab_T")); + WmShell::Get()->new_window_controller()->NewTab(); +} + +void HandleNewWindow() { + base::RecordAction(UserMetricsAction("Accel_New_Window")); + WmShell::Get()->new_window_controller()->NewWindow(false /* is_incognito */); +} + +bool CanHandleNextIme(ImeControlDelegate* ime_control_delegate) { + return ime_control_delegate && ime_control_delegate->CanCycleIme(); +} + +bool CanHandleCycleMru(const ui::Accelerator& accelerator) { + // Don't do anything when Alt+Tab is hit while a virtual keyboard is showing. + // Touchscreen users have better window switching options. It would be + // preferable if we could tell whether this event actually came from a virtual + // keyboard, but there's no easy way to do so, thus we block Alt+Tab when the + // virtual keyboard is showing, even if it came from a real keyboard. See + // http://crbug.com/638269 + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + return !(keyboard_controller && keyboard_controller->keyboard_visible()); +} + +void HandleNextIme(ImeControlDelegate* ime_control_delegate) { + base::RecordAction(UserMetricsAction("Accel_Next_Ime")); + ime_control_delegate->HandleNextIme(); +} + +void HandleOpenFeedbackPage() { + base::RecordAction(UserMetricsAction("Accel_Open_Feedback_Page")); + WmShell::Get()->new_window_controller()->OpenFeedbackPage(); +} + +bool CanHandlePreviousIme(ImeControlDelegate* ime_control_delegate) { + return ime_control_delegate && ime_control_delegate->CanCycleIme(); +} + +void HandlePreviousIme(ImeControlDelegate* ime_control_delegate, + const ui::Accelerator& accelerator) { + base::RecordAction(UserMetricsAction("Accel_Previous_Ime")); + if (accelerator.type() == ui::ET_KEY_PRESSED) + ime_control_delegate->HandlePreviousIme(); + // Else: consume the Ctrl+Space ET_KEY_RELEASED event but do not do anything. +} + +void HandleRestoreTab() { + base::RecordAction(UserMetricsAction("Accel_Restore_Tab")); + WmShell::Get()->new_window_controller()->RestoreTab(); +} + +void HandleShowKeyboardOverlay() { + base::RecordAction(UserMetricsAction("Accel_Show_Keyboard_Overlay")); + WmShell::Get()->new_window_controller()->ShowKeyboardOverlay(); +} + +bool CanHandleShowMessageCenterBubble() { + WmWindow* target_root = WmShell::Get()->GetRootWindowForNewWindows(); + StatusAreaWidget* status_area_widget = + WmShelf::ForWindow(target_root)->shelf_widget()->status_area_widget(); + return status_area_widget && + status_area_widget->web_notification_tray()->visible(); +} + +void HandleShowMessageCenterBubble() { + base::RecordAction(UserMetricsAction("Accel_Show_Message_Center_Bubble")); + WmWindow* target_root = WmShell::Get()->GetRootWindowForNewWindows(); + StatusAreaWidget* status_area_widget = + WmShelf::ForWindow(target_root)->shelf_widget()->status_area_widget(); + if (status_area_widget) { + WebNotificationTray* notification_tray = + status_area_widget->web_notification_tray(); + if (notification_tray->visible()) + notification_tray->ShowMessageCenterBubble(); + } +} + +void HandleShowTaskManager() { + base::RecordAction(UserMetricsAction("Accel_Show_Task_Manager")); + WmShell::Get()->new_window_controller()->ShowTaskManager(); +} + +bool CanHandleSwitchIme(ImeControlDelegate* ime_control_delegate, + const ui::Accelerator& accelerator) { + return ime_control_delegate && + ime_control_delegate->CanSwitchIme(accelerator); +} + +void HandleSwitchIme(ImeControlDelegate* ime_control_delegate, + const ui::Accelerator& accelerator) { + base::RecordAction(UserMetricsAction("Accel_Switch_Ime")); + ime_control_delegate->HandleSwitchIme(accelerator); +} + +bool CanHandleToggleAppList(const ui::Accelerator& accelerator, + const ui::Accelerator& previous_accelerator) { + if (accelerator.key_code() == ui::VKEY_LWIN) { + // If something else was pressed between the Search key (LWIN) + // being pressed and released, then ignore the release of the + // Search key. + if (previous_accelerator.type() != ui::ET_KEY_PRESSED || + previous_accelerator.key_code() != ui::VKEY_LWIN) { + return false; + } + + // When spoken feedback is enabled, we should neither toggle the list nor + // consume the key since Search+Shift is one of the shortcuts the a11y + // feature uses. crbug.com/132296 + if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled()) + return false; + } + return true; +} + +void HandleToggleAppList(const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_LWIN) + base::RecordAction(UserMetricsAction("Accel_Search_LWin")); + WmShell::Get()->ToggleAppList(); +} + +void HandleToggleFullscreen(const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_MEDIA_LAUNCH_APP2) + base::RecordAction(UserMetricsAction("Accel_Fullscreen_F4")); + accelerators::ToggleFullscreen(); +} + +void HandleToggleOverview() { + base::RecordAction(base::UserMetricsAction("Accel_Overview_F5")); + WmShell::Get()->window_selector_controller()->ToggleOverview(); +} + +bool CanHandleWindowSnapOrDock() { + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + if (!active_window) + return false; + wm::WindowState* window_state = active_window->GetWindowState(); + // Disable window snapping shortcut key for full screen window due to + // http://crbug.com/135487. + return (window_state && window_state->IsUserPositionable() && + !window_state->IsFullscreen()); +} + +void HandleWindowSnapOrDock(AcceleratorAction action) { + if (action == WINDOW_CYCLE_SNAP_DOCK_LEFT) + base::RecordAction(UserMetricsAction("Accel_Window_Snap_Left")); + else + base::RecordAction(UserMetricsAction("Accel_Window_Snap_Right")); + + const wm::WMEvent event(action == WINDOW_CYCLE_SNAP_DOCK_LEFT + ? wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT + : wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT); + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + DCHECK(active_window); + active_window->GetWindowState()->OnWMEvent(&event); +} + +void HandleWindowMinimize() { + base::RecordAction(base::UserMetricsAction("Accel_Toggle_Minimized_Minus")); + accelerators::ToggleMinimized(); +} + +bool CanHandlePositionCenter() { + // Docked windows do not support centering. + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + return (active_window && !active_window->GetWindowState()->IsDocked()); +} + +void HandlePositionCenter() { + base::RecordAction(UserMetricsAction("Accel_Window_Position_Center")); + wm::CenterWindow(WmShell::Get()->GetActiveWindow()); +} + +void HandleShowImeMenuBubble() { + base::RecordAction(UserMetricsAction("Accel_Show_Ime_Menu_Bubble")); + + StatusAreaWidget* status_area_widget = + WmShelf::ForWindow(WmShell::Get()->GetPrimaryRootWindow()) + ->GetStatusAreaWidget(); + if (status_area_widget) { + ImeMenuTray* ime_menu_tray = status_area_widget->ime_menu_tray(); + if (ime_menu_tray && ime_menu_tray->visible() && + !ime_menu_tray->IsImeMenuBubbleShown()) { + ime_menu_tray->ShowImeMenuBubble(); + } + } +} + +void HandleCrosh() { + base::RecordAction(UserMetricsAction("Accel_Open_Crosh")); + + WmShell::Get()->new_window_controller()->OpenCrosh(); +} + +bool CanHandleDisableCapsLock(const ui::Accelerator& previous_accelerator) { + ui::KeyboardCode previous_key_code = previous_accelerator.key_code(); + if (previous_accelerator.type() == ui::ET_KEY_RELEASED || + (previous_key_code != ui::VKEY_LSHIFT && + previous_key_code != ui::VKEY_SHIFT && + previous_key_code != ui::VKEY_RSHIFT)) { + // If something else was pressed between the Shift key being pressed + // and released, then ignore the release of the Shift key. + return false; + } + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + chromeos::input_method::ImeKeyboard* keyboard = + ime ? ime->GetImeKeyboard() : NULL; + return (keyboard && keyboard->CapsLockIsEnabled()); +} + +void HandleDisableCapsLock() { + base::RecordAction(UserMetricsAction("Accel_Disable_Caps_Lock")); + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + ime->GetImeKeyboard()->SetCapsLockEnabled(false); +} + +void HandleFileManager() { + base::RecordAction(UserMetricsAction("Accel_Open_File_Manager")); + + WmShell::Get()->new_window_controller()->OpenFileManager(); +} + +void HandleGetHelp() { + WmShell::Get()->new_window_controller()->OpenGetHelp(); +} + +bool CanHandleLock() { + return WmShell::Get()->GetSessionStateDelegate()->CanLockScreen(); +} + +void HandleLock() { + base::RecordAction(UserMetricsAction("Accel_LockScreen_L")); + WmShell::Get()->GetSessionStateDelegate()->LockScreen(); +} + +void HandleShowStylusTools() { + base::RecordAction(UserMetricsAction("Accel_Show_Stylus_Tools")); + + RootWindowController* root_window_controller = + WmShell::Get()->GetRootWindowForNewWindows()->GetRootWindowController(); + PaletteTray* palette_tray = + root_window_controller->GetShelf()->GetStatusAreaWidget()->palette_tray(); + palette_tray->ShowPalette(); +} + +bool CanHandleShowStylusTools() { + return WmShell::Get()->palette_delegate() && + WmShell::Get()->palette_delegate()->ShouldShowPalette(); +} + +void HandleSuspend() { + base::RecordAction(UserMetricsAction("Accel_Suspend")); + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestSuspend(); +} + +bool CanHandleCycleUser() { + return WmShell::Get()->delegate()->IsMultiProfilesEnabled() && + WmShell::Get()->GetSessionStateDelegate()->NumberOfLoggedInUsers() > 1; +} + +void HandleCycleUser(CycleUserDirection direction) { + MultiProfileUMA::RecordSwitchActiveUser( + MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR); + switch (direction) { + case CycleUserDirection::NEXT: + base::RecordAction(UserMetricsAction("Accel_Switch_To_Next_User")); + break; + case CycleUserDirection::PREVIOUS: + base::RecordAction(UserMetricsAction("Accel_Switch_To_Previous_User")); + break; + } + WmShell::Get()->GetSessionStateDelegate()->CycleActiveUser(direction); +} + +bool CanHandleToggleCapsLock(const ui::Accelerator& accelerator, + const ui::Accelerator& previous_accelerator) { + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + + // This shortcust is set to be trigger on release. Either the current + // accelerator is a Search release or Alt release. + if (accelerator.key_code() == ui::VKEY_LWIN && + accelerator.type() == ui::ET_KEY_RELEASED) { + // The previous must be either an Alt press or Search press: + // 1. Press Alt, Press Search, Release Search, Release Alt. + // 2. Press Search, Press Alt, Release Search, Release Alt. + if (previous_accelerator.type() == ui::ET_KEY_PRESSED && + (previous_accelerator.key_code() == ui::VKEY_LWIN || + previous_accelerator.key_code() == ui::VKEY_MENU)) { + return ime && ime->GetImeKeyboard(); + } + } + + // Alt release. + if (accelerator.key_code() == ui::VKEY_MENU && + accelerator.type() == ui::ET_KEY_RELEASED) { + // The previous must be either an Alt press or Search press: + // 3. Press Alt, Press Search, Release Alt, Release Search. + // 4. Press Search, Press Alt, Release Alt, Release Search. + if (previous_accelerator.type() == ui::ET_KEY_PRESSED && + (previous_accelerator.key_code() == ui::VKEY_LWIN || + previous_accelerator.key_code() == ui::VKEY_MENU)) { + return ime && ime->GetImeKeyboard(); + } + } + + return false; +} + +void HandleToggleCapsLock() { + base::RecordAction(UserMetricsAction("Accel_Toggle_Caps_Lock")); + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + chromeos::input_method::ImeKeyboard* keyboard = ime->GetImeKeyboard(); + keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled()); +} + +void HandleToggleHighContrast() { + base::RecordAction(UserMetricsAction("Accel_Toggle_High_Contrast")); + + // Show a notification so the user knows that this accelerator toggled + // high contrast mode, and that they can press it again to toggle back. + // The message center automatically only shows this once per session. + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kHighContrastToggleAccelNotificationId, base::string16() /* title */, + l10n_util::GetStringUTF16(IDS_HIGH_CONTRAST_ACCEL_MSG), + gfx::Image(CreateVectorIcon(kSystemMenuAccessibilityIcon, SK_ColorBLACK)), + base::string16() /* display source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierAccessibility), + message_center::RichNotificationData(), nullptr)); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); + + WmShell::Get()->accessibility_delegate()->ToggleHighContrast(); +} + +void HandleToggleSpokenFeedback() { + base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback")); + + WmShell::Get()->accessibility_delegate()->ToggleSpokenFeedback( + A11Y_NOTIFICATION_SHOW); +} + +void HandleVolumeDown(mojom::VolumeController* volume_controller, + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_VOLUME_DOWN) + base::RecordAction(UserMetricsAction("Accel_VolumeDown_F9")); + + if (volume_controller) + volume_controller->VolumeDown(); +} + +void HandleVolumeMute(mojom::VolumeController* volume_controller, + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_VOLUME_MUTE) + base::RecordAction(UserMetricsAction("Accel_VolumeMute_F8")); + + if (volume_controller) + volume_controller->VolumeMute(); +} + +void HandleVolumeUp(mojom::VolumeController* volume_controller, + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_VOLUME_UP) + base::RecordAction(UserMetricsAction("Accel_VolumeUp_F10")); + + if (volume_controller) + volume_controller->VolumeUp(); +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// AcceleratorController, public: + +AcceleratorController::AcceleratorController( + AcceleratorControllerDelegate* delegate, + ui::AcceleratorManagerDelegate* manager_delegate) + : delegate_(delegate), + accelerator_manager_(new ui::AcceleratorManager(manager_delegate)), + accelerator_history_(new ui::AcceleratorHistory) { + Init(); +} + +AcceleratorController::~AcceleratorController() {} + +void AcceleratorController::Register( + const std::vector<ui::Accelerator>& accelerators, + ui::AcceleratorTarget* target) { + accelerator_manager_->Register( + accelerators, ui::AcceleratorManager::kNormalPriority, target); +} + +void AcceleratorController::Unregister(const ui::Accelerator& accelerator, + ui::AcceleratorTarget* target) { + accelerator_manager_->Unregister(accelerator, target); +} + +void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) { + accelerator_manager_->UnregisterAll(target); +} + +bool AcceleratorController::Process(const ui::Accelerator& accelerator) { + return accelerator_manager_->Process(accelerator); +} + +bool AcceleratorController::IsRegistered( + const ui::Accelerator& accelerator) const { + return accelerator_manager_->IsRegistered(accelerator); +} + +bool AcceleratorController::IsPreferred( + const ui::Accelerator& accelerator) const { + std::map<ui::Accelerator, AcceleratorAction>::const_iterator iter = + accelerators_.find(accelerator); + if (iter == accelerators_.end()) + return false; // not an accelerator. + + return preferred_actions_.find(iter->second) != preferred_actions_.end(); +} + +bool AcceleratorController::IsReserved( + const ui::Accelerator& accelerator) const { + std::map<ui::Accelerator, AcceleratorAction>::const_iterator iter = + accelerators_.find(accelerator); + if (iter == accelerators_.end()) + return false; // not an accelerator. + + return reserved_actions_.find(iter->second) != reserved_actions_.end(); +} + +bool AcceleratorController::IsDeprecated( + const ui::Accelerator& accelerator) const { + return deprecated_accelerators_.count(accelerator) != 0; +} + +bool AcceleratorController::PerformActionIfEnabled(AcceleratorAction action) { + if (CanPerformAction(action, ui::Accelerator())) { + PerformAction(action, ui::Accelerator()); + return true; + } + return false; +} + +AcceleratorController::AcceleratorProcessingRestriction +AcceleratorController::GetCurrentAcceleratorRestriction() { + return GetAcceleratorProcessingRestriction(-1); +} + +void AcceleratorController::SetImeControlDelegate( + std::unique_ptr<ImeControlDelegate> ime_control_delegate) { + ime_control_delegate_ = std::move(ime_control_delegate); +} + +bool AcceleratorController::ShouldCloseMenuAndRepostAccelerator( + const ui::Accelerator& accelerator) const { + auto itr = accelerators_.find(accelerator); + if (itr == accelerators_.end()) + return false; // Menu shouldn't be closed for an invalid accelerator. + + AcceleratorAction action = itr->second; + return actions_keeping_menu_open_.count(action) == 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// AcceleratorController, ui::AcceleratorTarget implementation: + +bool AcceleratorController::AcceleratorPressed( + const ui::Accelerator& accelerator) { + std::map<ui::Accelerator, AcceleratorAction>::const_iterator it = + accelerators_.find(accelerator); + DCHECK(it != accelerators_.end()); + AcceleratorAction action = it->second; + if (!CanPerformAction(action, accelerator)) + return false; + + // Handling the deprecated accelerators (if any) only if action can be + // performed. + if (MaybeDeprecatedAcceleratorPressed(action, accelerator) == + AcceleratorProcessingStatus::STOP) { + return false; + } + + PerformAction(action, accelerator); + return ShouldActionConsumeKeyEvent(action); +} + +bool AcceleratorController::CanHandleAccelerators() const { + return true; +} + +void AcceleratorController::BindRequest( + mojom::AcceleratorControllerRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void AcceleratorController::SetVolumeController( + mojom::VolumeControllerPtr controller) { + volume_controller_ = std::move(controller); +} + +/////////////////////////////////////////////////////////////////////////////// +// AcceleratorController, private: + +void AcceleratorController::Init() { + for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { + actions_allowed_at_login_screen_.insert( + kActionsAllowedAtLoginOrLockScreen[i]); + actions_allowed_at_lock_screen_.insert( + kActionsAllowedAtLoginOrLockScreen[i]); + } + for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) + actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]); + for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) + actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]); + for (size_t i = 0; i < kPreferredActionsLength; ++i) + preferred_actions_.insert(kPreferredActions[i]); + for (size_t i = 0; i < kReservedActionsLength; ++i) + reserved_actions_.insert(kReservedActions[i]); + for (size_t i = 0; i < kRepeatableActionsLength; ++i) + repeatable_actions_.insert(kRepeatableActions[i]); + for (size_t i = 0; i < kActionsAllowedInAppModeOrPinnedModeLength; ++i) { + actions_allowed_in_app_mode_.insert( + kActionsAllowedInAppModeOrPinnedMode[i]); + actions_allowed_in_pinned_mode_.insert( + kActionsAllowedInAppModeOrPinnedMode[i]); + } + for (size_t i = 0; i < kActionsAllowedInPinnedModeLength; ++i) + actions_allowed_in_pinned_mode_.insert(kActionsAllowedInPinnedMode[i]); + for (size_t i = 0; i < kActionsNeedingWindowLength; ++i) + actions_needing_window_.insert(kActionsNeedingWindow[i]); + for (size_t i = 0; i < kActionsKeepingMenuOpenLength; ++i) + actions_keeping_menu_open_.insert(kActionsKeepingMenuOpen[i]); + + RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength); + + RegisterDeprecatedAccelerators(); + + if (debug::DebugAcceleratorsEnabled()) { + RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength); + // All debug accelerators are reserved. + for (size_t i = 0; i < kDebugAcceleratorDataLength; ++i) + reserved_actions_.insert(kDebugAcceleratorData[i].action); + } + + if (debug::DeveloperAcceleratorsEnabled()) { + RegisterAccelerators(kDeveloperAcceleratorData, + kDeveloperAcceleratorDataLength); + // Developer accelerators are also reserved. + for (size_t i = 0; i < kDeveloperAcceleratorDataLength; ++i) + reserved_actions_.insert(kDeveloperAcceleratorData[i].action); + } +} + +void AcceleratorController::RegisterAccelerators( + const AcceleratorData accelerators[], + size_t accelerators_length) { + std::vector<ui::Accelerator> ui_accelerators; + for (size_t i = 0; i < accelerators_length; ++i) { + ui::Accelerator accelerator = + CreateAccelerator(accelerators[i].keycode, accelerators[i].modifiers, + accelerators[i].trigger_on_press); + ui_accelerators.push_back(accelerator); + accelerators_.insert(std::make_pair(accelerator, accelerators[i].action)); + } + Register(ui_accelerators, this); +} + +void AcceleratorController::RegisterDeprecatedAccelerators() { + for (size_t i = 0; i < kDeprecatedAcceleratorsDataLength; ++i) { + const DeprecatedAcceleratorData* data = &kDeprecatedAcceleratorsData[i]; + actions_with_deprecations_[data->action] = data; + } + + std::vector<ui::Accelerator> ui_accelerators; + for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) { + const AcceleratorData& accelerator_data = kDeprecatedAccelerators[i]; + const ui::Accelerator deprecated_accelerator = + CreateAccelerator(accelerator_data.keycode, accelerator_data.modifiers, + accelerator_data.trigger_on_press); + + ui_accelerators.push_back(deprecated_accelerator); + accelerators_[deprecated_accelerator] = accelerator_data.action; + deprecated_accelerators_.insert(deprecated_accelerator); + } + Register(ui_accelerators, this); +} + +bool AcceleratorController::CanPerformAction( + AcceleratorAction action, + const ui::Accelerator& accelerator) { + if (accelerator.IsRepeat() && !repeatable_actions_.count(action)) + return false; + + AcceleratorProcessingRestriction restriction = + GetAcceleratorProcessingRestriction(action); + if (restriction != RESTRICTION_NONE) + return restriction == RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; + + const ui::Accelerator& previous_accelerator = + accelerator_history_->previous_accelerator(); + + // True should be returned if running |action| does something. Otherwise, + // false should be returned to give the web contents a chance at handling the + // accelerator. + switch (action) { + case CYCLE_BACKWARD_MRU: + case CYCLE_FORWARD_MRU: + return CanHandleCycleMru(accelerator); + case DEBUG_PRINT_LAYER_HIERARCHY: + case DEBUG_PRINT_VIEW_HIERARCHY: + case DEBUG_PRINT_WINDOW_HIERARCHY: + case DEBUG_SHOW_TOAST: + case DEBUG_TOGGLE_TOUCH_PAD: + case DEBUG_TOGGLE_TOUCH_SCREEN: + case DEBUG_TOGGLE_TOUCH_VIEW: + case DEBUG_TOGGLE_WALLPAPER_MODE: + case DEBUG_TRIGGER_CRASH: + return debug::DebugAcceleratorsEnabled(); + case DISABLE_CAPS_LOCK: + return CanHandleDisableCapsLock(previous_accelerator); + case LOCK_SCREEN: + return CanHandleLock(); + case NEW_INCOGNITO_WINDOW: + return CanHandleNewIncognitoWindow(); + case NEXT_IME: + return CanHandleNextIme(ime_control_delegate_.get()); + case PREVIOUS_IME: + return CanHandlePreviousIme(ime_control_delegate_.get()); + case SHOW_MESSAGE_CENTER_BUBBLE: + return CanHandleShowMessageCenterBubble(); + case SHOW_STYLUS_TOOLS: + return CanHandleShowStylusTools(); + case SWITCH_IME: + return CanHandleSwitchIme(ime_control_delegate_.get(), accelerator); + case SWITCH_TO_PREVIOUS_USER: + case SWITCH_TO_NEXT_USER: + return CanHandleCycleUser(); + case TOGGLE_APP_LIST: + return CanHandleToggleAppList(accelerator, previous_accelerator); + case TOGGLE_CAPS_LOCK: + return CanHandleToggleCapsLock(accelerator, previous_accelerator); + case WINDOW_CYCLE_SNAP_DOCK_LEFT: + case WINDOW_CYCLE_SNAP_DOCK_RIGHT: + return CanHandleWindowSnapOrDock(); + case WINDOW_POSITION_CENTER: + return CanHandlePositionCenter(); + + // The following are always enabled. + case BRIGHTNESS_DOWN: + case BRIGHTNESS_UP: + case EXIT: + case FOCUS_NEXT_PANE: + case FOCUS_PREVIOUS_PANE: + case FOCUS_SHELF: + case KEYBOARD_BRIGHTNESS_DOWN: + case KEYBOARD_BRIGHTNESS_UP: + case LAUNCH_APP_0: + case LAUNCH_APP_1: + case LAUNCH_APP_2: + case LAUNCH_APP_3: + case LAUNCH_APP_4: + case LAUNCH_APP_5: + case LAUNCH_APP_6: + case LAUNCH_APP_7: + case LAUNCH_LAST_APP: + case MEDIA_NEXT_TRACK: + case MEDIA_PLAY_PAUSE: + case MEDIA_PREV_TRACK: + case NEW_TAB: + case NEW_WINDOW: + case OPEN_CROSH: + case OPEN_FEEDBACK_PAGE: + case OPEN_FILE_MANAGER: + case OPEN_GET_HELP: + case PRINT_UI_HIERARCHIES: + case RESTORE_TAB: + case SHOW_IME_MENU_BUBBLE: + case SHOW_KEYBOARD_OVERLAY: + case SHOW_TASK_MANAGER: + case SUSPEND: + case TOGGLE_FULLSCREEN: + case TOGGLE_HIGH_CONTRAST: + case TOGGLE_MAXIMIZED: + case TOGGLE_OVERVIEW: + case TOGGLE_SPOKEN_FEEDBACK: + case TOGGLE_WIFI: + case VOLUME_DOWN: + case VOLUME_MUTE: + case VOLUME_UP: + case WINDOW_MINIMIZE: + return true; + + default: + // Default switch is temporary until mash transition complete. Needed as + // some actions don't yet work with mash. + break; + } + return delegate_ && delegate_->HandlesAction(action) && + delegate_->CanPerformAction(action, accelerator, previous_accelerator); +} + +void AcceleratorController::PerformAction(AcceleratorAction action, + const ui::Accelerator& accelerator) { + AcceleratorProcessingRestriction restriction = + GetAcceleratorProcessingRestriction(action); + if (restriction != RESTRICTION_NONE) + return; + + // If your accelerator invokes more than one line of code, please either + // implement it in your module's controller code or pull it into a HandleFoo() + // function above. + switch (action) { + case BRIGHTNESS_DOWN: { + BrightnessControlDelegate* delegate = + WmShell::Get()->brightness_control_delegate(); + if (delegate) + delegate->HandleBrightnessDown(accelerator); + break; + } + case BRIGHTNESS_UP: { + BrightnessControlDelegate* delegate = + WmShell::Get()->brightness_control_delegate(); + if (delegate) + delegate->HandleBrightnessUp(accelerator); + break; + } + case CYCLE_BACKWARD_MRU: + HandleCycleBackwardMRU(accelerator); + break; + case CYCLE_FORWARD_MRU: + HandleCycleForwardMRU(accelerator); + break; + case DEBUG_PRINT_LAYER_HIERARCHY: + case DEBUG_PRINT_VIEW_HIERARCHY: + case DEBUG_PRINT_WINDOW_HIERARCHY: + case DEBUG_SHOW_TOAST: + case DEBUG_TOGGLE_TOUCH_PAD: + case DEBUG_TOGGLE_TOUCH_SCREEN: + case DEBUG_TOGGLE_TOUCH_VIEW: + case DEBUG_TOGGLE_WALLPAPER_MODE: + case DEBUG_TRIGGER_CRASH: + debug::PerformDebugActionIfEnabled(action); + break; + case DISABLE_CAPS_LOCK: + HandleDisableCapsLock(); + break; + case EXIT: + // UMA metrics are recorded in the handler. + exit_warning_handler_.HandleAccelerator(); + break; + case FOCUS_NEXT_PANE: + HandleRotatePaneFocus(FocusCycler::FORWARD); + break; + case FOCUS_PREVIOUS_PANE: + HandleRotatePaneFocus(FocusCycler::BACKWARD); + break; + case FOCUS_SHELF: + HandleFocusShelf(); + break; + case KEYBOARD_BRIGHTNESS_DOWN: { + KeyboardBrightnessControlDelegate* delegate = + WmShell::Get()->keyboard_brightness_control_delegate(); + if (delegate) + delegate->HandleKeyboardBrightnessDown(accelerator); + break; + } + case KEYBOARD_BRIGHTNESS_UP: { + KeyboardBrightnessControlDelegate* delegate = + WmShell::Get()->keyboard_brightness_control_delegate(); + if (delegate) + delegate->HandleKeyboardBrightnessUp(accelerator); + break; + } + case LAUNCH_APP_0: + HandleLaunchAppN(0); + break; + case LAUNCH_APP_1: + HandleLaunchAppN(1); + break; + case LAUNCH_APP_2: + HandleLaunchAppN(2); + break; + case LAUNCH_APP_3: + HandleLaunchAppN(3); + break; + case LAUNCH_APP_4: + HandleLaunchAppN(4); + break; + case LAUNCH_APP_5: + HandleLaunchAppN(5); + break; + case LAUNCH_APP_6: + HandleLaunchAppN(6); + break; + case LAUNCH_APP_7: + HandleLaunchAppN(7); + break; + case LAUNCH_LAST_APP: + HandleLaunchLastApp(); + break; + case LOCK_SCREEN: + HandleLock(); + break; + case MEDIA_NEXT_TRACK: + HandleMediaNextTrack(); + break; + case MEDIA_PLAY_PAUSE: + HandleMediaPlayPause(); + break; + case MEDIA_PREV_TRACK: + HandleMediaPrevTrack(); + break; + case NEW_INCOGNITO_WINDOW: + HandleNewIncognitoWindow(); + break; + case NEW_TAB: + HandleNewTab(accelerator); + break; + case NEW_WINDOW: + HandleNewWindow(); + break; + case NEXT_IME: + HandleNextIme(ime_control_delegate_.get()); + break; + case OPEN_CROSH: + HandleCrosh(); + break; + case OPEN_FEEDBACK_PAGE: + HandleOpenFeedbackPage(); + break; + case OPEN_FILE_MANAGER: + HandleFileManager(); + break; + case OPEN_GET_HELP: + HandleGetHelp(); + break; + case PREVIOUS_IME: + HandlePreviousIme(ime_control_delegate_.get(), accelerator); + break; + case PRINT_UI_HIERARCHIES: + debug::PrintUIHierarchies(); + break; + case RESTORE_TAB: + HandleRestoreTab(); + break; + case SHOW_IME_MENU_BUBBLE: + HandleShowImeMenuBubble(); + break; + case SHOW_KEYBOARD_OVERLAY: + HandleShowKeyboardOverlay(); + break; + case SHOW_MESSAGE_CENTER_BUBBLE: + HandleShowMessageCenterBubble(); + break; + case SHOW_STYLUS_TOOLS: + HandleShowStylusTools(); + break; + case SHOW_TASK_MANAGER: + HandleShowTaskManager(); + break; + case SUSPEND: + HandleSuspend(); + break; + case SWITCH_IME: + HandleSwitchIme(ime_control_delegate_.get(), accelerator); + break; + case SWITCH_TO_NEXT_USER: + HandleCycleUser(CycleUserDirection::NEXT); + break; + case SWITCH_TO_PREVIOUS_USER: + HandleCycleUser(CycleUserDirection::PREVIOUS); + break; + case TOGGLE_APP_LIST: + HandleToggleAppList(accelerator); + break; + case TOGGLE_CAPS_LOCK: + HandleToggleCapsLock(); + break; + case TOGGLE_FULLSCREEN: + HandleToggleFullscreen(accelerator); + break; + case TOGGLE_HIGH_CONTRAST: + HandleToggleHighContrast(); + break; + case TOGGLE_MAXIMIZED: + accelerators::ToggleMaximized(); + break; + case TOGGLE_OVERVIEW: + HandleToggleOverview(); + break; + case TOGGLE_SPOKEN_FEEDBACK: + HandleToggleSpokenFeedback(); + break; + case TOGGLE_WIFI: + WmShell::Get()->system_tray_notifier()->NotifyRequestToggleWifi(); + break; + case VOLUME_DOWN: + HandleVolumeDown(volume_controller_.get(), accelerator); + break; + case VOLUME_MUTE: + HandleVolumeMute(volume_controller_.get(), accelerator); + break; + case VOLUME_UP: + HandleVolumeUp(volume_controller_.get(), accelerator); + break; + case WINDOW_CYCLE_SNAP_DOCK_LEFT: + case WINDOW_CYCLE_SNAP_DOCK_RIGHT: + HandleWindowSnapOrDock(action); + break; + case WINDOW_MINIMIZE: + HandleWindowMinimize(); + break; + case WINDOW_POSITION_CENTER: + HandlePositionCenter(); + break; + default: + // Temporary until mash transition complete. Needed as some actions + // don't yet work with mash. + DCHECK(delegate_ && delegate_->HandlesAction(action)); + delegate_->PerformAction(action, accelerator); + break; + } +} + +bool AcceleratorController::ShouldActionConsumeKeyEvent( + AcceleratorAction action) { + // Adding new exceptions is *STRONGLY* discouraged. + return true; +} + +AcceleratorController::AcceleratorProcessingRestriction +AcceleratorController::GetAcceleratorProcessingRestriction(int action) { + WmShell* wm_shell = WmShell::Get(); + if (wm_shell->IsPinned() && + actions_allowed_in_pinned_mode_.find(action) == + actions_allowed_in_pinned_mode_.end()) { + return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; + } + // TODO(xiyuan): Replace with SessionController. http://crbug.com/648964 + if (!wm_shell->GetSessionStateDelegate()->IsActiveUserSessionStarted() && + actions_allowed_at_login_screen_.find(action) == + actions_allowed_at_login_screen_.end()) { + return RESTRICTION_PREVENT_PROCESSING; + } + if (wm_shell->GetSessionStateDelegate()->IsScreenLocked() && + actions_allowed_at_lock_screen_.find(action) == + actions_allowed_at_lock_screen_.end()) { + return RESTRICTION_PREVENT_PROCESSING; + } + if (wm_shell->delegate()->IsRunningInForcedAppMode() && + actions_allowed_in_app_mode_.find(action) == + actions_allowed_in_app_mode_.end()) { + return RESTRICTION_PREVENT_PROCESSING; + } + if (WmShell::Get()->IsSystemModalWindowOpen() && + actions_allowed_at_modal_window_.find(action) == + actions_allowed_at_modal_window_.end()) { + // Note we prevent the shortcut from propagating so it will not + // be passed to the modal window. This is important for things like + // Alt+Tab that would cause an undesired effect in the modal window by + // cycling through its window elements. + return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; + } + if (wm_shell->mru_window_tracker()->BuildMruWindowList().empty() && + actions_needing_window_.find(action) != actions_needing_window_.end()) { + wm_shell->accessibility_delegate()->TriggerAccessibilityAlert( + A11Y_ALERT_WINDOW_NEEDED); + return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION; + } + return RESTRICTION_NONE; +} + +AcceleratorController::AcceleratorProcessingStatus +AcceleratorController::MaybeDeprecatedAcceleratorPressed( + AcceleratorAction action, + const ui::Accelerator& accelerator) const { + auto itr = actions_with_deprecations_.find(action); + if (itr == actions_with_deprecations_.end()) { + // The action is not associated with any deprecated accelerators, and hence + // should be performed normally. + return AcceleratorProcessingStatus::PROCEED; + } + + // This action is associated with new and deprecated accelerators, find which + // one is |accelerator|. + const DeprecatedAcceleratorData* data = itr->second; + if (!deprecated_accelerators_.count(accelerator)) { + // This is a new accelerator replacing the old deprecated one. + // Record UMA stats and proceed normally to perform it. + RecordUmaHistogram(data->uma_histogram_name, NEW_USED); + return AcceleratorProcessingStatus::PROCEED; + } + + // This accelerator has been deprecated and should be treated according + // to its |DeprecatedAcceleratorData|. + + // Record UMA stats. + RecordUmaHistogram(data->uma_histogram_name, DEPRECATED_USED); + + if (delegate_) { + // We always display the notification as long as this |data| entry exists. + delegate_->ShowDeprecatedAcceleratorNotification( + data->uma_histogram_name, data->notification_message_id, + data->old_shortcut_id, data->new_shortcut_id); + } + + if (!data->deprecated_enabled) + return AcceleratorProcessingStatus::STOP; + + return AcceleratorProcessingStatus::PROCEED; +} + +} // namespace ash
diff --git a/ash/common/accelerators/accelerator_controller.h b/ash/common/accelerators/accelerator_controller.h new file mode 100644 index 0000000..0a39c63 --- /dev/null +++ b/ash/common/accelerators/accelerator_controller.h
@@ -0,0 +1,234 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_ACCELERATOR_CONTROLLER_H_ +#define ASH_COMMON_ACCELERATORS_ACCELERATOR_CONTROLLER_H_ + +#include <stddef.h> + +#include <map> +#include <memory> +#include <set> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/accelerators/accelerator_table.h" +#include "ash/common/accelerators/exit_warning_handler.h" +#include "ash/public/interfaces/accelerator_controller.mojom.h" +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/accelerators/accelerator_history.h" + +namespace ui { +class AcceleratorManager; +class AcceleratorManagerDelegate; +} + +namespace ash { + +struct AcceleratorData; +class AcceleratorControllerDelegate; +class ExitWarningHandler; +class ImeControlDelegate; + +// AcceleratorController provides functions for registering or unregistering +// global keyboard accelerators, which are handled earlier than any windows. It +// also implements several handlers as an accelerator target. +class ASH_EXPORT AcceleratorController + : public ui::AcceleratorTarget, + NON_EXPORTED_BASE(public mojom::AcceleratorController) { + public: + AcceleratorController(AcceleratorControllerDelegate* delegate, + ui::AcceleratorManagerDelegate* manager_delegate); + ~AcceleratorController() override; + + // A list of possible ways in which an accelerator should be restricted before + // processing. Any target registered with this controller should respect + // restrictions by calling |GetCurrentAcceleratorRestriction| during + // processing. + enum AcceleratorProcessingRestriction { + // Process the accelerator normally. + RESTRICTION_NONE, + + // Don't process the accelerator. + RESTRICTION_PREVENT_PROCESSING, + + // Don't process the accelerator and prevent propagation to other targets. + RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION + }; + + // Registers global keyboard accelerators for the specified target. If + // multiple targets are registered for any given accelerator, a target + // registered later has higher priority. + void Register(const std::vector<ui::Accelerator>& accelerators, + ui::AcceleratorTarget* target); + + // Unregisters the specified keyboard accelerator for the specified target. + void Unregister(const ui::Accelerator& accelerator, + ui::AcceleratorTarget* target); + + // Unregisters all keyboard accelerators for the specified target. + void UnregisterAll(ui::AcceleratorTarget* target); + + // Activates the target associated with the specified accelerator. + // First, AcceleratorPressed handler of the most recently registered target + // is called, and if that handler processes the event (i.e. returns true), + // this method immediately returns. If not, we do the same thing on the next + // target, and so on. + // Returns true if an accelerator was activated. + bool Process(const ui::Accelerator& accelerator); + + // Returns true if the |accelerator| is registered. + bool IsRegistered(const ui::Accelerator& accelerator) const; + + // Returns true if the |accelerator| is preferred. A preferred accelerator + // is handled before being passed to an window/web contents, unless + // the window is in fullscreen state. + bool IsPreferred(const ui::Accelerator& accelerator) const; + + // Returns true if the |accelerator| is reserved. A reserved accelerator + // is always handled and will never be passed to an window/web contents. + bool IsReserved(const ui::Accelerator& accelerator) const; + + // Returns true if the |accelerator| is deprecated. Deprecated accelerators + // can be consumed by web contents if needed. + bool IsDeprecated(const ui::Accelerator& accelerator) const; + + // Performs the specified action if it is enabled. Returns whether the action + // was performed successfully. + bool PerformActionIfEnabled(AcceleratorAction action); + + // Returns the restriction for the current context. + AcceleratorProcessingRestriction GetCurrentAcceleratorRestriction(); + + void SetImeControlDelegate( + std::unique_ptr<ImeControlDelegate> ime_control_delegate); + + // Provides access to the ExitWarningHandler for testing. + ExitWarningHandler* GetExitWarningHandlerForTest() { + return &exit_warning_handler_; + } + + // Returns true if the menu should close in order to perform the accelerator. + bool ShouldCloseMenuAndRepostAccelerator( + const ui::Accelerator& accelerator) const; + + ui::AcceleratorHistory* accelerator_history() { + return accelerator_history_.get(); + } + + // Overridden from ui::AcceleratorTarget: + bool AcceleratorPressed(const ui::Accelerator& accelerator) override; + bool CanHandleAccelerators() const override; + + // Binds the mojom::AcceleratorController interface to this object. + void BindRequest(mojom::AcceleratorControllerRequest request); + + // mojom::AcceleratorController: + void SetVolumeController(mojom::VolumeControllerPtr controller) override; + + private: + FRIEND_TEST_ALL_PREFIXES(AcceleratorControllerTest, GlobalAccelerators); + FRIEND_TEST_ALL_PREFIXES(AcceleratorControllerTest, + DontRepeatToggleFullscreen); + FRIEND_TEST_ALL_PREFIXES(DeprecatedAcceleratorTester, + TestDeprecatedAcceleratorsBehavior); + + // Initializes the accelerators this class handles as a target. + void Init(); + + // Registers the specified accelerators. + void RegisterAccelerators(const AcceleratorData accelerators[], + size_t accelerators_length); + + // Registers the deprecated accelerators and their replacing new ones. + void RegisterDeprecatedAccelerators(); + + // Returns whether |action| can be performed. The |accelerator| may provide + // additional data the action needs. + bool CanPerformAction(AcceleratorAction action, + const ui::Accelerator& accelerator); + + // Performs the specified action. The |accelerator| may provide additional + // data the action needs. + void PerformAction(AcceleratorAction action, + const ui::Accelerator& accelerator); + + // Returns whether performing |action| should consume the key event. + bool ShouldActionConsumeKeyEvent(AcceleratorAction action); + + // Get the accelerator restriction for the given action. Supply an |action| + // of -1 to get restrictions that apply for the current context. + AcceleratorProcessingRestriction GetAcceleratorProcessingRestriction( + int action); + + // If |accelerator| is a deprecated accelerator, it performs the appropriate + // deprecated accelerator pre-handling. + // Returns PROCEED if the accelerator's action should be performed (i.e. if + // |accelerator| is not a deprecated accelerator, or it's an enabled + // deprecated accelerator), and STOP otherwise (if the accelerator is a + // disabled deprecated accelerator). + enum class AcceleratorProcessingStatus { PROCEED, STOP }; + AcceleratorProcessingStatus MaybeDeprecatedAcceleratorPressed( + AcceleratorAction action, + const ui::Accelerator& accelerator) const; + + AcceleratorControllerDelegate* delegate_; + + std::unique_ptr<ui::AcceleratorManager> accelerator_manager_; + + // A tracker for the current and previous accelerators. + std::unique_ptr<ui::AcceleratorHistory> accelerator_history_; + + std::unique_ptr<ImeControlDelegate> ime_control_delegate_; + + // Handles the exit accelerator which requires a double press to exit and + // shows a popup with an explanation. + ExitWarningHandler exit_warning_handler_; + + // A map from accelerators to the AcceleratorAction values, which are used in + // the implementation. + std::map<ui::Accelerator, AcceleratorAction> accelerators_; + + std::map<AcceleratorAction, const DeprecatedAcceleratorData*> + actions_with_deprecations_; + std::set<ui::Accelerator> deprecated_accelerators_; + + // Bindings for the mojom::AcceleratorController interface. + mojo::BindingSet<mojom::AcceleratorController> bindings_; + + // Volume controller interface in chrome browser. May be null in tests. Exists + // because chrome owns the CrasAudioHandler dbus communication. + mojom::VolumeControllerPtr volume_controller_; + + // Actions allowed when the user is not signed in. + std::set<int> actions_allowed_at_login_screen_; + // Actions allowed when the screen is locked. + std::set<int> actions_allowed_at_lock_screen_; + // Actions allowed when a modal window is up. + std::set<int> actions_allowed_at_modal_window_; + // Preferred actions. See accelerator_table.h for details. + std::set<int> preferred_actions_; + // Reserved actions. See accelerator_table.h for details. + std::set<int> reserved_actions_; + // Actions which will be repeated while holding the accelerator key. + std::set<int> repeatable_actions_; + // Actions allowed in app mode. + std::set<int> actions_allowed_in_app_mode_; + // Actions allowed in pinned mode. + std::set<int> actions_allowed_in_pinned_mode_; + // Actions disallowed if there are no windows. + std::set<int> actions_needing_window_; + // Actions that can be performed without closing the menu (if one is present). + std::set<int> actions_keeping_menu_open_; + + DISALLOW_COPY_AND_ASSIGN(AcceleratorController); +}; + +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_ACCELERATOR_CONTROLLER_H_
diff --git a/ash/common/accelerators/accelerator_controller_delegate.h b/ash/common/accelerators/accelerator_controller_delegate.h new file mode 100644 index 0000000..291d9fd5 --- /dev/null +++ b/ash/common/accelerators/accelerator_controller_delegate.h
@@ -0,0 +1,50 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_H_ +#define ASH_COMMON_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "ash/common/accelerators/accelerator_table.h" + +namespace ui { +class Accelerator; +} + +namespace ash { + +// Used by AcceleratorController to handle environment specific commands. This +// file is temporary while ash supports both mus and aura. +class ASH_EXPORT AcceleratorControllerDelegate { + public: + // Returns true if the delegate is responsible for handling |action|. This + // should not return whether the action may be enabled, only if this delegate + // handles the action. + virtual bool HandlesAction(AcceleratorAction action) = 0; + + // Returns true if the delegate can perform the action at this time. Only + // invoked if HandlesAction() returns true. + virtual bool CanPerformAction( + AcceleratorAction action, + const ui::Accelerator& accelerator, + const ui::Accelerator& previous_accelerator) = 0; + + // Performs the specified action. + virtual void PerformAction(AcceleratorAction action, + const ui::Accelerator& accelerator) = 0; + + // Shows a warning the user is using a deprecated accelerator. + virtual void ShowDeprecatedAcceleratorNotification( + const char* const notification_id, + int message_id, + int old_shortcut_id, + int new_shortcut_id) = 0; + + protected: + virtual ~AcceleratorControllerDelegate() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_H_
diff --git a/ash/common/accelerators/accelerator_router.cc b/ash/common/accelerators/accelerator_router.cc new file mode 100644 index 0000000..2a42383 --- /dev/null +++ b/ash/common/accelerators/accelerator_router.cc
@@ -0,0 +1,134 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/accelerator_router.h" + +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/metrics/histogram_macros.h" +#include "base/stl_util.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/event.h" + +namespace ash { + +namespace { + +// Returns true if |key_code| is a key usually handled directly by the shell. +bool IsSystemKey(ui::KeyboardCode key_code) { + switch (key_code) { + case ui::VKEY_MEDIA_LAUNCH_APP2: // Fullscreen button. + case ui::VKEY_MEDIA_LAUNCH_APP1: // Overview button. + case ui::VKEY_BRIGHTNESS_DOWN: + case ui::VKEY_BRIGHTNESS_UP: + case ui::VKEY_KBD_BRIGHTNESS_DOWN: + case ui::VKEY_KBD_BRIGHTNESS_UP: + case ui::VKEY_VOLUME_MUTE: + case ui::VKEY_VOLUME_DOWN: + case ui::VKEY_VOLUME_UP: + case ui::VKEY_POWER: + return true; + default: + return false; + } +} + +} // namespace + +AcceleratorRouter::AcceleratorRouter() {} + +AcceleratorRouter::~AcceleratorRouter() {} + +bool AcceleratorRouter::ProcessAccelerator(WmWindow* target, + const ui::KeyEvent& key_event, + const ui::Accelerator& accelerator) { + // Callers should never supply null. + DCHECK(target); + RecordSearchKeyStats(accelerator); + // Special hardware keys like brightness and volume are handled in + // special way. However, some windows can override this behavior + // (e.g. Chrome v1 apps by default and Chrome v2 apps with + // permission) by setting a window property. + if (IsSystemKey(key_event.key_code()) && + !CanConsumeSystemKeys(target, key_event)) { + // System keys are always consumed regardless of whether they trigger an + // accelerator to prevent windows from seeing unexpected key up events. + WmShell::Get()->accelerator_controller()->Process(accelerator); + return true; + } + if (!ShouldProcessAcceleratorNow(target, key_event, accelerator)) + return false; + return WmShell::Get()->accelerator_controller()->Process(accelerator); +} + +void AcceleratorRouter::RecordSearchKeyStats( + const ui::Accelerator& accelerator) { + if (accelerator.IsCmdDown()) { + if (search_key_state_ == RELEASED) { + search_key_state_ = PRESSED; + search_key_pressed_timestamp_ = base::TimeTicks::Now(); + } + + if (accelerator.key_code() != ui::KeyboardCode::VKEY_COMMAND && + search_key_state_ == PRESSED) { + search_key_state_ = RECORDED; + UMA_HISTOGRAM_TIMES( + "Keyboard.Shortcuts.CrosSearchKeyDelay", + base::TimeTicks::Now() - search_key_pressed_timestamp_); + } + } else { + search_key_state_ = RELEASED; + } +} + +bool AcceleratorRouter::CanConsumeSystemKeys(WmWindow* target, + const ui::KeyEvent& event) { + // Uses the top level window so if the target is a web contents window the + // containing parent window will be checked for the property. + WmWindow* top_level = target->GetToplevelWindowForFocus(); + return top_level && top_level->GetWindowState()->can_consume_system_keys(); +} + +bool AcceleratorRouter::ShouldProcessAcceleratorNow( + WmWindow* target, + const ui::KeyEvent& event, + const ui::Accelerator& accelerator) { + // Callers should never supply null. + DCHECK(target); + // On ChromeOS, If the accelerator is Search+<key(s)> then it must never be + // intercepted by apps or windows. + if (accelerator.IsCmdDown()) + return true; + + if (base::ContainsValue(WmShell::Get()->GetAllRootWindows(), target)) + return true; + + AcceleratorController* accelerator_controller = + WmShell::Get()->accelerator_controller(); + + // Reserved accelerators (such as Power button) always have a prority. + if (accelerator_controller->IsReserved(accelerator)) + return true; + + // A full screen window has a right to handle all key events including the + // reserved ones. + WmWindow* top_level = target->GetToplevelWindowForFocus(); + if (top_level && top_level->GetWindowState()->IsFullscreen()) { + // On ChromeOS, fullscreen windows are either browser or apps, which + // send key events to a web content first, then will process keys + // if the web content didn't consume them. + return false; + } + + // Handle preferred accelerators (such as ALT-TAB) before sending + // to the target. + if (accelerator_controller->IsPreferred(accelerator)) + return true; + + return WmShell::Get()->GetAppListTargetVisibility(); +} + +} // namespace ash
diff --git a/ash/accelerators/accelerator_router.h b/ash/common/accelerators/accelerator_router.h similarity index 100% rename from ash/accelerators/accelerator_router.h rename to ash/common/accelerators/accelerator_router.h
diff --git a/ash/common/accelerators/accelerator_table.cc b/ash/common/accelerators/accelerator_table.cc new file mode 100644 index 0000000..f0f06f82 --- /dev/null +++ b/ash/common/accelerators/accelerator_table.cc
@@ -0,0 +1,503 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/accelerator_table.h" + +#include "ash/strings/grit/ash_strings.h" +#include "base/macros.h" + +namespace ash { + +const int kDebugModifier = + ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN; + +const AcceleratorData kAcceleratorData[] = { + {true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, PREVIOUS_IME}, + {false, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN, PREVIOUS_IME}, + // Shortcuts for Japanese IME. + {true, ui::VKEY_CONVERT, ui::EF_NONE, SWITCH_IME}, + {true, ui::VKEY_NONCONVERT, ui::EF_NONE, SWITCH_IME}, + {true, ui::VKEY_DBE_SBCSCHAR, ui::EF_NONE, SWITCH_IME}, + {true, ui::VKEY_DBE_DBCSCHAR, ui::EF_NONE, SWITCH_IME}, + // Shortcut for Koren IME. + {true, ui::VKEY_HANGUL, ui::EF_NONE, SWITCH_IME}, + + {true, ui::VKEY_TAB, ui::EF_ALT_DOWN, CYCLE_FORWARD_MRU}, + {true, ui::VKEY_TAB, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, + CYCLE_BACKWARD_MRU}, + {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE, TOGGLE_OVERVIEW}, + {true, ui::VKEY_BROWSER_SEARCH, ui::EF_NONE, TOGGLE_APP_LIST}, + {true, ui::VKEY_WLAN, ui::EF_NONE, TOGGLE_WIFI}, + {true, ui::VKEY_KBD_BRIGHTNESS_DOWN, ui::EF_NONE, KEYBOARD_BRIGHTNESS_DOWN}, + {true, ui::VKEY_KBD_BRIGHTNESS_UP, ui::EF_NONE, KEYBOARD_BRIGHTNESS_UP}, + // Maximize button. + {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_CONTROL_DOWN, TOGGLE_MIRROR_MODE}, + {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_ALT_DOWN, SWAP_PRIMARY_DISPLAY}, + // Cycle windows button. + {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_CONTROL_DOWN, TAKE_SCREENSHOT}, + {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, + TAKE_PARTIAL_SCREENSHOT}, + {true, ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, + TAKE_WINDOW_SCREENSHOT}, + {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_NONE, BRIGHTNESS_DOWN}, + {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_ALT_DOWN, KEYBOARD_BRIGHTNESS_DOWN}, + {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_NONE, BRIGHTNESS_UP}, + {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_ALT_DOWN, KEYBOARD_BRIGHTNESS_UP}, + {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + MAGNIFY_SCREEN_ZOOM_OUT}, + {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + MAGNIFY_SCREEN_ZOOM_IN}, + {true, ui::VKEY_L, ui::EF_COMMAND_DOWN, LOCK_SCREEN}, + {true, ui::VKEY_L, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, SUSPEND}, + // The lock key on Chrome OS keyboards produces F13 scancodes. + {true, ui::VKEY_F13, ui::EF_NONE, LOCK_PRESSED}, + {false, ui::VKEY_F13, ui::EF_NONE, LOCK_RELEASED}, + // Generic keyboards can use VKEY_SLEEP to mimic ChromeOS keyboard's lock + // key. + {true, ui::VKEY_SLEEP, ui::EF_NONE, LOCK_PRESSED}, + {false, ui::VKEY_SLEEP, ui::EF_NONE, LOCK_RELEASED}, + {true, ui::VKEY_POWER, ui::EF_NONE, POWER_PRESSED}, + {false, ui::VKEY_POWER, ui::EF_NONE, POWER_RELEASED}, + {true, ui::VKEY_M, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, OPEN_FILE_MANAGER}, + {true, ui::VKEY_OEM_2, ui::EF_CONTROL_DOWN, OPEN_GET_HELP}, + {true, ui::VKEY_OEM_2, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, + OPEN_GET_HELP}, + {true, ui::VKEY_T, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, OPEN_CROSH}, + {true, ui::VKEY_I, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + TOUCH_HUD_MODE_CHANGE}, + {true, ui::VKEY_I, + ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN, + TOUCH_HUD_CLEAR}, + {true, ui::VKEY_P, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + TOUCH_HUD_PROJECTION_TOGGLE}, + {true, ui::VKEY_H, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, + TOGGLE_HIGH_CONTRAST}, + {true, ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + TOGGLE_SPOKEN_FEEDBACK}, + {true, ui::VKEY_OEM_COMMA, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + SWITCH_TO_PREVIOUS_USER}, + {true, ui::VKEY_OEM_PERIOD, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + SWITCH_TO_NEXT_USER}, + // Single shift release turns off caps lock. + {false, ui::VKEY_LSHIFT, ui::EF_NONE, DISABLE_CAPS_LOCK}, + {false, ui::VKEY_SHIFT, ui::EF_NONE, DISABLE_CAPS_LOCK}, + {false, ui::VKEY_RSHIFT, ui::EF_NONE, DISABLE_CAPS_LOCK}, + // Accelerators to toggle Caps Lock. + // The following is triggered when Search is released while Alt is still + // down. The key_code here is LWIN (for search) and Alt is a modifier. + {false, ui::VKEY_LWIN, ui::EF_ALT_DOWN, TOGGLE_CAPS_LOCK}, + // The following is triggered when Alt is released while search is still + // down. The key_code here is MENU (for Alt) and Search is a modifier + // (EF_COMMAND_DOWN is used for Search as a modifier). + {false, ui::VKEY_MENU, ui::EF_COMMAND_DOWN, TOGGLE_CAPS_LOCK}, + {true, ui::VKEY_VOLUME_MUTE, ui::EF_NONE, VOLUME_MUTE}, + {true, ui::VKEY_VOLUME_DOWN, ui::EF_NONE, VOLUME_DOWN}, + {true, ui::VKEY_VOLUME_UP, ui::EF_NONE, VOLUME_UP}, + {true, ui::VKEY_ESCAPE, ui::EF_COMMAND_DOWN, SHOW_TASK_MANAGER}, + {true, ui::VKEY_SPACE, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, NEXT_IME}, + {true, ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, OPEN_FEEDBACK_PAGE}, + {true, ui::VKEY_Q, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, EXIT}, + {true, ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, + NEW_INCOGNITO_WINDOW}, + {true, ui::VKEY_N, ui::EF_CONTROL_DOWN, NEW_WINDOW}, + {true, ui::VKEY_T, ui::EF_CONTROL_DOWN, NEW_TAB}, + {true, ui::VKEY_OEM_MINUS, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, + SCALE_UI_UP}, + {true, ui::VKEY_OEM_PLUS, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, + SCALE_UI_DOWN}, + {true, ui::VKEY_0, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, SCALE_UI_RESET}, + {true, ui::VKEY_BROWSER_REFRESH, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, + ROTATE_SCREEN}, + {true, ui::VKEY_BROWSER_REFRESH, + ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, ROTATE_WINDOW}, + {true, ui::VKEY_T, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, RESTORE_TAB}, + {true, ui::VKEY_PRINT, ui::EF_NONE, TAKE_SCREENSHOT}, + // On Chrome OS, Search key is mapped to LWIN. The Search key binding should + // act on release instead of press when using Search as a modifier key for + // extended keyboard shortcuts. + {false, ui::VKEY_LWIN, ui::EF_NONE, TOGGLE_APP_LIST}, + {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_NONE, TOGGLE_FULLSCREEN}, + {true, ui::VKEY_MEDIA_LAUNCH_APP2, ui::EF_SHIFT_DOWN, TOGGLE_FULLSCREEN}, + {true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN, UNPIN}, + {true, ui::VKEY_L, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, FOCUS_SHELF}, + {true, ui::VKEY_HELP, ui::EF_NONE, SHOW_KEYBOARD_OVERLAY}, + {true, ui::VKEY_OEM_2, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + SHOW_KEYBOARD_OVERLAY}, + {true, ui::VKEY_OEM_2, + ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + SHOW_KEYBOARD_OVERLAY}, + {true, ui::VKEY_F14, ui::EF_NONE, SHOW_KEYBOARD_OVERLAY}, + {true, ui::VKEY_N, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, + SHOW_MESSAGE_CENTER_BUBBLE}, + {true, ui::VKEY_P, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, SHOW_STYLUS_TOOLS}, + {true, ui::VKEY_S, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, + SHOW_SYSTEM_TRAY_BUBBLE}, + {true, ui::VKEY_K, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, + SHOW_IME_MENU_BUBBLE}, + {true, ui::VKEY_1, ui::EF_ALT_DOWN, LAUNCH_APP_0}, + {true, ui::VKEY_2, ui::EF_ALT_DOWN, LAUNCH_APP_1}, + {true, ui::VKEY_3, ui::EF_ALT_DOWN, LAUNCH_APP_2}, + {true, ui::VKEY_4, ui::EF_ALT_DOWN, LAUNCH_APP_3}, + {true, ui::VKEY_5, ui::EF_ALT_DOWN, LAUNCH_APP_4}, + {true, ui::VKEY_6, ui::EF_ALT_DOWN, LAUNCH_APP_5}, + {true, ui::VKEY_7, ui::EF_ALT_DOWN, LAUNCH_APP_6}, + {true, ui::VKEY_8, ui::EF_ALT_DOWN, LAUNCH_APP_7}, + {true, ui::VKEY_9, ui::EF_ALT_DOWN, LAUNCH_LAST_APP}, + + // Window management shortcuts. + {true, ui::VKEY_OEM_4, ui::EF_ALT_DOWN, WINDOW_CYCLE_SNAP_DOCK_LEFT}, + {true, ui::VKEY_OEM_6, ui::EF_ALT_DOWN, WINDOW_CYCLE_SNAP_DOCK_RIGHT}, + {true, ui::VKEY_OEM_MINUS, ui::EF_ALT_DOWN, WINDOW_MINIMIZE}, + {true, ui::VKEY_OEM_PLUS, ui::EF_ALT_DOWN, TOGGLE_MAXIMIZED}, + {true, ui::VKEY_OEM_PLUS, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, + WINDOW_POSITION_CENTER}, + {true, ui::VKEY_BROWSER_FORWARD, ui::EF_CONTROL_DOWN, FOCUS_NEXT_PANE}, + {true, ui::VKEY_BROWSER_BACK, ui::EF_CONTROL_DOWN, FOCUS_PREVIOUS_PANE}, + + // Media Player shortcuts. + {true, ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE, MEDIA_NEXT_TRACK}, + {true, ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE, MEDIA_PLAY_PAUSE}, + {true, ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE, MEDIA_PREV_TRACK}, + + // Debugging shortcuts that need to be available to end-users in + // release builds. + {true, ui::VKEY_U, kDebugModifier, PRINT_UI_HIERARCHIES}, + + // TODO(yusukes): Handle VKEY_MEDIA_STOP, and + // VKEY_MEDIA_LAUNCH_MAIL. +}; + +const size_t kAcceleratorDataLength = arraysize(kAcceleratorData); + +// Instructions for how to deprecate and replace an Accelerator: +// +// 1- Replace the old deprecated accelerator from the above list with the new +// accelerator that will take its place. +// 2- Add an entry for it in the following |kDeprecatedAccelerators| list. +// 3- Add another entry in the |kDeprecatedAcceleratorsData|. +// 4- That entry should contain the following: +// - The action that the deprecated accelerator maps to. +// - Define a histogram for this action in |histograms.xml| in the form +// "Ash.Accelerators.Deprecated.{ActionName}" and include the name of this +// histogram in this entry. This name will be used as the ID of the +// notification to be shown to the user. This is to prevent duplication of +// same notification. +// - The ID of the localized notification message to give the users telling +// them about the deprecation (Add one in |ash_strings.grd|. Search for +// the comment <!-- Deprecated Accelerators Messages -->). +// - The IDs of the localized old and new shortcut text to be used to fill +// the notification text. Also found in |ash_strings.grd|. +// - {true or false} whether the deprecated accelerator is still enabled (we +// don't disable a deprecated accelerator abruptly). +// 5- Don't forget to update the keyboard overlay. Find 'shortcut' in the file +// keyboard_overlay_data.js. +const AcceleratorData kDeprecatedAccelerators[] = { + {true, ui::VKEY_L, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, LOCK_SCREEN}, + {true, ui::VKEY_ESCAPE, ui::EF_SHIFT_DOWN, SHOW_TASK_MANAGER}}; + +const size_t kDeprecatedAcceleratorsLength = arraysize(kDeprecatedAccelerators); + +const DeprecatedAcceleratorData kDeprecatedAcceleratorsData[] = { + { + LOCK_SCREEN, "Ash.Accelerators.Deprecated.LockScreen", + IDS_DEPRECATED_LOCK_SCREEN_MSG, IDS_SHORTCUT_LOCK_SCREEN_OLD, + IDS_SHORTCUT_LOCK_SCREEN_NEW, + false // Old accelerator was disabled in M56. + }, + {SHOW_TASK_MANAGER, "Ash.Accelerators.Deprecated.ShowTaskManager", + IDS_DEPRECATED_SHOW_TASK_MANAGER_MSG, IDS_SHORTCUT_TASK_MANAGER_OLD, + IDS_SHORTCUT_TASK_MANAGER_NEW, true}}; + +const size_t kDeprecatedAcceleratorsDataLength = + arraysize(kDeprecatedAcceleratorsData); + +const AcceleratorData kDebugAcceleratorData[] = { + {true, ui::VKEY_N, kDebugModifier, TOGGLE_WIFI}, + {true, ui::VKEY_O, kDebugModifier, DEBUG_SHOW_TOAST}, + {true, ui::VKEY_P, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, + DEBUG_TOGGLE_TOUCH_PAD}, + {true, ui::VKEY_T, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN, + DEBUG_TOGGLE_TOUCH_SCREEN}, + {true, ui::VKEY_T, kDebugModifier, DEBUG_TOGGLE_TOUCH_VIEW}, + {true, ui::VKEY_B, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + DEBUG_TOGGLE_WALLPAPER_MODE}, + {true, ui::VKEY_L, kDebugModifier, DEBUG_PRINT_LAYER_HIERARCHY}, + {true, ui::VKEY_V, kDebugModifier, DEBUG_PRINT_VIEW_HIERARCHY}, + {true, ui::VKEY_W, kDebugModifier, DEBUG_PRINT_WINDOW_HIERARCHY}, + {true, ui::VKEY_D, kDebugModifier, DEBUG_TOGGLE_DEVICE_SCALE_FACTOR}, + {true, ui::VKEY_B, kDebugModifier, DEBUG_TOGGLE_SHOW_DEBUG_BORDERS}, + {true, ui::VKEY_F, kDebugModifier, DEBUG_TOGGLE_SHOW_FPS_COUNTER}, + {true, ui::VKEY_P, kDebugModifier, DEBUG_TOGGLE_SHOW_PAINT_RECTS}, + {true, ui::VKEY_K, kDebugModifier, DEBUG_TRIGGER_CRASH}, +}; + +const size_t kDebugAcceleratorDataLength = arraysize(kDebugAcceleratorData); + +const AcceleratorData kDeveloperAcceleratorData[] = { + // Extra shortcut for debug build to control magnifier on Linux desktop. + {true, ui::VKEY_BRIGHTNESS_DOWN, ui::EF_CONTROL_DOWN, + MAGNIFY_SCREEN_ZOOM_OUT}, + {true, ui::VKEY_BRIGHTNESS_UP, ui::EF_CONTROL_DOWN, MAGNIFY_SCREEN_ZOOM_IN}, + // Extra shortcuts to lock the screen on Linux desktop. + {true, ui::VKEY_L, ui::EF_ALT_DOWN, LOCK_PRESSED}, + {false, ui::VKEY_L, ui::EF_ALT_DOWN, LOCK_RELEASED}, + {true, ui::VKEY_P, ui::EF_ALT_DOWN, POWER_PRESSED}, + {false, ui::VKEY_P, ui::EF_ALT_DOWN, POWER_RELEASED}, + {true, ui::VKEY_POWER, ui::EF_SHIFT_DOWN, LOCK_PRESSED}, + {false, ui::VKEY_POWER, ui::EF_SHIFT_DOWN, LOCK_RELEASED}, + {true, ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, + DEV_ADD_REMOVE_DISPLAY}, + {true, ui::VKEY_J, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, + DEV_TOGGLE_UNIFIED_DESKTOP}, + {true, ui::VKEY_M, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, + TOGGLE_MIRROR_MODE}, + {true, ui::VKEY_W, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, TOGGLE_WIFI}, + // Extra shortcut for display swapping as Alt-F4 is taken on Linux desktop. + {true, ui::VKEY_S, kDebugModifier, SWAP_PRIMARY_DISPLAY}, + // Extra shortcut to rotate/scale up/down the screen on Linux desktop. + {true, ui::VKEY_R, kDebugModifier, ROTATE_SCREEN}, + // For testing on systems where Alt-Tab is already mapped. + {true, ui::VKEY_W, ui::EF_ALT_DOWN, CYCLE_FORWARD_MRU}, + {true, ui::VKEY_F11, ui::EF_CONTROL_DOWN, + DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN}, + {true, ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN, CYCLE_BACKWARD_MRU}, + {true, ui::VKEY_F, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, + TOGGLE_FULLSCREEN}, +}; + +const size_t kDeveloperAcceleratorDataLength = + arraysize(kDeveloperAcceleratorData); + +const AcceleratorAction kPreferredActions[] = { + // Window cycling accelerators. + CYCLE_BACKWARD_MRU, // Shift+Alt+Tab + CYCLE_FORWARD_MRU, // Alt+Tab +}; + +const size_t kPreferredActionsLength = arraysize(kPreferredActions); + +const AcceleratorAction kReservedActions[] = { + POWER_PRESSED, POWER_RELEASED, SUSPEND, +}; + +const size_t kReservedActionsLength = arraysize(kReservedActions); + +const AcceleratorAction kActionsAllowedAtLoginOrLockScreen[] = { + BRIGHTNESS_DOWN, + BRIGHTNESS_UP, + DEBUG_PRINT_LAYER_HIERARCHY, + DEBUG_PRINT_VIEW_HIERARCHY, + DEBUG_PRINT_WINDOW_HIERARCHY, + DEBUG_TOGGLE_TOUCH_PAD, + DEBUG_TOGGLE_TOUCH_SCREEN, + DEBUG_TOGGLE_TOUCH_VIEW, + DEV_ADD_REMOVE_DISPLAY, + DISABLE_CAPS_LOCK, + KEYBOARD_BRIGHTNESS_DOWN, + KEYBOARD_BRIGHTNESS_UP, + MAGNIFY_SCREEN_ZOOM_IN, // Control+F7 + MAGNIFY_SCREEN_ZOOM_OUT, // Control+F6 + NEXT_IME, + PREVIOUS_IME, + PRINT_UI_HIERARCHIES, + ROTATE_SCREEN, + SCALE_UI_DOWN, + SCALE_UI_RESET, + SCALE_UI_UP, + SHOW_IME_MENU_BUBBLE, + SHOW_SYSTEM_TRAY_BUBBLE, + SWITCH_IME, // Switch to another IME depending on the accelerator. + TAKE_PARTIAL_SCREENSHOT, + TAKE_SCREENSHOT, + TAKE_WINDOW_SCREENSHOT, + TOGGLE_CAPS_LOCK, + TOGGLE_HIGH_CONTRAST, + TOGGLE_MIRROR_MODE, + TOGGLE_SPOKEN_FEEDBACK, + TOGGLE_WIFI, + TOUCH_HUD_CLEAR, + VOLUME_DOWN, + VOLUME_MUTE, + VOLUME_UP, +#if !defined(NDEBUG) + POWER_PRESSED, + POWER_RELEASED, +#endif // !defined(NDEBUG) +}; + +const size_t kActionsAllowedAtLoginOrLockScreenLength = + arraysize(kActionsAllowedAtLoginOrLockScreen); + +const AcceleratorAction kActionsAllowedAtLockScreen[] = { + EXIT, SUSPEND, +}; + +const size_t kActionsAllowedAtLockScreenLength = + arraysize(kActionsAllowedAtLockScreen); + +const AcceleratorAction kActionsAllowedAtModalWindow[] = { + BRIGHTNESS_DOWN, + BRIGHTNESS_UP, + DEBUG_TOGGLE_TOUCH_PAD, + DEBUG_TOGGLE_TOUCH_SCREEN, + DEV_ADD_REMOVE_DISPLAY, + DISABLE_CAPS_LOCK, + EXIT, + KEYBOARD_BRIGHTNESS_DOWN, + KEYBOARD_BRIGHTNESS_UP, + LOCK_SCREEN, + MAGNIFY_SCREEN_ZOOM_IN, + MAGNIFY_SCREEN_ZOOM_OUT, + MEDIA_NEXT_TRACK, + MEDIA_PLAY_PAUSE, + MEDIA_PREV_TRACK, + NEXT_IME, + OPEN_FEEDBACK_PAGE, + POWER_PRESSED, + POWER_RELEASED, + PREVIOUS_IME, + PRINT_UI_HIERARCHIES, + ROTATE_SCREEN, + SCALE_UI_DOWN, + SCALE_UI_RESET, + SCALE_UI_UP, + SHOW_IME_MENU_BUBBLE, + SHOW_KEYBOARD_OVERLAY, + SUSPEND, + SWAP_PRIMARY_DISPLAY, + SWITCH_IME, + TAKE_PARTIAL_SCREENSHOT, + TAKE_SCREENSHOT, + TAKE_WINDOW_SCREENSHOT, + TOGGLE_CAPS_LOCK, + TOGGLE_HIGH_CONTRAST, + TOGGLE_MIRROR_MODE, + TOGGLE_SPOKEN_FEEDBACK, + TOGGLE_WIFI, + VOLUME_DOWN, + VOLUME_MUTE, + VOLUME_UP, +}; + +const size_t kActionsAllowedAtModalWindowLength = + arraysize(kActionsAllowedAtModalWindow); + +const AcceleratorAction kRepeatableActions[] = { + BRIGHTNESS_DOWN, + BRIGHTNESS_UP, + FOCUS_NEXT_PANE, + FOCUS_PREVIOUS_PANE, + KEYBOARD_BRIGHTNESS_DOWN, + KEYBOARD_BRIGHTNESS_UP, + MAGNIFY_SCREEN_ZOOM_IN, + MAGNIFY_SCREEN_ZOOM_OUT, + MEDIA_NEXT_TRACK, + MEDIA_PREV_TRACK, + RESTORE_TAB, + VOLUME_DOWN, + VOLUME_UP, +}; + +const size_t kRepeatableActionsLength = arraysize(kRepeatableActions); + +const AcceleratorAction kActionsAllowedInAppModeOrPinnedMode[] = { + BRIGHTNESS_DOWN, + BRIGHTNESS_UP, + DEBUG_PRINT_LAYER_HIERARCHY, + DEBUG_PRINT_VIEW_HIERARCHY, + DEBUG_PRINT_WINDOW_HIERARCHY, + DEBUG_TOGGLE_TOUCH_PAD, + DEBUG_TOGGLE_TOUCH_SCREEN, + DEV_ADD_REMOVE_DISPLAY, + DISABLE_CAPS_LOCK, + KEYBOARD_BRIGHTNESS_DOWN, + KEYBOARD_BRIGHTNESS_UP, + MAGNIFY_SCREEN_ZOOM_IN, // Control+F7 + MAGNIFY_SCREEN_ZOOM_OUT, // Control+F6 + MEDIA_NEXT_TRACK, + MEDIA_PLAY_PAUSE, + MEDIA_PREV_TRACK, + NEXT_IME, + POWER_PRESSED, + POWER_RELEASED, + PREVIOUS_IME, + PRINT_UI_HIERARCHIES, + ROTATE_SCREEN, + SCALE_UI_DOWN, + SCALE_UI_RESET, + SCALE_UI_UP, + SWAP_PRIMARY_DISPLAY, + SWITCH_IME, // Switch to another IME depending on the accelerator. + TOGGLE_CAPS_LOCK, + TOGGLE_HIGH_CONTRAST, + TOGGLE_MIRROR_MODE, + TOGGLE_SPOKEN_FEEDBACK, + TOGGLE_WIFI, + TOUCH_HUD_CLEAR, + VOLUME_DOWN, + VOLUME_MUTE, + VOLUME_UP, +}; + +const size_t kActionsAllowedInAppModeOrPinnedModeLength = + arraysize(kActionsAllowedInAppModeOrPinnedMode); + +const AcceleratorAction kActionsAllowedInPinnedMode[] = { + LOCK_SCREEN, + SUSPEND, + TAKE_PARTIAL_SCREENSHOT, + TAKE_SCREENSHOT, + TAKE_WINDOW_SCREENSHOT, + UNPIN, +}; + +const size_t kActionsAllowedInPinnedModeLength = + arraysize(kActionsAllowedInPinnedMode); + +const AcceleratorAction kActionsNeedingWindow[] = { + CYCLE_BACKWARD_MRU, + CYCLE_FORWARD_MRU, + TOGGLE_OVERVIEW, + WINDOW_CYCLE_SNAP_DOCK_LEFT, + WINDOW_CYCLE_SNAP_DOCK_RIGHT, + WINDOW_MINIMIZE, + TOGGLE_FULLSCREEN, + TOGGLE_MAXIMIZED, + WINDOW_POSITION_CENTER, + ROTATE_WINDOW, +}; + +const size_t kActionsNeedingWindowLength = arraysize(kActionsNeedingWindow); + +const AcceleratorAction kActionsKeepingMenuOpen[] = { + BRIGHTNESS_DOWN, + BRIGHTNESS_UP, + DEBUG_TOGGLE_TOUCH_PAD, + DEBUG_TOGGLE_TOUCH_SCREEN, + DISABLE_CAPS_LOCK, + KEYBOARD_BRIGHTNESS_DOWN, + KEYBOARD_BRIGHTNESS_UP, + MEDIA_NEXT_TRACK, + MEDIA_PLAY_PAUSE, + MEDIA_PREV_TRACK, + NEXT_IME, + PREVIOUS_IME, + PRINT_UI_HIERARCHIES, + SWITCH_IME, + TAKE_PARTIAL_SCREENSHOT, + TAKE_SCREENSHOT, + TAKE_WINDOW_SCREENSHOT, + TOGGLE_APP_LIST, + TOGGLE_CAPS_LOCK, + TOGGLE_HIGH_CONTRAST, + TOGGLE_SPOKEN_FEEDBACK, + TOGGLE_WIFI, + VOLUME_DOWN, + VOLUME_MUTE, + VOLUME_UP, +}; + +const size_t kActionsKeepingMenuOpenLength = arraysize(kActionsKeepingMenuOpen); + +} // namespace ash
diff --git a/ash/common/accelerators/accelerator_table.h b/ash/common/accelerators/accelerator_table.h new file mode 100644 index 0000000..86a4e0d1 --- /dev/null +++ b/ash/common/accelerators/accelerator_table.h
@@ -0,0 +1,264 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_ACCELERATOR_TABLE_H_ +#define ASH_COMMON_ACCELERATORS_ACCELERATOR_TABLE_H_ + +#include <stddef.h> + +#include "ash/ash_export.h" +#include "ui/events/event_constants.h" +#include "ui/events/keycodes/keyboard_codes.h" + +namespace ash { + +// There are five classes of accelerators in Ash: +// +// Ash (OS) reserved: +// * Neither packaged apps nor web pages can cancel. +// * For example, power button. +// * See kReservedActions below. +// +// Ash (OS) preferred: +// * Fullscreen window can consume, but normal window can't. +// * For example, Alt-Tab window cycling. +// * See kPreferredActions below. +// +// Chrome OS system keys: +// * For legacy reasons, v1 apps can process and cancel. Otherwise handled +// directly by Ash. +// * Brightness, volume control, etc. +// * See IsSystemKey() in ash/accelerators/accelerator_filter.cc. +// +// Browser reserved: +// * Packaged apps can cancel but web pages cannot. +// * For example, browser back and forward from first-row function keys. +// * See IsReservedCommandOrKey() in +// chrome/browser/ui/browser_command_controller.cc. +// +// Browser non-reserved: +// * Both packaged apps and web pages can cancel. +// * For example, selecting tabs by number with Ctrl-1 to Ctrl-9. +// * See kAcceleratorMap in chrome/browser/ui/views/accelerator_table.cc. +// +// In particular, there is not an accelerator processing pass for Ash after +// the browser gets the accelerator. See crbug.com/285308 for details. +// +// There are also various restrictions on accelerators allowed at the login +// screen, when running in "forced app mode" (like a kiosk), etc. See the +// various kActionsAllowed* below. +// +// Please put if/def sections at the end of the bare section and keep the list +// within each section in alphabetical order. +enum AcceleratorAction { + BRIGHTNESS_DOWN, + BRIGHTNESS_UP, + CYCLE_BACKWARD_MRU, + CYCLE_FORWARD_MRU, + DEBUG_PRINT_LAYER_HIERARCHY, + DEBUG_PRINT_VIEW_HIERARCHY, + DEBUG_PRINT_WINDOW_HIERARCHY, + DEBUG_SHOW_TOAST, + DEBUG_TOGGLE_DEVICE_SCALE_FACTOR, + DEBUG_TOGGLE_SHOW_DEBUG_BORDERS, + DEBUG_TOGGLE_SHOW_FPS_COUNTER, + DEBUG_TOGGLE_SHOW_PAINT_RECTS, + DEBUG_TOGGLE_TOUCH_PAD, + DEBUG_TOGGLE_TOUCH_SCREEN, + DEBUG_TOGGLE_TOUCH_VIEW, + DEBUG_TOGGLE_WALLPAPER_MODE, + DEBUG_TRIGGER_CRASH, // Intentionally crash the ash process. + DEV_ADD_REMOVE_DISPLAY, + DEV_TOGGLE_ROOT_WINDOW_FULL_SCREEN, + DEV_TOGGLE_UNIFIED_DESKTOP, + DISABLE_CAPS_LOCK, + EXIT, + FOCUS_NEXT_PANE, + FOCUS_PREVIOUS_PANE, + FOCUS_SHELF, + KEYBOARD_BRIGHTNESS_DOWN, + KEYBOARD_BRIGHTNESS_UP, + LAUNCH_APP_0, + LAUNCH_APP_1, + LAUNCH_APP_2, + LAUNCH_APP_3, + LAUNCH_APP_4, + LAUNCH_APP_5, + LAUNCH_APP_6, + LAUNCH_APP_7, + LAUNCH_LAST_APP, + LOCK_PRESSED, + LOCK_RELEASED, + LOCK_SCREEN, + MAGNIFY_SCREEN_ZOOM_IN, + MAGNIFY_SCREEN_ZOOM_OUT, + MEDIA_NEXT_TRACK, + MEDIA_PLAY_PAUSE, + MEDIA_PREV_TRACK, + NEW_INCOGNITO_WINDOW, + NEW_TAB, + NEW_WINDOW, + NEXT_IME, + OPEN_CROSH, + OPEN_FEEDBACK_PAGE, + OPEN_FILE_MANAGER, + OPEN_GET_HELP, + POWER_PRESSED, + POWER_RELEASED, + PREVIOUS_IME, + PRINT_UI_HIERARCHIES, + RESTORE_TAB, + ROTATE_SCREEN, + ROTATE_WINDOW, + SCALE_UI_DOWN, + SCALE_UI_RESET, + SCALE_UI_UP, + SHOW_IME_MENU_BUBBLE, + SHOW_KEYBOARD_OVERLAY, + SHOW_MESSAGE_CENTER_BUBBLE, + SHOW_STYLUS_TOOLS, + SHOW_SYSTEM_TRAY_BUBBLE, + SHOW_TASK_MANAGER, + SUSPEND, + SWAP_PRIMARY_DISPLAY, + SWITCH_IME, // Switch to another IME depending on the accelerator. + SWITCH_TO_NEXT_USER, + SWITCH_TO_PREVIOUS_USER, + TAKE_PARTIAL_SCREENSHOT, + TAKE_SCREENSHOT, + TAKE_WINDOW_SCREENSHOT, + TOGGLE_APP_LIST, + TOGGLE_CAPS_LOCK, + TOGGLE_FULLSCREEN, + TOGGLE_HIGH_CONTRAST, + TOGGLE_MAXIMIZED, + TOGGLE_MIRROR_MODE, + TOGGLE_OVERVIEW, + TOGGLE_SPOKEN_FEEDBACK, + TOGGLE_WIFI, + TOUCH_HUD_CLEAR, + TOUCH_HUD_MODE_CHANGE, + TOUCH_HUD_PROJECTION_TOGGLE, + UNPIN, + VOLUME_DOWN, + VOLUME_MUTE, + VOLUME_UP, + WINDOW_CYCLE_SNAP_DOCK_LEFT, + WINDOW_CYCLE_SNAP_DOCK_RIGHT, + WINDOW_MINIMIZE, + WINDOW_POSITION_CENTER, +}; + +struct AcceleratorData { + bool trigger_on_press; + ui::KeyboardCode keycode; + int modifiers; + AcceleratorAction action; +}; + +// Gathers the needed data to handle deprecated accelerators. +struct DeprecatedAcceleratorData { + // The action that has deprecated accelerators. + AcceleratorAction action; + + // The name of the UMA histogram that will be used to measure the deprecated + // v.s. new accelerator usage. + const char* uma_histogram_name; + + // The ID of the localized notification message to show to users informing + // them about the deprecation. + int notification_message_id; + + // The ID of the localized old deprecated shortcut key. + int old_shortcut_id; + + // The ID of the localized new shortcut key. + int new_shortcut_id; + + // Specifies whether the deprecated accelerator is still enabled to do its + // associated action. + bool deprecated_enabled; +}; + +// This will be used for the UMA stats to measure the how many users are using +// the old v.s. new accelerators. +enum DeprecatedAcceleratorUsage { + DEPRECATED_USED = 0, // The deprecated accelerator is used. + NEW_USED, // The new accelerator is used. + DEPRECATED_USAGE_COUNT, // Maximum value of this enum for histogram use. +}; + +// Accelerators handled by AcceleratorController. +ASH_EXPORT extern const AcceleratorData kAcceleratorData[]; +ASH_EXPORT extern const size_t kAcceleratorDataLength; + +// The list of the deprecated accelerators. +ASH_EXPORT extern const AcceleratorData kDeprecatedAccelerators[]; +ASH_EXPORT extern const size_t kDeprecatedAcceleratorsLength; + +// The list of the actions with deprecated accelerators and the needed data to +// handle them. +ASH_EXPORT extern const DeprecatedAcceleratorData kDeprecatedAcceleratorsData[]; +ASH_EXPORT extern const size_t kDeprecatedAcceleratorsDataLength; + +// Debug accelerators. Debug accelerators are only enabled when the "Debugging +// keyboard shortcuts" flag (--ash-debug-shortcuts) is enabled. Debug actions +// are always run (similar to reserved actions). Debug accelerators can be +// enabled in about:flags. +ASH_EXPORT extern const AcceleratorData kDebugAcceleratorData[]; +ASH_EXPORT extern const size_t kDebugAcceleratorDataLength; + +// Developer accelerators that are enabled only with the command-line switch +// --ash-dev-shortcuts. They are always run similar to reserved actions. +ASH_EXPORT extern const AcceleratorData kDeveloperAcceleratorData[]; +ASH_EXPORT extern const size_t kDeveloperAcceleratorDataLength; + +// Actions that should be handled very early in Ash unless the current target +// window is full-screen. +ASH_EXPORT extern const AcceleratorAction kPreferredActions[]; +ASH_EXPORT extern const size_t kPreferredActionsLength; + +// Actions that are always handled in Ash. +ASH_EXPORT extern const AcceleratorAction kReservedActions[]; +ASH_EXPORT extern const size_t kReservedActionsLength; + +// Actions allowed while user is not signed in or screen is locked. +ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtLoginOrLockScreen[]; +ASH_EXPORT extern const size_t kActionsAllowedAtLoginOrLockScreenLength; + +// Actions allowed while screen is locked (in addition to +// kActionsAllowedAtLoginOrLockScreen). +ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtLockScreen[]; +ASH_EXPORT extern const size_t kActionsAllowedAtLockScreenLength; + +// Actions allowed while a modal window is up. +ASH_EXPORT extern const AcceleratorAction kActionsAllowedAtModalWindow[]; +ASH_EXPORT extern const size_t kActionsAllowedAtModalWindowLength; + +// Actions which may be repeated by holding an accelerator key. +ASH_EXPORT extern const AcceleratorAction kRepeatableActions[]; +ASH_EXPORT extern const size_t kRepeatableActionsLength; + +// Actions allowed in app mode or pinned mode. +ASH_EXPORT extern const AcceleratorAction + kActionsAllowedInAppModeOrPinnedMode[]; +ASH_EXPORT extern const size_t kActionsAllowedInAppModeOrPinnedModeLength; + +// Actions that can be performed in pinned mode. +// In pinned mode, the action listed this or "in app mode or pinned mode" table +// can be performed. +ASH_EXPORT extern const AcceleratorAction kActionsAllowedInPinnedMode[]; +ASH_EXPORT extern const size_t kActionsAllowedInPinnedModeLength; + +// Actions that require at least 1 window. +ASH_EXPORT extern const AcceleratorAction kActionsNeedingWindow[]; +ASH_EXPORT extern const size_t kActionsNeedingWindowLength; + +// Actions that can be performed while keeping the menu open. +ASH_EXPORT extern const AcceleratorAction kActionsKeepingMenuOpen[]; +ASH_EXPORT extern const size_t kActionsKeepingMenuOpenLength; + +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_ACCELERATOR_TABLE_H_
diff --git a/ash/common/accelerators/accelerator_table_unittest.cc b/ash/common/accelerators/accelerator_table_unittest.cc new file mode 100644 index 0000000..e469625 --- /dev/null +++ b/ash/common/accelerators/accelerator_table_unittest.cc
@@ -0,0 +1,104 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <set> + +#include "ash/common/accelerators/accelerator_table.h" +#include "base/strings/string_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +namespace { + +struct Cmp { + bool operator()(const AcceleratorData& lhs, const AcceleratorData& rhs) { + if (lhs.trigger_on_press != rhs.trigger_on_press) + return lhs.trigger_on_press < rhs.trigger_on_press; + if (lhs.keycode != rhs.keycode) + return lhs.keycode < rhs.keycode; + return lhs.modifiers < rhs.modifiers; + // Do not check |action|. + } +}; + +} // namespace + +TEST(AcceleratorTableTest, CheckDuplicatedAccelerators) { + std::set<AcceleratorData, Cmp> accelerators; + for (size_t i = 0; i < kAcceleratorDataLength; ++i) { + const AcceleratorData& entry = kAcceleratorData[i]; + EXPECT_TRUE(accelerators.insert(entry).second) + << "Duplicated accelerator: " << entry.trigger_on_press << ", " + << entry.keycode << ", " << (entry.modifiers & ui::EF_SHIFT_DOWN) + << ", " << (entry.modifiers & ui::EF_CONTROL_DOWN) << ", " + << (entry.modifiers & ui::EF_ALT_DOWN); + } +} + +TEST(AcceleratorTableTest, CheckDuplicatedReservedActions) { + std::set<AcceleratorAction> actions; + for (size_t i = 0; i < kReservedActionsLength; ++i) { + EXPECT_TRUE(actions.insert(kReservedActions[i]).second) + << "Duplicated action: " << kReservedActions[i]; + } +} + +TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtLoginOrLockScreen) { + std::set<AcceleratorAction> actions; + for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { + EXPECT_TRUE(actions.insert(kActionsAllowedAtLoginOrLockScreen[i]).second) + << "Duplicated action: " << kActionsAllowedAtLoginOrLockScreen[i]; + } + for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) { + EXPECT_TRUE(actions.insert(kActionsAllowedAtLockScreen[i]).second) + << "Duplicated action: " << kActionsAllowedAtLockScreen[i]; + } +} + +TEST(AcceleratorTableTest, CheckDuplicatedActionsAllowedAtModalWindow) { + std::set<AcceleratorAction> actions; + for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) { + EXPECT_TRUE(actions.insert(kActionsAllowedAtModalWindow[i]).second) + << "Duplicated action: " << kActionsAllowedAtModalWindow[i] + << " at index: " << i; + } +} + +TEST(AcceleratorTableTest, CheckDuplicatedRepeatableActions) { + std::set<AcceleratorAction> actions; + for (size_t i = 0; i < kRepeatableActionsLength; ++i) { + EXPECT_TRUE(actions.insert(kRepeatableActions[i]).second) + << "Duplicated action: " << kRepeatableActions[i] << " at index: " << i; + } +} + +TEST(AcceleratorTableTest, CheckDeprecatedAccelerators) { + std::set<AcceleratorData, Cmp> deprecated_actions; + for (size_t i = 0; i < kDeprecatedAcceleratorsLength; ++i) { + // A deprecated action can never appear twice in the list. + const AcceleratorData& entry = kDeprecatedAccelerators[i]; + EXPECT_TRUE(deprecated_actions.insert(entry).second) + << "Duplicate deprecated accelerator: " << entry.trigger_on_press + << ", " << entry.keycode << ", " + << (entry.modifiers & ui::EF_SHIFT_DOWN) << ", " + << (entry.modifiers & ui::EF_CONTROL_DOWN) << ", " + << (entry.modifiers & ui::EF_ALT_DOWN); + } + + std::set<AcceleratorAction> actions; + for (size_t i = 0; i < kDeprecatedAcceleratorsDataLength; ++i) { + // There must never be any duplicated actions. + const DeprecatedAcceleratorData& data = kDeprecatedAcceleratorsData[i]; + EXPECT_TRUE(actions.insert(data.action).second) << "Deprecated action: " + << data.action; + + // The UMA histogram name must be of the format "Ash.Accelerators.*" + std::string uma_histogram(data.uma_histogram_name); + EXPECT_TRUE(base::StartsWith(uma_histogram, "Ash.Accelerators.", + base::CompareCase::SENSITIVE)); + } +} + +} // namespace ash
diff --git a/ash/common/accelerators/ash_focus_manager_factory.cc b/ash/common/accelerators/ash_focus_manager_factory.cc new file mode 100644 index 0000000..058e0575 --- /dev/null +++ b/ash/common/accelerators/ash_focus_manager_factory.cc
@@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/ash_focus_manager_factory.h" + +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/wm_shell.h" +#include "base/memory/ptr_util.h" +#include "ui/views/focus/focus_manager.h" + +namespace ash { + +AshFocusManagerFactory::AshFocusManagerFactory() {} +AshFocusManagerFactory::~AshFocusManagerFactory() {} + +views::FocusManager* AshFocusManagerFactory::CreateFocusManager( + views::Widget* widget, + bool desktop_widget) { + return new views::FocusManager( + widget, + desktop_widget ? nullptr : base::WrapUnique<Delegate>(new Delegate)); +} + +bool AshFocusManagerFactory::Delegate::ProcessAccelerator( + const ui::Accelerator& accelerator) { + AcceleratorController* controller = WmShell::Get()->accelerator_controller(); + if (controller) + return controller->Process(accelerator); + return false; +} + +} // namespace ash
diff --git a/ash/common/accelerators/ash_focus_manager_factory.h b/ash/common/accelerators/ash_focus_manager_factory.h new file mode 100644 index 0000000..32d9e9a --- /dev/null +++ b/ash/common/accelerators/ash_focus_manager_factory.h
@@ -0,0 +1,38 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_ASH_FOCUS_MANAGER_FACTORY_H_ +#define ASH_COMMON_ACCELERATORS_ASH_FOCUS_MANAGER_FACTORY_H_ + +#include "base/macros.h" +#include "ui/views/focus/focus_manager_delegate.h" +#include "ui/views/focus/focus_manager_factory.h" + +namespace ash { + +// A factory class for creating a custom views::FocusManager object which +// supports Ash shortcuts. +class AshFocusManagerFactory : public views::FocusManagerFactory { + public: + AshFocusManagerFactory(); + ~AshFocusManagerFactory() override; + + protected: + // views::FocusManagerFactory overrides: + views::FocusManager* CreateFocusManager(views::Widget* widget, + bool desktop_widget) override; + + private: + class Delegate : public views::FocusManagerDelegate { + public: + // views::FocusManagerDelegate overrides: + bool ProcessAccelerator(const ui::Accelerator& accelerator) override; + }; + + DISALLOW_COPY_AND_ASSIGN(AshFocusManagerFactory); +}; + +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_ASH_FOCUS_MANAGER_FACTORY_H_
diff --git a/ash/common/accelerators/debug_commands.cc b/ash/common/accelerators/debug_commands.cc new file mode 100644 index 0000000..c84d84f --- /dev/null +++ b/ash/common/accelerators/debug_commands.cc
@@ -0,0 +1,215 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/debug_commands.h" + +#include "ash/common/accelerators/accelerator_commands.h" +#include "ash/common/ash_switches.h" +#include "ash/common/shell_delegate.h" +#include "ash/common/system/toast/toast_data.h" +#include "ash/common/system/toast/toast_manager.h" +#include "ash/common/wallpaper/wallpaper_controller.h" +#include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_properties.h" +#include "base/command_line.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/compositor/debug_utils.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/debug_utils.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace debug { +namespace { + +void HandlePrintLayerHierarchy() { + for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { + ui::Layer* layer = root->GetLayer(); + if (layer) + ui::PrintLayerHierarchy( + layer, root->GetRootWindowController()->GetLastMouseLocationInRoot()); + } +} + +void HandlePrintViewHierarchy() { + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + if (!active_window) + return; + views::Widget* widget = active_window->GetInternalWidget(); + if (!widget) + return; + views::PrintViewHierarchy(widget->GetRootView()); +} + +void PrintWindowHierarchy(const WmWindow* active_window, + WmWindow* window, + int indent, + std::ostringstream* out) { + std::string indent_str(indent, ' '); + std::string name(window->GetName()); + if (name.empty()) + name = "\"\""; + *out << indent_str << name << " (" << window << ")" + << " type=" << window->GetType() + << ((window == active_window) ? " [active] " : " ") + << (window->IsVisible() ? " visible " : " ") + << window->GetBounds().ToString() + << (window->aura_window()->GetProperty(kSnapChildrenToPixelBoundary) + ? " [snapped] " + : "") + << ", subpixel offset=" + << window->GetLayer()->subpixel_position_offset().ToString() << '\n'; + + for (WmWindow* child : window->GetChildren()) + PrintWindowHierarchy(active_window, child, indent + 3, out); +} + +void HandlePrintWindowHierarchy() { + WmWindow* active_window = WmShell::Get()->GetActiveWindow(); + WmWindow::Windows roots = WmShell::Get()->GetAllRootWindows(); + for (size_t i = 0; i < roots.size(); ++i) { + std::ostringstream out; + out << "RootWindow " << i << ":\n"; + PrintWindowHierarchy(active_window, roots[i], 0, &out); + // Error so logs can be collected from end-users. + LOG(ERROR) << out.str(); + } +} + +gfx::ImageSkia CreateWallpaperImage(SkColor fill, SkColor rect) { + // TODO(oshima): Consider adding a command line option to control wallpaper + // images for testing. The size is randomly picked. + gfx::Size image_size(1366, 768); + gfx::Canvas canvas(image_size, 1.0f, true); + canvas.DrawColor(fill); + cc::PaintFlags flags; + flags.setColor(rect); + flags.setStrokeWidth(10); + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setBlendMode(SkBlendMode::kSrcOver); + canvas.DrawRoundRect(gfx::Rect(image_size), 100, flags); + return gfx::ImageSkia(canvas.ExtractImageRep()); +} + +void HandleToggleWallpaperMode() { + static int index = 0; + WallpaperController* wallpaper_controller = + WmShell::Get()->wallpaper_controller(); + switch (++index % 4) { + case 0: + ash::WmShell::Get()->wallpaper_delegate()->InitializeWallpaper(); + break; + case 1: + wallpaper_controller->SetWallpaperImage( + CreateWallpaperImage(SK_ColorRED, SK_ColorBLUE), + wallpaper::WALLPAPER_LAYOUT_STRETCH); + break; + case 2: + wallpaper_controller->SetWallpaperImage( + CreateWallpaperImage(SK_ColorBLUE, SK_ColorGREEN), + wallpaper::WALLPAPER_LAYOUT_CENTER); + break; + case 3: + wallpaper_controller->SetWallpaperImage( + CreateWallpaperImage(SK_ColorGREEN, SK_ColorRED), + wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED); + break; + } +} + +void HandleToggleTouchpad() { + base::RecordAction(base::UserMetricsAction("Accel_Toggle_Touchpad")); + ash::WmShell::Get()->delegate()->ToggleTouchpad(); +} + +void HandleToggleTouchscreen() { + base::RecordAction(base::UserMetricsAction("Accel_Toggle_Touchscreen")); + ShellDelegate* delegate = WmShell::Get()->delegate(); + delegate->SetTouchscreenEnabledInPrefs( + !delegate->IsTouchscreenEnabledInPrefs(false /* use_local_state */), + false /* use_local_state */); + delegate->UpdateTouchscreenStatusFromPrefs(); +} + +void HandleToggleTouchView() { + MaximizeModeController* controller = + WmShell::Get()->maximize_mode_controller(); + controller->EnableMaximizeModeWindowManager( + !controller->IsMaximizeModeWindowManagerEnabled()); +} + +void HandleTriggerCrash() { + CHECK(false) << "Intentional crash via debug accelerator."; +} + +} // namespace + +void PrintUIHierarchies() { + // This is a separate command so the user only has to hit one key to generate + // all the logs. Developers use the individual dumps repeatedly, so keep + // those as separate commands to avoid spamming their logs. + HandlePrintLayerHierarchy(); + HandlePrintWindowHierarchy(); + HandlePrintViewHierarchy(); +} + +bool DebugAcceleratorsEnabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshDebugShortcuts); +} + +bool DeveloperAcceleratorsEnabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshDeveloperShortcuts); +} + +void PerformDebugActionIfEnabled(AcceleratorAction action) { + if (!DebugAcceleratorsEnabled()) + return; + + switch (action) { + case DEBUG_PRINT_LAYER_HIERARCHY: + HandlePrintLayerHierarchy(); + break; + case DEBUG_PRINT_VIEW_HIERARCHY: + HandlePrintViewHierarchy(); + break; + case DEBUG_PRINT_WINDOW_HIERARCHY: + HandlePrintWindowHierarchy(); + break; + case DEBUG_SHOW_TOAST: + WmShell::Get()->toast_manager()->Show( + ToastData("id", base::ASCIIToUTF16("Toast"), 5000 /* duration_ms */, + base::ASCIIToUTF16("Dismiss"))); + break; + case DEBUG_TOGGLE_TOUCH_PAD: + HandleToggleTouchpad(); + break; + case DEBUG_TOGGLE_TOUCH_SCREEN: + HandleToggleTouchscreen(); + break; + case DEBUG_TOGGLE_TOUCH_VIEW: + HandleToggleTouchView(); + break; + case DEBUG_TOGGLE_WALLPAPER_MODE: + HandleToggleWallpaperMode(); + break; + case DEBUG_TRIGGER_CRASH: + HandleTriggerCrash(); + break; + default: + break; + } +} + +} // namespace debug +} // namespace ash
diff --git a/ash/common/accelerators/debug_commands.h b/ash/common/accelerators/debug_commands.h new file mode 100644 index 0000000..3ef73ae4 --- /dev/null +++ b/ash/common/accelerators/debug_commands.h
@@ -0,0 +1,36 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_DEBUG_COMMANDS_H_ +#define ASH_COMMON_ACCELERATORS_DEBUG_COMMANDS_H_ + +#include "ash/ash_export.h" +#include "ash/common/accelerators/accelerator_table.h" + +// This file contains implementations of commands that are used only when +// debugging. +// +// NOTE: these commands may be enabled in about:flags, so that they may be +// available at run time. +namespace ash { +namespace debug { + +// Print the views::View, ui::Layer and aura::Window hierarchies. This may be +// useful in debugging user reported bugs. +ASH_EXPORT void PrintUIHierarchies(); + +// Returns true if debug accelerators are enabled. +ASH_EXPORT bool DebugAcceleratorsEnabled(); + +// Returns true if developer accelerators are enabled. +ASH_EXPORT bool DeveloperAcceleratorsEnabled(); + +// Performs |action| if |action| belongs to a debug-only accelerator and debug +// accelerators are enabled. +ASH_EXPORT void PerformDebugActionIfEnabled(AcceleratorAction action); + +} // namespace debug +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_DEBUG_COMMANDS_H_
diff --git a/ash/common/accelerators/exit_warning_handler.cc b/ash/common/accelerators/exit_warning_handler.cc new file mode 100644 index 0000000..9f6b970 --- /dev/null +++ b/ash/common/accelerators/exit_warning_handler.cc
@@ -0,0 +1,175 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/accelerators/exit_warning_handler.h" + +#include "ash/common/shell_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/text_utils.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { +namespace { + +const int64_t kTimeOutMilliseconds = 2000; +// Color of the text of the warning message. +const SkColor kTextColor = SK_ColorWHITE; +// Color of the window background. +const SkColor kWindowBackgroundColor = SkColorSetARGB(0xC0, 0x0, 0x0, 0x0); +// Radius of the rounded corners of the window. +const int kWindowCornerRadius = 2; +const int kHorizontalMarginAroundText = 100; +const int kVerticalMarginAroundText = 100; + +class ExitWarningWidgetDelegateView : public views::WidgetDelegateView { + public: + ExitWarningWidgetDelegateView() + : text_(l10n_util::GetStringUTF16(IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT)), + accessible_name_(l10n_util::GetStringUTF16( + IDS_ASH_SIGN_OUT_WARNING_POPUP_TEXT_ACCESSIBLE)), + text_width_(0), + width_(0), + height_(0) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + const gfx::FontList& font_list = + rb.GetFontList(ui::ResourceBundle::LargeFont); + text_width_ = gfx::GetStringWidth(text_, font_list); + width_ = text_width_ + kHorizontalMarginAroundText; + height_ = font_list.GetHeight() + kVerticalMarginAroundText; + views::Label* label = new views::Label(); + label->SetText(text_); + label->SetHorizontalAlignment(gfx::ALIGN_CENTER); + label->SetFontList(font_list); + label->SetEnabledColor(kTextColor); + label->SetDisabledColor(kTextColor); + label->SetAutoColorReadabilityEnabled(false); + label->SetSubpixelRenderingEnabled(false); + AddChildView(label); + SetLayoutManager(new views::FillLayout); + } + + gfx::Size GetPreferredSize() const override { + return gfx::Size(width_, height_); + } + + void OnPaint(gfx::Canvas* canvas) override { + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(kWindowBackgroundColor); + canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, flags); + views::WidgetDelegateView::OnPaint(canvas); + } + + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->SetName(accessible_name_); + node_data->role = ui::AX_ROLE_ALERT; + } + + private: + base::string16 text_; + base::string16 accessible_name_; + int text_width_; + int width_; + int height_; + + DISALLOW_COPY_AND_ASSIGN(ExitWarningWidgetDelegateView); +}; + +} // namespace + +ExitWarningHandler::ExitWarningHandler() + : state_(IDLE), stub_timer_for_test_(false) {} + +ExitWarningHandler::~ExitWarningHandler() { + // Note: If a timer is outstanding, it is stopped in its destructor. + Hide(); +} + +void ExitWarningHandler::HandleAccelerator() { + switch (state_) { + case IDLE: + state_ = WAIT_FOR_DOUBLE_PRESS; + Show(); + StartTimer(); + WmShell::Get()->RecordUserMetricsAction(UMA_ACCEL_EXIT_FIRST_Q); + break; + case WAIT_FOR_DOUBLE_PRESS: + state_ = EXITING; + CancelTimer(); + Hide(); + WmShell::Get()->RecordUserMetricsAction(UMA_ACCEL_EXIT_SECOND_Q); + WmShell::Get()->delegate()->Exit(); + break; + case EXITING: + break; + } +} + +void ExitWarningHandler::TimerAction() { + Hide(); + if (state_ == WAIT_FOR_DOUBLE_PRESS) + state_ = IDLE; +} + +void ExitWarningHandler::StartTimer() { + if (stub_timer_for_test_) + return; + timer_.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kTimeOutMilliseconds), this, + &ExitWarningHandler::TimerAction); +} + +void ExitWarningHandler::CancelTimer() { + timer_.Stop(); +} + +void ExitWarningHandler::Show() { + if (widget_) + return; + WmWindow* root_window = WmShell::Get()->GetRootWindowForNewWindows(); + ExitWarningWidgetDelegateView* delegate = new ExitWarningWidgetDelegateView; + gfx::Size rs = root_window->GetBounds().size(); + gfx::Size ps = delegate->GetPreferredSize(); + gfx::Rect bounds((rs.width() - ps.width()) / 2, + (rs.height() - ps.height()) / 3, ps.width(), ps.height()); + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.accept_events = false; + params.keep_on_top = true; + params.remove_standard_frame = true; + params.delegate = delegate; + params.bounds = bounds; + params.name = "ExitWarningWindow"; + widget_.reset(new views::Widget); + root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + widget_.get(), kShellWindowId_SettingBubbleContainer, ¶ms); + widget_->Init(params); + widget_->Show(); + + delegate->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); +} + +void ExitWarningHandler::Hide() { + widget_.reset(); +} + +} // namespace ash
diff --git a/ash/common/accelerators/exit_warning_handler.h b/ash/common/accelerators/exit_warning_handler.h new file mode 100644 index 0000000..d992ba9 --- /dev/null +++ b/ash/common/accelerators/exit_warning_handler.h
@@ -0,0 +1,84 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_ACCELERATORS_EXIT_WARNING_HANDLER_H_ +#define ASH_COMMON_ACCELERATORS_EXIT_WARNING_HANDLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/timer/timer.h" +#include "ui/base/accelerators/accelerator.h" + +namespace views { +class Widget; +} + +namespace ash { + +// In order to avoid accidental exits when the user presses the exit shortcut by +// mistake, we require that the user press it twice within a short period of +// time. During that time we show a popup informing the user of this. +// +// Notes: +// +// The corresponding accelerator must not be repeatable (see kRepeatableActions +// in accelerator_table.cc). Otherwise, the "Double Press Exit" will be +// activated just by holding it down, i.e. probably every time. +// +// State Transition Diagrams: +// +// IDLE +// | Press +// WAIT_FOR_DOUBLE_PRESS action: show ui & start timers +// | Press (before time limit ) +// EXITING action: hide ui, stop timer, exit +// +// IDLE +// | Press +// WAIT_FOR_DOUBLE_PRESS action: show ui & start timers +// | T timer expires +// IDLE action: hide ui +// + +class AcceleratorControllerTest; + +class ASH_EXPORT ExitWarningHandler { + public: + ExitWarningHandler(); + + ~ExitWarningHandler(); + + // Handles accelerator for exit (Ctrl-Shift-Q). + void HandleAccelerator(); + + private: + friend class AcceleratorControllerTest; + + enum State { IDLE, WAIT_FOR_DOUBLE_PRESS, EXITING }; + + // Performs actions when the time limit is exceeded. + void TimerAction(); + + void StartTimer(); + void CancelTimer(); + + void Show(); + void Hide(); + + State state_; + std::unique_ptr<views::Widget> widget_; + base::OneShotTimer timer_; + + // Flag to suppress starting the timer for testing. For test we call + // TimerAction() directly to simulate the expiration of the timer. + bool stub_timer_for_test_; + + DISALLOW_COPY_AND_ASSIGN(ExitWarningHandler); +}; + +} // namespace ash + +#endif // ASH_COMMON_ACCELERATORS_EXIT_WARNING_HANDLER_H_
diff --git a/ash/common/devtools/ash_devtools_unittest.cc b/ash/common/devtools/ash_devtools_unittest.cc index 9aa0192..7c96bff 100644 --- a/ash/common/devtools/ash_devtools_unittest.cc +++ b/ash/common/devtools/ash_devtools_unittest.cc
@@ -4,10 +4,10 @@ #include "ash/common/devtools/ash_devtools_css_agent.h" #include "ash/common/devtools/ash_devtools_dom_agent.h" +#include "ash/common/test/ash_test.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" -#include "ash/test/ash_test.h" #include "base/memory/ptr_util.h" #include "base/strings/stringprintf.h" #include "ui/display/display.h"
diff --git a/ash/common/drag_drop/OWNERS b/ash/common/drag_drop/OWNERS new file mode 100644 index 0000000..d231d19d --- /dev/null +++ b/ash/common/drag_drop/OWNERS
@@ -0,0 +1 @@ +mfomitchev@chromium.org
diff --git a/ash/common/drag_drop/drag_image_view.cc b/ash/common/drag_drop/drag_image_view.cc new file mode 100644 index 0000000..1306bf1 --- /dev/null +++ b/ash/common/drag_drop/drag_image_view.cc
@@ -0,0 +1,208 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/drag_drop/drag_image_view.h" + +#include <memory> + +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "skia/ext/image_operations.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/display/display.h" +#include "ui/gfx/canvas.h" +#include "ui/resources/grit/ui_resources.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { +using views::Widget; + +std::unique_ptr<Widget> CreateDragWidget(WmWindow* root_window) { + std::unique_ptr<Widget> drag_widget(new Widget); + Widget::InitParams params; + params.type = Widget::InitParams::TYPE_TOOLTIP; + params.name = "DragWidget"; + params.keep_on_top = true; + params.accept_events = false; + params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE; + params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; + root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + drag_widget.get(), kShellWindowId_DragImageAndTooltipContainer, ¶ms); + drag_widget->Init(params); + drag_widget->SetOpacity(1.f); + return drag_widget; +} + +} // namespace + +DragImageView::DragImageView(WmWindow* root_window, + ui::DragDropTypes::DragEventSource event_source) + : drag_event_source_(event_source), + touch_drag_operation_(ui::DragDropTypes::DRAG_NONE) { + DCHECK(root_window); + widget_ = CreateDragWidget(root_window); + widget_->SetContentsView(this); + widget_->SetAlwaysOnTop(true); + + // We are owned by the DragDropController. + set_owned_by_client(); +} + +DragImageView::~DragImageView() { + widget_->Hide(); +} + +void DragImageView::SetBoundsInScreen(const gfx::Rect& bounds) { + drag_image_size_ = bounds.size(); + widget_->SetBounds(bounds); +} + +void DragImageView::SetScreenPosition(const gfx::Point& position) { + widget_->SetBounds( + gfx::Rect(position, widget_->GetWindowBoundsInScreen().size())); +} + +gfx::Rect DragImageView::GetBoundsInScreen() const { + return widget_->GetWindowBoundsInScreen(); +} + +void DragImageView::SetWidgetVisible(bool visible) { + if (visible != widget_->IsVisible()) { + if (visible) + widget_->Show(); + else + widget_->Hide(); + } +} + +void DragImageView::SetTouchDragOperationHintOff() { + // Simply set the drag type to non-touch so that no hint is drawn. + drag_event_source_ = ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE; + + // This disables the drag hint image. This should reduce the widget size if + // the drag image is smaller than the drag hint image, so we set new bounds. + gfx::Rect new_bounds = GetBoundsInScreen(); + new_bounds.set_size(drag_image_size_); + SetBoundsInScreen(new_bounds); + SchedulePaint(); +} + +void DragImageView::SetTouchDragOperation(int operation) { + if (touch_drag_operation_ == operation) + return; + touch_drag_operation_ = operation; + SchedulePaint(); +} + +void DragImageView::SetTouchDragOperationHintPosition( + const gfx::Point& position) { + if (touch_drag_operation_indicator_position_ == position) + return; + touch_drag_operation_indicator_position_ = position; + SchedulePaint(); +} + +void DragImageView::SetOpacity(float visibility) { + DCHECK_GE(visibility, 0.0f); + DCHECK_LE(visibility, 1.0f); + widget_->SetOpacity(visibility); +} + +void DragImageView::OnPaint(gfx::Canvas* canvas) { + if (GetImage().isNull()) + return; + + // |drag_image_size_| is in DIP. + // ImageSkia::size() also returns the size in DIP. + if (GetImage().size() == drag_image_size_) { + canvas->DrawImageInt(GetImage(), 0, 0); + } else { + WmWindow* window = WmWindow::Get(widget_->GetNativeWindow()); + const float device_scale = + window->GetDisplayNearestWindow().device_scale_factor(); + // The drag image already has device scale factor applied. But + // |drag_image_size_| is in DIP units. + gfx::Size drag_image_size_pixels = + gfx::ScaleToRoundedSize(drag_image_size_, device_scale); + gfx::ImageSkiaRep image_rep = GetImage().GetRepresentation(device_scale); + if (image_rep.is_null()) + return; + SkBitmap scaled = skia::ImageOperations::Resize( + image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3, + drag_image_size_pixels.width(), drag_image_size_pixels.height()); + gfx::ImageSkia image_skia(gfx::ImageSkiaRep(scaled, device_scale)); + canvas->DrawImageInt(image_skia, 0, 0); + } + + gfx::Image* drag_hint = DragHint(); + if (!ShouldDrawDragHint() || drag_hint->IsEmpty()) + return; + + // Make sure drag hint image is positioned within the widget. + gfx::Size drag_hint_size = drag_hint->Size(); + gfx::Point drag_hint_position = touch_drag_operation_indicator_position_; + drag_hint_position.Offset(-drag_hint_size.width() / 2, 0); + gfx::Rect drag_hint_bounds(drag_hint_position, drag_hint_size); + + gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size(); + drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size)); + + // Draw image. + canvas->DrawImageInt(*(drag_hint->ToImageSkia()), drag_hint_bounds.x(), + drag_hint_bounds.y()); +} + +gfx::Image* DragImageView::DragHint() const { + // Select appropriate drag hint. + gfx::Image* drag_hint = + &ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_TOUCH_DRAG_TIP_NODROP); + if (touch_drag_operation_ & ui::DragDropTypes::DRAG_COPY) { + drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_TOUCH_DRAG_TIP_COPY); + } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_MOVE) { + drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_TOUCH_DRAG_TIP_MOVE); + } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_LINK) { + drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_TOUCH_DRAG_TIP_LINK); + } + return drag_hint; +} + +bool DragImageView::ShouldDrawDragHint() const { + return drag_event_source_ == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH; +} + +gfx::Size DragImageView::GetMinimumSize() const { + gfx::Size minimum_size = drag_image_size_; + if (ShouldDrawDragHint()) + minimum_size.SetToMax(DragHint()->Size()); + return minimum_size; +} + +void DragImageView::Layout() { + View::Layout(); + + // Only consider resizing the widget for the drag hint image if we are in a + // touch initiated drag. + gfx::Image* drag_hint = DragHint(); + if (!ShouldDrawDragHint() || drag_hint->IsEmpty()) + return; + + gfx::Size drag_hint_size = drag_hint->Size(); + + // Enlarge widget if required to fit the drag hint image. + gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size(); + if (drag_hint_size.width() > widget_size.width() || + drag_hint_size.height() > widget_size.height()) { + widget_size.SetToMax(drag_hint_size); + widget_->SetSize(widget_size); + } +} + +} // namespace ash
diff --git a/ash/common/drag_drop/drag_image_view.h b/ash/common/drag_drop/drag_image_view.h new file mode 100644 index 0000000..de6e4d5 --- /dev/null +++ b/ash/common/drag_drop/drag_image_view.h
@@ -0,0 +1,103 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_DRAG_DROP_DRAG_IMAGE_VIEW_H_ +#define ASH_COMMON_DRAG_DROP_DRAG_IMAGE_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/base/dragdrop/drag_drop_types.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/controls/image_view.h" + +namespace gfx { +class Image; +} + +namespace views { +class Widget; +} + +namespace ash { + +class WmWindow; + +// This class allows to show a (native) view always on top of everything. It +// does this by creating a widget and setting the content as the given view. The +// caller can then use this object to freely move / drag it around on the +// desktop in screen coordinates. +class ASH_EXPORT DragImageView : public views::ImageView { + public: + // |root_window| is the root window on which to create the drag image widget. + // |source| is the event source that started this drag drop operation (touch + // or mouse). It is used to determine attributes of the drag image such as + // whether to show drag operation hint on top of the image. + DragImageView(WmWindow* root_window, + ui::DragDropTypes::DragEventSource source); + ~DragImageView() override; + + // Sets the bounds of the native widget in screen + // coordinates. + // TODO(oshima): Looks like this is root window's + // coordinate. Change this to screen's coordinate. + void SetBoundsInScreen(const gfx::Rect& bounds); + + // Sets the position of the native widget. + void SetScreenPosition(const gfx::Point& position); + + // Gets the image position in screen coordinates. + gfx::Rect GetBoundsInScreen() const; + + // Sets the visibility of the native widget. + void SetWidgetVisible(bool visible); + + // For touch drag drop, we show a hint corresponding to the drag operation + // (since no mouse cursor is visible). These functions set the hint + // parameters. + void SetTouchDragOperationHintOff(); + + // |operation| is a bit field indicating allowable drag operations from + // ui::DragDropTypes::DragOperation. + void SetTouchDragOperation(int operation); + void SetTouchDragOperationHintPosition(const gfx::Point& position); + + // Sets the |opacity| of the image view between 0.0 and 1.0. + void SetOpacity(float opacity); + + gfx::Size GetMinimumSize() const override; + + private: + gfx::Image* DragHint() const; + // Drag hint images are only drawn when the input source is touch. + bool ShouldDrawDragHint() const; + + // Overridden from views::ImageView. + void OnPaint(gfx::Canvas* canvas) override; + + // Overridden from views::view + void Layout() override; + + std::unique_ptr<views::Widget> widget_; + + // Save the requested drag image size. We may need to display a drag hint + // image, which potentially expands |widget_|'s size. That drag hint image + // may be disabled (e.g. during the drag cancel animation). In that case, + // we need to know the originally requested size to render the drag image. + gfx::Size drag_image_size_; + + ui::DragDropTypes::DragEventSource drag_event_source_; + + // Bitmask of ui::DragDropTypes::DragOperation values. + int touch_drag_operation_; + gfx::Point touch_drag_operation_indicator_position_; + + DISALLOW_COPY_AND_ASSIGN(DragImageView); +}; + +} // namespace ash + +#endif // ASH_COMMON_DRAG_DROP_DRAG_IMAGE_VIEW_H_
diff --git a/ash/common/drag_drop/drag_image_view_unittest.cc b/ash/common/drag_drop/drag_image_view_unittest.cc new file mode 100644 index 0000000..e74d1bc --- /dev/null +++ b/ash/common/drag_drop/drag_image_view_unittest.cc
@@ -0,0 +1,77 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/drag_drop/drag_image_view.h" + +#include "ash/common/test/ash_test.h" +#include "ui/base/dragdrop/drag_drop_types.h" + +namespace ash { +namespace test { + +using DragDropImageTest = AshTest; + +TEST_F(DragDropImageTest, SetBoundsConsidersDragHintForTouch) { + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow()); + DragImageView drag_image_view( + window_owner->window(), + ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_TOUCH); + + gfx::Size minimum_size = drag_image_view.GetMinimumSize(); + gfx::Point new_pos(5, 5); + + if (!minimum_size.IsEmpty()) { + // Expect that the view is at least the size of the drag hint image. + gfx::Rect small_bounds(0, 0, 1, 1); + drag_image_view.SetBoundsInScreen(small_bounds); + EXPECT_EQ(gfx::Rect(minimum_size), drag_image_view.GetBoundsInScreen()); + + // Expect that we can change the position without affecting the bounds. + drag_image_view.SetScreenPosition(new_pos); + EXPECT_EQ(gfx::Rect(new_pos, minimum_size), + drag_image_view.GetBoundsInScreen()); + } + + // Expect that we can resize the view normally. + gfx::Rect large_bounds(0, 0, minimum_size.width() + 1, + minimum_size.height() + 1); + drag_image_view.SetBoundsInScreen(large_bounds); + EXPECT_EQ(large_bounds, drag_image_view.GetBoundsInScreen()); + // Expect that we can change the position without affecting the bounds. + drag_image_view.SetScreenPosition(new_pos); + EXPECT_EQ(gfx::Rect(new_pos, large_bounds.size()), + drag_image_view.GetBoundsInScreen()); +} + +TEST_F(DragDropImageTest, SetBoundsIgnoresDragHintForMouse) { + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow()); + DragImageView drag_image_view( + window_owner->window(), + ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_MOUSE); + + // Expect no drag hint image. + gfx::Rect small_bounds(0, 0, 1, 1); + drag_image_view.SetBoundsInScreen(small_bounds); + EXPECT_EQ(small_bounds, drag_image_view.GetBoundsInScreen()); + EXPECT_EQ(drag_image_view.GetMinimumSize(), + drag_image_view.GetBoundsInScreen().size()); + + gfx::Point new_pos(5, 5); + // Expect that we can change the position without affecting the bounds. + drag_image_view.SetScreenPosition(new_pos); + EXPECT_EQ(gfx::Rect(new_pos, small_bounds.size()), + drag_image_view.GetBoundsInScreen()); + + // Expect that we can resize the view. + gfx::Rect large_bounds(0, 0, 100, 100); + drag_image_view.SetBoundsInScreen(large_bounds); + EXPECT_EQ(large_bounds, drag_image_view.GetBoundsInScreen()); + // Expect that we can change the position without affecting the bounds. + drag_image_view.SetScreenPosition(new_pos); + EXPECT_EQ(gfx::Rect(new_pos, large_bounds.size()), + drag_image_view.GetBoundsInScreen()); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/focus_cycler.cc b/ash/common/focus_cycler.cc index 47ef19b..5ef50d4 100644 --- a/ash/common/focus_cycler.cc +++ b/ash/common/focus_cycler.cc
@@ -4,10 +4,10 @@ #include "ash/common/focus_cycler.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" #include "ui/views/accessible_pane_view.h" #include "ui/views/focus/focus_search.h" #include "ui/views/widget/widget.h"
diff --git a/ash/common/frame/OWNERS b/ash/common/frame/OWNERS new file mode 100644 index 0000000..e710530 --- /dev/null +++ b/ash/common/frame/OWNERS
@@ -0,0 +1 @@ +pkotwicz@chromium.org
diff --git a/ash/common/frame/caption_buttons/caption_button_types.h b/ash/common/frame/caption_buttons/caption_button_types.h new file mode 100644 index 0000000..ca067be --- /dev/null +++ b/ash/common/frame/caption_buttons/caption_button_types.h
@@ -0,0 +1,25 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_ +#define ASH_COMMON_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_ + +namespace ash { + +// These are the icon types that a caption button can have. The size button's +// action (SnapType) can be different from its icon. +enum CaptionButtonIcon { + CAPTION_BUTTON_ICON_MINIMIZE, + CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, + CAPTION_BUTTON_ICON_CLOSE, + CAPTION_BUTTON_ICON_LEFT_SNAPPED, + CAPTION_BUTTON_ICON_RIGHT_SNAPPED, + CAPTION_BUTTON_ICON_BACK, + CAPTION_BUTTON_ICON_LOCATION, + CAPTION_BUTTON_ICON_COUNT +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_
diff --git a/ash/common/frame/caption_buttons/frame_caption_button.cc b/ash/common/frame/caption_buttons/frame_caption_button.cc new file mode 100644 index 0000000..0d26e0d --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_caption_button.cc
@@ -0,0 +1,191 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/caption_buttons/frame_caption_button.h" + +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/animation/throb_animation.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" + +namespace ash { + +namespace { + +// The duration of the crossfade animation when swapping the button's images. +const int kSwapImagesAnimationDurationMs = 200; + +// The duration of the fade out animation of the old icon during a crossfade +// animation as a ratio of |kSwapImagesAnimationDurationMs|. +const float kFadeOutRatio = 0.5f; + +// The alpha to draw inactive icons with. +const float kInactiveIconAlpha = 0.2f; + +// The colors and alpha values used for the button background hovered and +// pressed states. +// TODO(tdanderson|estade): Request these colors from ThemeProvider. +const int kHoveredAlpha = 0x14; +const int kPressedAlpha = 0x24; + +} // namespace + +// static +const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton"; + +FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener, + CaptionButtonIcon icon) + : CustomButton(listener), + icon_(icon), + paint_as_active_(false), + use_light_images_(false), + alpha_(255), + swap_images_animation_(new gfx::SlideAnimation(this)) { + set_animate_on_state_change(true); + swap_images_animation_->Reset(1); + + // Do not flip the gfx::Canvas passed to the OnPaint() method. The snap left + // and snap right button icons should not be flipped. The other icons are + // horizontally symmetrical. +} + +FrameCaptionButton::~FrameCaptionButton() {} + +void FrameCaptionButton::SetImage(CaptionButtonIcon icon, + Animate animate, + const gfx::VectorIcon& icon_definition) { + gfx::ImageSkia new_icon_image = gfx::CreateVectorIcon( + icon_definition, + use_light_images_ ? SK_ColorWHITE : gfx::kChromeIconGrey); + + // The early return is dependent on |animate| because callers use SetImage() + // with ANIMATE_NO to progress the crossfade animation to the end. + if (icon == icon_ && + (animate == ANIMATE_YES || !swap_images_animation_->is_animating()) && + new_icon_image.BackedBySameObjectAs(icon_image_)) { + return; + } + + if (animate == ANIMATE_YES) + crossfade_icon_image_ = icon_image_; + + icon_ = icon; + icon_definition_ = &icon_definition; + icon_image_ = new_icon_image; + + if (animate == ANIMATE_YES) { + swap_images_animation_->Reset(0); + swap_images_animation_->SetSlideDuration(kSwapImagesAnimationDurationMs); + swap_images_animation_->Show(); + } else { + swap_images_animation_->Reset(1); + } + PreferredSizeChanged(); + SchedulePaint(); +} + +bool FrameCaptionButton::IsAnimatingImageSwap() const { + return swap_images_animation_->is_animating(); +} + +void FrameCaptionButton::SetAlpha(int alpha) { + if (alpha_ != alpha) { + alpha_ = alpha; + SchedulePaint(); + } +} + +gfx::Size FrameCaptionButton::GetPreferredSize() const { + return size_; +} + +const char* FrameCaptionButton::GetClassName() const { + return kViewClassName; +} + +void FrameCaptionButton::OnPaint(gfx::Canvas* canvas) { + SkAlpha bg_alpha = SK_AlphaTRANSPARENT; + if (hover_animation().is_animating()) + bg_alpha = hover_animation().CurrentValueBetween(0, kHoveredAlpha); + else if (state() == STATE_HOVERED) + bg_alpha = kHoveredAlpha; + else if (state() == STATE_PRESSED) + bg_alpha = kPressedAlpha; + + if (bg_alpha != SK_AlphaTRANSPARENT) { + canvas->DrawColor(SkColorSetA( + use_light_images_ ? SK_ColorWHITE : SK_ColorBLACK, bg_alpha)); + } + + int icon_alpha = swap_images_animation_->CurrentValueBetween(0, 255); + int crossfade_icon_alpha = 0; + if (icon_alpha < static_cast<int>(kFadeOutRatio * 255)) + crossfade_icon_alpha = static_cast<int>(255 - icon_alpha / kFadeOutRatio); + + if (crossfade_icon_alpha > 0 && !crossfade_icon_image_.isNull()) { + gfx::Canvas icon_canvas(icon_image_.size(), canvas->image_scale(), false); + cc::PaintFlags flags; + flags.setAlpha(icon_alpha); + icon_canvas.DrawImageInt(icon_image_, 0, 0, flags); + + flags.setAlpha(crossfade_icon_alpha); + flags.setBlendMode(SkBlendMode::kPlus); + icon_canvas.DrawImageInt(crossfade_icon_image_, 0, 0, flags); + + PaintCentered(canvas, gfx::ImageSkia(icon_canvas.ExtractImageRep()), + alpha_); + } else { + if (!swap_images_animation_->is_animating()) + icon_alpha = alpha_; + PaintCentered(canvas, icon_image_, icon_alpha); + } +} + +void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) { + // CustomButton does not become pressed when the user drags off and then back + // onto the button. Make FrameCaptionButton pressed in this case because this + // behavior is more consistent with AlternateFrameSizeButton. + if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || + event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { + if (HitTestPoint(event->location())) { + SetState(STATE_PRESSED); + RequestFocus(); + event->StopPropagation(); + } else { + SetState(STATE_NORMAL); + } + } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { + if (HitTestPoint(event->location())) { + SetState(STATE_HOVERED); + NotifyClick(*event); + event->StopPropagation(); + } + } + CustomButton::OnGestureEvent(event); +} + +void FrameCaptionButton::PaintCentered(gfx::Canvas* canvas, + const gfx::ImageSkia& to_center, + int alpha) { + if (!paint_as_active_) { + // Paint icons as active when they are hovered over or pressed. + double inactive_alpha = kInactiveIconAlpha; + if (hover_animation().is_animating()) { + inactive_alpha = + hover_animation().CurrentValueBetween(inactive_alpha, 1.0f); + } else if (state() == STATE_PRESSED || state() == STATE_HOVERED) { + inactive_alpha = 1.0f; + } + alpha *= inactive_alpha; + } + + cc::PaintFlags flags; + flags.setAlpha(alpha); + canvas->DrawImageInt(to_center, (width() - to_center.width()) / 2, + (height() - to_center.height()) / 2, flags); +} + +} // namespace ash
diff --git a/ash/common/frame/caption_buttons/frame_caption_button.h b/ash/common/frame/caption_buttons/frame_caption_button.h new file mode 100644 index 0000000..8b6df285 --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_caption_button.h
@@ -0,0 +1,106 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_ +#define ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/frame/caption_buttons/caption_button_types.h" +#include "base/macros.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/controls/button/custom_button.h" + +namespace gfx { +class SlideAnimation; +struct VectorIcon; +} + +namespace ash { + +// Base class for the window caption buttons (minimize, maximize, restore, +// close). +class ASH_EXPORT FrameCaptionButton : public views::CustomButton { + public: + enum Animate { ANIMATE_YES, ANIMATE_NO }; + + static const char kViewClassName[]; + + FrameCaptionButton(views::ButtonListener* listener, CaptionButtonIcon icon); + ~FrameCaptionButton() override; + + // Sets the image to use to paint the button. If |animate| is ANIMATE_YES, + // the button crossfades to the new visuals. If the image matches the one + // currently used by the button and |animate| is ANIMATE_NO, the crossfade + // animation is progressed to the end. + void SetImage(CaptionButtonIcon icon, + Animate animate, + const gfx::VectorIcon& icon_image); + + // Returns true if the button is crossfading to new visuals set in + // SetImage(). + bool IsAnimatingImageSwap() const; + + // Sets the alpha to use for painting. Used to animate visibility changes. + void SetAlpha(int alpha); + + // views::View overrides: + gfx::Size GetPreferredSize() const override; + const char* GetClassName() const override; + void OnPaint(gfx::Canvas* canvas) override; + + void set_paint_as_active(bool paint_as_active) { + paint_as_active_ = paint_as_active; + } + + void set_use_light_images(bool light) { use_light_images_ = light; } + + CaptionButtonIcon icon() const { return icon_; } + + void set_size(const gfx::Size& size) { size_ = size; } + + protected: + // views::CustomButton override: + void OnGestureEvent(ui::GestureEvent* event) override; + + private: + // Paints |to_center| centered within the button with |alpha|. + void PaintCentered(gfx::Canvas* canvas, + const gfx::ImageSkia& to_center, + int alpha); + + // The button's current icon. + CaptionButtonIcon icon_; + + // The size of the button. + gfx::Size size_; + + // Whether the button should be painted as active. + bool paint_as_active_; + + // Whether to paint in a lighter color (for use on dark backgrounds). + bool use_light_images_; + + // Current alpha to use for painting. + int alpha_; + + // The image id (kept for the purposes of testing) and image used to paint the + // button's icon. + const gfx::VectorIcon* icon_definition_ = nullptr; + gfx::ImageSkia icon_image_; + + // The icon image to crossfade from. + gfx::ImageSkia crossfade_icon_image_; + + // Crossfade animation started when the button's images are changed by + // SetImage(). + std::unique_ptr<gfx::SlideAnimation> swap_images_animation_; + + DISALLOW_COPY_AND_ASSIGN(FrameCaptionButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc new file mode 100644 index 0000000..3539a04 --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -0,0 +1,412 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" + +#include <cmath> +#include <map> + +#include "ash/common/frame/caption_buttons/frame_caption_button.h" +#include "ash/common/frame/caption_buttons/frame_size_button.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ui/base/hit_test.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/animation/tween.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/vector_icon_types.h" +#include "ui/strings/grit/ui_strings.h" // Accessibility names +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +namespace { + +// Duration of the animation of the position of |minimize_button_|. +const int kPositionAnimationDurationMs = 500; + +// Duration of the animation of the alpha of |size_button_|. +const int kAlphaAnimationDurationMs = 250; + +// Delay during |maximize_mode_animation_| hide to wait before beginning to +// animate the position of |minimize_button_|. +const int kHidePositionDelayMs = 100; + +// Duration of |maximize_mode_animation_| hiding. +// Hiding size button 250 +// |------------------------| +// Delay 100 Slide minimize button 500 +// |---------|-------------------------------------------------| +const int kHideAnimationDurationMs = + kHidePositionDelayMs + kPositionAnimationDurationMs; + +// Delay during |maximize_mode_animation_| show to wait before beginning to +// animate the alpha of |size_button_|. +const int kShowAnimationAlphaDelayMs = 100; + +// Duration of |maximize_mode_animation_| showing. +// Slide minimize button 500 +// |-------------------------------------------------| +// Delay 100 Show size button 250 +// |---------|-----------------------| +const int kShowAnimationDurationMs = kPositionAnimationDurationMs; + +// Value of |maximize_mode_animation_| showing to begin animating alpha of +// |size_button_|. +float SizeButtonShowStartValue() { + return static_cast<float>(kShowAnimationAlphaDelayMs) / + kShowAnimationDurationMs; +} + +// Amount of |maximize_mode_animation_| showing to animate the alpha of +// |size_button_|. +float SizeButtonShowDuration() { + return static_cast<float>(kAlphaAnimationDurationMs) / + kShowAnimationDurationMs; +} + +// Amount of |maximize_mode_animation_| hiding to animate the alpha of +// |size_button_|. +float SizeButtonHideDuration() { + return static_cast<float>(kAlphaAnimationDurationMs) / + kHideAnimationDurationMs; +} + +// Value of |maximize_mode_animation_| hiding to begin animating the position of +// |minimize_button_|. +float HidePositionStartValue() { + return 1.0f - + static_cast<float>(kHidePositionDelayMs) / kHideAnimationDurationMs; +} + +// Converts |point| from |src| to |dst| and hittests against |dst|. +bool ConvertPointToViewAndHitTest(const views::View* src, + const views::View* dst, + const gfx::Point& point) { + gfx::Point converted(point); + views::View::ConvertPointToTarget(src, dst, &converted); + return dst->HitTestPoint(converted); +} + +// Bounds animation values to the range 0.0 - 1.0. Allows for mapping of offset +// animations to the expected range so that gfx::Tween::CalculateValue() can be +// used. +double CapAnimationValue(double value) { + return std::min(1.0, std::max(0.0, value)); +} + +} // namespace + +// static +const char FrameCaptionButtonContainerView::kViewClassName[] = + "FrameCaptionButtonContainerView"; + +FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( + views::Widget* frame) + : frame_(frame), + minimize_button_(NULL), + size_button_(NULL), + close_button_(NULL) { + bool size_button_visibility = ShouldSizeButtonBeVisible(); + maximize_mode_animation_.reset(new gfx::SlideAnimation(this)); + maximize_mode_animation_->SetTweenType(gfx::Tween::LINEAR); + + // Ensure animation tracks visibility of size button. + if (size_button_visibility) + maximize_mode_animation_->Reset(1.0f); + + // Insert the buttons left to right. + minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); + minimize_button_->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); + minimize_button_->SetVisible(frame_->widget_delegate()->CanMinimize()); + AddChildView(minimize_button_); + + size_button_ = new FrameSizeButton(this, frame, this); + size_button_->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); + size_button_->SetVisible(size_button_visibility); + AddChildView(size_button_); + + close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); + close_button_->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); + AddChildView(close_button_); +} + +FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {} + +void FrameCaptionButtonContainerView::TestApi::EndAnimations() { + container_view_->maximize_mode_animation_->End(); +} + +void FrameCaptionButtonContainerView::SetButtonImage( + CaptionButtonIcon icon, + const gfx::VectorIcon& icon_definition) { + button_icon_map_[icon] = &icon_definition; + + FrameCaptionButton* buttons[] = {minimize_button_, size_button_, + close_button_}; + for (size_t i = 0; i < arraysize(buttons); ++i) { + if (buttons[i]->icon() == icon) + buttons[i]->SetImage(icon, FrameCaptionButton::ANIMATE_NO, + icon_definition); + } +} + +void FrameCaptionButtonContainerView::SetPaintAsActive(bool paint_as_active) { + minimize_button_->set_paint_as_active(paint_as_active); + size_button_->set_paint_as_active(paint_as_active); + close_button_->set_paint_as_active(paint_as_active); +} + +void FrameCaptionButtonContainerView::SetUseLightImages(bool light) { + minimize_button_->set_use_light_images(light); + size_button_->set_use_light_images(light); + close_button_->set_use_light_images(light); +} + +void FrameCaptionButtonContainerView::ResetWindowControls() { + SetButtonsToNormal(ANIMATE_NO); +} + +int FrameCaptionButtonContainerView::NonClientHitTest( + const gfx::Point& point) const { + if (close_button_->visible() && + ConvertPointToViewAndHitTest(this, close_button_, point)) { + return HTCLOSE; + } else if (size_button_->visible() && + ConvertPointToViewAndHitTest(this, size_button_, point)) { + return HTMAXBUTTON; + } else if (minimize_button_->visible() && + ConvertPointToViewAndHitTest(this, minimize_button_, point)) { + return HTMINBUTTON; + } + return HTNOWHERE; +} + +void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() { + bool visible = ShouldSizeButtonBeVisible(); + if (visible) { + size_button_->SetVisible(true); + maximize_mode_animation_->SetSlideDuration(kShowAnimationDurationMs); + maximize_mode_animation_->Show(); + } else { + maximize_mode_animation_->SetSlideDuration(kHideAnimationDurationMs); + maximize_mode_animation_->Hide(); + } +} + +void FrameCaptionButtonContainerView::SetButtonSize(const gfx::Size& size) { + minimize_button_->set_size(size); + size_button_->set_size(size); + close_button_->set_size(size); +} + +gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { + int width = 0; + for (int i = 0; i < child_count(); ++i) { + const views::View* child = child_at(i); + if (child->visible()) + width += child_at(i)->GetPreferredSize().width(); + } + return gfx::Size(width, close_button_->GetPreferredSize().height()); +} + +void FrameCaptionButtonContainerView::Layout() { + int x = 0; + for (int i = 0; i < child_count(); ++i) { + views::View* child = child_at(i); + if (!child->visible()) + continue; + + gfx::Size size = child->GetPreferredSize(); + child->SetBounds(x, 0, size.width(), size.height()); + x += size.width(); + } + if (maximize_mode_animation_->is_animating()) { + AnimationProgressed(maximize_mode_animation_.get()); + } +} + +const char* FrameCaptionButtonContainerView::GetClassName() const { + return kViewClassName; +} + +void FrameCaptionButtonContainerView::AnimationEnded( + const gfx::Animation* animation) { + // Ensure that position is calculated at least once. + AnimationProgressed(animation); + + double current_value = maximize_mode_animation_->GetCurrentValue(); + if (current_value == 0.0) { + size_button_->SetVisible(false); + PreferredSizeChanged(); + } +} + +void FrameCaptionButtonContainerView::AnimationProgressed( + const gfx::Animation* animation) { + double current_value = animation->GetCurrentValue(); + int size_alpha = 0; + int minimize_x = 0; + if (maximize_mode_animation_->IsShowing()) { + double scaled_value = + CapAnimationValue((current_value - SizeButtonShowStartValue()) / + SizeButtonShowDuration()); + double tweened_value_alpha = + gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value); + size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 0, 255); + + double tweened_value_slide = + gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, current_value); + minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_slide, + size_button_->x(), 0); + } else { + double scaled_value_alpha = + CapAnimationValue((1.0f - current_value) / SizeButtonHideDuration()); + double tweened_value_alpha = + gfx::Tween::CalculateValue(gfx::Tween::EASE_IN, scaled_value_alpha); + size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 255, 0); + + double scaled_value_position = CapAnimationValue( + (HidePositionStartValue() - current_value) / HidePositionStartValue()); + double tweened_value_position = + gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value_position); + minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_position, 0, + size_button_->x()); + } + size_button_->SetAlpha(size_alpha); + minimize_button_->SetX(minimize_x); +} + +void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, + CaptionButtonIcon icon, + Animate animate) { + // The early return is dependant on |animate| because callers use + // SetButtonIcon() with ANIMATE_NO to progress |button|'s crossfade animation + // to the end. + if (button->icon() == icon && + (animate == ANIMATE_YES || !button->IsAnimatingImageSwap())) { + return; + } + + FrameCaptionButton::Animate fcb_animate = + (animate == ANIMATE_YES) ? FrameCaptionButton::ANIMATE_YES + : FrameCaptionButton::ANIMATE_NO; + auto it = button_icon_map_.find(icon); + if (it != button_icon_map_.end()) + button->SetImage(icon, fcb_animate, *it->second); +} + +bool FrameCaptionButtonContainerView::ShouldSizeButtonBeVisible() const { + return !WmShell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled() && + frame_->widget_delegate()->CanMaximize(); +} + +void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + // Abort any animations of the button icons. + SetButtonsToNormal(ANIMATE_NO); + + UserMetricsAction action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE; + if (sender == minimize_button_) { + frame_->Minimize(); + } else if (sender == size_button_) { + if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen. + frame_->Restore(); + action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN; + } else if (frame_->IsMaximized()) { + frame_->Restore(); + action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE; + } else { + frame_->Maximize(); + action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE; + } + + if (event.IsGestureEvent()) + WmShell::Get()->RecordGestureAction(GESTURE_FRAMEMAXIMIZE_TAP); + } else if (sender == close_button_) { + frame_->Close(); + action = UMA_WINDOW_CLOSE_BUTTON_CLICK; + } else { + return; + } + WmShell::Get()->RecordUserMetricsAction(action); +} + +bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const { + return minimize_button_->visible(); +} + +void FrameCaptionButtonContainerView::SetButtonsToNormal(Animate animate) { + SetButtonIcons(CAPTION_BUTTON_ICON_MINIMIZE, CAPTION_BUTTON_ICON_CLOSE, + animate); + minimize_button_->SetState(views::Button::STATE_NORMAL); + size_button_->SetState(views::Button::STATE_NORMAL); + close_button_->SetState(views::Button::STATE_NORMAL); +} + +void FrameCaptionButtonContainerView::SetButtonIcons( + CaptionButtonIcon minimize_button_icon, + CaptionButtonIcon close_button_icon, + Animate animate) { + SetButtonIcon(minimize_button_, minimize_button_icon, animate); + SetButtonIcon(close_button_, close_button_icon, animate); +} + +const FrameCaptionButton* FrameCaptionButtonContainerView::GetButtonClosestTo( + const gfx::Point& position_in_screen) const { + // Since the buttons all have the same size, the closest button is the button + // with the center point closest to |position_in_screen|. + // TODO(pkotwicz): Make the caption buttons not overlap. + gfx::Point position(position_in_screen); + views::View::ConvertPointFromScreen(this, &position); + + FrameCaptionButton* buttons[] = {minimize_button_, size_button_, + close_button_}; + int min_squared_distance = INT_MAX; + FrameCaptionButton* closest_button = NULL; + for (size_t i = 0; i < arraysize(buttons); ++i) { + FrameCaptionButton* button = buttons[i]; + if (!button->visible()) + continue; + + gfx::Point center_point = button->GetLocalBounds().CenterPoint(); + views::View::ConvertPointToTarget(button, this, ¢er_point); + int squared_distance = static_cast<int>( + pow(static_cast<double>(position.x() - center_point.x()), 2) + + pow(static_cast<double>(position.y() - center_point.y()), 2)); + if (squared_distance < min_squared_distance) { + min_squared_distance = squared_distance; + closest_button = button; + } + } + return closest_button; +} + +void FrameCaptionButtonContainerView::SetHoveredAndPressedButtons( + const FrameCaptionButton* to_hover, + const FrameCaptionButton* to_press) { + FrameCaptionButton* buttons[] = {minimize_button_, size_button_, + close_button_}; + for (size_t i = 0; i < arraysize(buttons); ++i) { + FrameCaptionButton* button = buttons[i]; + views::Button::ButtonState new_state = views::Button::STATE_NORMAL; + if (button == to_hover) + new_state = views::Button::STATE_HOVERED; + else if (button == to_press) + new_state = views::Button::STATE_PRESSED; + button->SetState(new_state); + } +} + +} // namespace ash
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view.h b/ash/common/frame/caption_buttons/frame_caption_button_container_view.h new file mode 100644 index 0000000..014071a --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view.h
@@ -0,0 +1,158 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ +#define ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ + +#include <map> + +#include "ash/ash_export.h" +#include "ash/common/frame/caption_buttons/frame_size_button_delegate.h" +#include "base/macros.h" +#include "ui/gfx/animation/animation_delegate.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace gfx { +class SlideAnimation; +struct VectorIcon; +} + +namespace views { +class Widget; +} + +namespace ash { + +// Container view for the frame caption buttons. It performs the appropriate +// action when a caption button is clicked. +class ASH_EXPORT FrameCaptionButtonContainerView + : public views::View, + public views::ButtonListener, + public FrameSizeButtonDelegate, + public gfx::AnimationDelegate { + public: + static const char kViewClassName[]; + + // |frame| is the views::Widget that the caption buttons act on. + explicit FrameCaptionButtonContainerView(views::Widget* frame); + ~FrameCaptionButtonContainerView() override; + + // For testing. + class ASH_EXPORT TestApi { + public: + explicit TestApi(FrameCaptionButtonContainerView* container_view) + : container_view_(container_view) {} + + void EndAnimations(); + + FrameCaptionButton* minimize_button() const { + return container_view_->minimize_button_; + } + + FrameCaptionButton* size_button() const { + return container_view_->size_button_; + } + + FrameCaptionButton* close_button() const { + return container_view_->close_button_; + } + + private: + FrameCaptionButtonContainerView* container_view_; + + DISALLOW_COPY_AND_ASSIGN(TestApi); + }; + + // Sets the id of the vector image to paint the button for |icon|. The + // FrameCaptionButtonContainerView will keep track of the image to use for + // |icon| even if none of the buttons currently use |icon|. + void SetButtonImage(CaptionButtonIcon icon, + const gfx::VectorIcon& icon_definition); + + // Sets whether the buttons should be painted as active. Does not schedule + // a repaint. + void SetPaintAsActive(bool paint_as_active); + + // Sets whether the buttons should be painted in a lighter color (for use on + // dark backgrounds). + void SetUseLightImages(bool light); + + // Tell the window controls to reset themselves to the normal state. + void ResetWindowControls(); + + // Determines the window HT* code for the caption button at |point|. Returns + // HTNOWHERE if |point| is not over any of the caption buttons. |point| must + // be in the coordinates of the FrameCaptionButtonContainerView. + int NonClientHitTest(const gfx::Point& point) const; + + // Updates the size button's visibility based on whether |frame_| can be + // maximized and if maximize mode is enabled. A parent view should relayout + // to reflect the change in visibility. + void UpdateSizeButtonVisibility(); + + // Sets the size of the buttons in this container. + void SetButtonSize(const gfx::Size& size); + + // views::View: + gfx::Size GetPreferredSize() const override; + void Layout() override; + const char* GetClassName() const override; + + // gfx::AnimationDelegate: + void AnimationEnded(const gfx::Animation* animation) override; + void AnimationProgressed(const gfx::Animation* animation) override; + + private: + friend class FrameCaptionButtonContainerViewTest; + + // Sets |button|'s icon to |icon|. If |animate| is ANIMATE_YES, the button + // will crossfade to the new icon. If |animate| is ANIMATE_NO and + // |icon| == |button|->icon(), the crossfade animation is progressed to the + // end. + void SetButtonIcon(FrameCaptionButton* button, + CaptionButtonIcon icon, + Animate animate); + + // Returns true if maximize mode is not enabled, and |frame_| widget delegate + // can be maximized. + bool ShouldSizeButtonBeVisible() const; + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + // FrameSizeButtonDelegate: + bool IsMinimizeButtonVisible() const override; + void SetButtonsToNormal(Animate animate) override; + void SetButtonIcons(CaptionButtonIcon minimize_button_icon, + CaptionButtonIcon close_button_icon, + Animate animate) override; + const FrameCaptionButton* GetButtonClosestTo( + const gfx::Point& position_in_screen) const override; + void SetHoveredAndPressedButtons(const FrameCaptionButton* to_hover, + const FrameCaptionButton* to_press) override; + + // The widget that the buttons act on. + views::Widget* frame_; + + // The buttons. In the normal button style, at most one of |minimize_button_| + // and |size_button_| is visible. + FrameCaptionButton* minimize_button_; + FrameCaptionButton* size_button_; + FrameCaptionButton* close_button_; + + // Mapping of the image needed to paint a button for each of the values of + // CaptionButtonIcon. + std::map<CaptionButtonIcon, const gfx::VectorIcon*> button_icon_map_; + + // Animation that affects the position of |minimize_button_| and the + // visibility of |size_button_|. + std::unique_ptr<gfx::SlideAnimation> maximize_mode_animation_; + + DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerView); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc new file mode 100644 index 0000000..f84fe43f --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -0,0 +1,204 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" + +#include "ash/common/ash_layout_constants.h" +#include "ash/common/frame/caption_buttons/frame_caption_button.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/test/ash_test_base.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +namespace { + +class TestWidgetDelegate : public views::WidgetDelegateView { + public: + TestWidgetDelegate(bool can_maximize, bool can_minimize) + : can_maximize_(can_maximize), can_minimize_(can_minimize) {} + ~TestWidgetDelegate() override {} + + bool CanMaximize() const override { return can_maximize_; } + + bool CanMinimize() const override { return can_minimize_; } + + private: + bool can_maximize_; + bool can_minimize_; + + DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); +}; + +} // namespace + +class FrameCaptionButtonContainerViewTest : public ash::test::AshTestBase { + public: + enum MaximizeAllowed { MAXIMIZE_ALLOWED, MAXIMIZE_DISALLOWED }; + + enum MinimizeAllowed { MINIMIZE_ALLOWED, MINIMIZE_DISALLOWED }; + + FrameCaptionButtonContainerViewTest() {} + + ~FrameCaptionButtonContainerViewTest() override {} + + // Creates a widget which allows maximizing based on |maximize_allowed|. + // The caller takes ownership of the returned widget. + views::Widget* CreateTestWidget(MaximizeAllowed maximize_allowed, + MinimizeAllowed minimize_allowed) + WARN_UNUSED_RESULT { + views::Widget* widget = new views::Widget; + views::Widget::InitParams params; + params.delegate = + new TestWidgetDelegate(maximize_allowed == MAXIMIZE_ALLOWED, + minimize_allowed == MINIMIZE_ALLOWED); + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.context = CurrentContext(); + widget->Init(params); + return widget; + } + + // Sets arbitrary images for the icons and assign the default caption button + // size to the buttons in |container|. + void InitContainer(FrameCaptionButtonContainerView* container) { + container->SetButtonSize( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); + for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) { + container->SetButtonImage(static_cast<CaptionButtonIcon>(icon), + ash::kWindowControlCloseIcon); + } + } + + // Tests that |leftmost| and |rightmost| are at |container|'s edges. + bool CheckButtonsAtEdges(FrameCaptionButtonContainerView* container, + const ash::FrameCaptionButton& leftmost, + const ash::FrameCaptionButton& rightmost) { + gfx::Rect expected(container->GetPreferredSize()); + + gfx::Rect container_size(container->GetPreferredSize()); + if (leftmost.y() == rightmost.y() && + leftmost.height() == rightmost.height() && + leftmost.x() == expected.x() && leftmost.y() == expected.y() && + leftmost.height() == expected.height() && + rightmost.bounds().right() == expected.right()) { + return true; + } + + LOG(ERROR) << "Buttons " << leftmost.bounds().ToString() << " " + << rightmost.bounds().ToString() << " not at edges of " + << expected.ToString(); + return false; + } + + private: + DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTest); +}; + +// Test how the allowed actions affect which caption buttons are visible. +TEST_F(FrameCaptionButtonContainerViewTest, ButtonVisibility) { + // All the buttons should be visible when minimizing and maximizing are + // allowed. + FrameCaptionButtonContainerView container1( + CreateTestWidget(MAXIMIZE_ALLOWED, MINIMIZE_ALLOWED)); + InitContainer(&container1); + container1.Layout(); + FrameCaptionButtonContainerView::TestApi t1(&container1); + EXPECT_TRUE(t1.minimize_button()->visible()); + EXPECT_TRUE(t1.size_button()->visible()); + EXPECT_TRUE(t1.close_button()->visible()); + EXPECT_TRUE(CheckButtonsAtEdges(&container1, *t1.minimize_button(), + *t1.close_button())); + + // The minimize button should be visible when minimizing is allowed but + // maximizing is disallowed. + FrameCaptionButtonContainerView container2( + CreateTestWidget(MAXIMIZE_DISALLOWED, MINIMIZE_ALLOWED)); + InitContainer(&container2); + container2.Layout(); + FrameCaptionButtonContainerView::TestApi t2(&container2); + EXPECT_TRUE(t2.minimize_button()->visible()); + EXPECT_FALSE(t2.size_button()->visible()); + EXPECT_TRUE(t2.close_button()->visible()); + EXPECT_TRUE(CheckButtonsAtEdges(&container2, *t2.minimize_button(), + *t2.close_button())); + + // Neither the minimize button nor the size button should be visible when + // neither minimizing nor maximizing are allowed. + FrameCaptionButtonContainerView container3( + CreateTestWidget(MAXIMIZE_DISALLOWED, MINIMIZE_DISALLOWED)); + InitContainer(&container3); + container3.Layout(); + FrameCaptionButtonContainerView::TestApi t3(&container3); + EXPECT_FALSE(t3.minimize_button()->visible()); + EXPECT_FALSE(t3.size_button()->visible()); + EXPECT_TRUE(t3.close_button()->visible()); + EXPECT_TRUE( + CheckButtonsAtEdges(&container3, *t3.close_button(), *t3.close_button())); +} + +// Tests that the layout animations trigered by button visibility result in the +// correct placement of the buttons. +TEST_F(FrameCaptionButtonContainerViewTest, + TestUpdateSizeButtonVisibilityAnimation) { + FrameCaptionButtonContainerView container( + CreateTestWidget(MAXIMIZE_ALLOWED, MINIMIZE_ALLOWED)); + InitContainer(&container); + container.SetBoundsRect(gfx::Rect(container.GetPreferredSize())); + container.Layout(); + + FrameCaptionButtonContainerView::TestApi test(&container); + gfx::Rect initial_minimize_button_bounds = test.minimize_button()->bounds(); + gfx::Rect initial_size_button_bounds = test.size_button()->bounds(); + gfx::Rect initial_close_button_bounds = test.close_button()->bounds(); + gfx::Rect initial_container_bounds = container.bounds(); + + ASSERT_EQ(initial_size_button_bounds.x(), + initial_minimize_button_bounds.right()); + ASSERT_EQ(initial_close_button_bounds.x(), + initial_size_button_bounds.right()); + + // Hidden size button should result in minimize button animating to the + // right. The size button should not be visible, but should not have moved. + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + container.UpdateSizeButtonVisibility(); + test.EndAnimations(); + // Parent needs to layout in response to size change. + container.Layout(); + + EXPECT_TRUE(test.minimize_button()->visible()); + EXPECT_FALSE(test.size_button()->visible()); + EXPECT_TRUE(test.close_button()->visible()); + gfx::Rect minimize_button_bounds = test.minimize_button()->bounds(); + gfx::Rect close_button_bounds = test.close_button()->bounds(); + EXPECT_EQ(close_button_bounds.x(), minimize_button_bounds.right()); + EXPECT_EQ(initial_size_button_bounds, test.size_button()->bounds()); + EXPECT_EQ(initial_close_button_bounds.size(), close_button_bounds.size()); + EXPECT_LT(container.GetPreferredSize().width(), + initial_container_bounds.width()); + + // Revealing the size button should cause the minimize button to return to its + // original position. + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + container.UpdateSizeButtonVisibility(); + // Calling code needs to layout in response to size change. + container.Layout(); + test.EndAnimations(); + EXPECT_TRUE(test.minimize_button()->visible()); + EXPECT_TRUE(test.size_button()->visible()); + EXPECT_TRUE(test.close_button()->visible()); + EXPECT_EQ(initial_minimize_button_bounds, test.minimize_button()->bounds()); + EXPECT_EQ(initial_size_button_bounds, test.size_button()->bounds()); + EXPECT_EQ(initial_close_button_bounds, test.close_button()->bounds()); + EXPECT_EQ(container.GetPreferredSize().width(), + initial_container_bounds.width()); +} + +} // namespace ash
diff --git a/ash/common/frame/caption_buttons/frame_size_button.cc b/ash/common/frame/caption_buttons/frame_size_button.cc new file mode 100644 index 0000000..cc2fe20 --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_size_button.cc
@@ -0,0 +1,270 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/caption_buttons/frame_size_button.h" + +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace/phantom_window_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/i18n/rtl.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { + +// The default delay between the user pressing the size button and the buttons +// adjacent to the size button morphing into buttons for snapping left and +// right. +const int kSetButtonsToSnapModeDelayMs = 150; + +// The amount that a user can overshoot one of the caption buttons while in +// "snap mode" and keep the button hovered/pressed. +const int kMaxOvershootX = 200; +const int kMaxOvershootY = 50; + +// Returns true if a mouse drag while in "snap mode" at |location_in_screen| +// would hover/press |button| or keep it hovered/pressed. +bool HitTestButton(const FrameCaptionButton* button, + const gfx::Point& location_in_screen) { + gfx::Rect expanded_bounds_in_screen = button->GetBoundsInScreen(); + if (button->state() == views::Button::STATE_HOVERED || + button->state() == views::Button::STATE_PRESSED) { + expanded_bounds_in_screen.Inset(-kMaxOvershootX, -kMaxOvershootY); + } + return expanded_bounds_in_screen.Contains(location_in_screen); +} + +} // namespace + +FrameSizeButton::FrameSizeButton(views::ButtonListener* listener, + views::Widget* frame, + FrameSizeButtonDelegate* delegate) + : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE), + frame_(frame), + delegate_(delegate), + set_buttons_to_snap_mode_delay_ms_(kSetButtonsToSnapModeDelayMs), + in_snap_mode_(false), + snap_type_(SNAP_NONE) {} + +FrameSizeButton::~FrameSizeButton() {} + +bool FrameSizeButton::OnMousePressed(const ui::MouseEvent& event) { + // The minimize and close buttons are set to snap left and right when snapping + // is enabled. Do not enable snapping if the minimize button is not visible. + // The close button is always visible. + if (IsTriggerableEvent(event) && !in_snap_mode_ && + delegate_->IsMinimizeButtonVisible()) { + StartSetButtonsToSnapModeTimer(event); + } + FrameCaptionButton::OnMousePressed(event); + return true; +} + +bool FrameSizeButton::OnMouseDragged(const ui::MouseEvent& event) { + UpdateSnapType(event); + // By default a FrameCaptionButton reverts to STATE_NORMAL once the mouse + // leaves its bounds. Skip FrameCaptionButton's handling when + // |in_snap_mode_| == true because we want different behavior. + if (!in_snap_mode_) + FrameCaptionButton::OnMouseDragged(event); + return true; +} + +void FrameSizeButton::OnMouseReleased(const ui::MouseEvent& event) { + if (!IsTriggerableEvent(event) || !CommitSnap(event)) + FrameCaptionButton::OnMouseReleased(event); +} + +void FrameSizeButton::OnMouseCaptureLost() { + SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); + FrameCaptionButton::OnMouseCaptureLost(); +} + +void FrameSizeButton::OnMouseMoved(const ui::MouseEvent& event) { + // Ignore any synthetic mouse moves during a drag. + if (!in_snap_mode_) + FrameCaptionButton::OnMouseMoved(event); +} + +void FrameSizeButton::OnGestureEvent(ui::GestureEvent* event) { + if (event->details().touch_points() > 1) { + SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); + return; + } + + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + StartSetButtonsToSnapModeTimer(*event); + // Go through FrameCaptionButton's handling so that the button gets pressed. + FrameCaptionButton::OnGestureEvent(event); + return; + } + + if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || + event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { + UpdateSnapType(*event); + event->SetHandled(); + return; + } + + if (event->type() == ui::ET_GESTURE_TAP || + event->type() == ui::ET_GESTURE_SCROLL_END || + event->type() == ui::ET_SCROLL_FLING_START || + event->type() == ui::ET_GESTURE_END) { + if (CommitSnap(*event)) { + event->SetHandled(); + return; + } + } + + FrameCaptionButton::OnGestureEvent(event); +} + +void FrameSizeButton::StartSetButtonsToSnapModeTimer( + const ui::LocatedEvent& event) { + set_buttons_to_snap_mode_timer_event_location_ = event.location(); + if (set_buttons_to_snap_mode_delay_ms_ == 0) { + AnimateButtonsToSnapMode(); + } else { + set_buttons_to_snap_mode_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(set_buttons_to_snap_mode_delay_ms_), + this, &FrameSizeButton::AnimateButtonsToSnapMode); + } +} + +void FrameSizeButton::AnimateButtonsToSnapMode() { + SetButtonsToSnapMode(FrameSizeButtonDelegate::ANIMATE_YES); +} + +void FrameSizeButton::SetButtonsToSnapMode( + FrameSizeButtonDelegate::Animate animate) { + in_snap_mode_ = true; + + // When using a right-to-left layout the close button is left of the size + // button and the minimize button is right of the size button. + if (base::i18n::IsRTL()) { + delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_RIGHT_SNAPPED, + CAPTION_BUTTON_ICON_LEFT_SNAPPED, animate); + } else { + delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_LEFT_SNAPPED, + CAPTION_BUTTON_ICON_RIGHT_SNAPPED, animate); + } +} + +void FrameSizeButton::UpdateSnapType(const ui::LocatedEvent& event) { + if (!in_snap_mode_) { + // Set the buttons adjacent to the size button to snap left and right early + // if the user drags past the drag threshold. + // |set_buttons_to_snap_mode_timer_| is checked to avoid entering the snap + // mode as a result of an unsupported drag type (e.g. only the right mouse + // button is pressed). + gfx::Vector2d delta(event.location() - + set_buttons_to_snap_mode_timer_event_location_); + if (!set_buttons_to_snap_mode_timer_.IsRunning() || + !views::View::ExceededDragThreshold(delta)) { + return; + } + AnimateButtonsToSnapMode(); + } + + gfx::Point event_location_in_screen(event.location()); + views::View::ConvertPointToScreen(this, &event_location_in_screen); + const FrameCaptionButton* to_hover = + GetButtonToHover(event_location_in_screen); + bool press_size_button = + to_hover || HitTestButton(this, event_location_in_screen); + + if (to_hover) { + // Progress the minimize and close icon morph animations to the end if they + // are in progress. + SetButtonsToSnapMode(FrameSizeButtonDelegate::ANIMATE_NO); + } + + delegate_->SetHoveredAndPressedButtons(to_hover, + press_size_button ? this : NULL); + + snap_type_ = SNAP_NONE; + if (to_hover) { + switch (to_hover->icon()) { + case CAPTION_BUTTON_ICON_LEFT_SNAPPED: + snap_type_ = SNAP_LEFT; + break; + case CAPTION_BUTTON_ICON_RIGHT_SNAPPED: + snap_type_ = SNAP_RIGHT; + break; + case CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE: + case CAPTION_BUTTON_ICON_MINIMIZE: + case CAPTION_BUTTON_ICON_CLOSE: + case CAPTION_BUTTON_ICON_BACK: + case CAPTION_BUTTON_ICON_LOCATION: + case CAPTION_BUTTON_ICON_COUNT: + NOTREACHED(); + break; + } + } + + if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { + WmWindow* window = WmWindow::Get(frame_->GetNativeWindow()); + if (!phantom_window_controller_.get()) + phantom_window_controller_.reset(new PhantomWindowController(window)); + gfx::Rect phantom_bounds_in_parent = + (snap_type_ == SNAP_LEFT) + ? wm::GetDefaultLeftSnappedWindowBoundsInParent(window) + : wm::GetDefaultRightSnappedWindowBoundsInParent(window); + phantom_window_controller_->Show( + window->GetParent()->ConvertRectToScreen(phantom_bounds_in_parent)); + } else { + phantom_window_controller_.reset(); + } +} + +const FrameCaptionButton* FrameSizeButton::GetButtonToHover( + const gfx::Point& event_location_in_screen) const { + const FrameCaptionButton* closest_button = + delegate_->GetButtonClosestTo(event_location_in_screen); + if ((closest_button->icon() == CAPTION_BUTTON_ICON_LEFT_SNAPPED || + closest_button->icon() == CAPTION_BUTTON_ICON_RIGHT_SNAPPED) && + HitTestButton(closest_button, event_location_in_screen)) { + return closest_button; + } + return NULL; +} + +bool FrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { + // The position of |event| may be different than the position of the previous + // event. + UpdateSnapType(event); + + if (in_snap_mode_ && (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { + WmWindow* window = WmWindow::Get(frame_->GetNativeWindow()); + wm::WindowState* window_state = window->GetWindowState(); + const wm::WMEvent snap_event(snap_type_ == SNAP_LEFT + ? wm::WM_EVENT_SNAP_LEFT + : wm::WM_EVENT_SNAP_RIGHT); + window_state->OnWMEvent(&snap_event); + WmShell::Get()->RecordUserMetricsAction( + snap_type_ == SNAP_LEFT ? UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT + : UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); + SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_NO); + return true; + } + SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); + return false; +} + +void FrameSizeButton::SetButtonsToNormalMode( + FrameSizeButtonDelegate::Animate animate) { + in_snap_mode_ = false; + snap_type_ = SNAP_NONE; + set_buttons_to_snap_mode_timer_.Stop(); + delegate_->SetButtonsToNormal(animate); + phantom_window_controller_.reset(); +} + +} // namespace ash
diff --git a/ash/common/frame/caption_buttons/frame_size_button.h b/ash/common/frame/caption_buttons/frame_size_button.h new file mode 100644 index 0000000..0ab4dcf --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_size_button.h
@@ -0,0 +1,120 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ +#define ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/frame/caption_buttons/frame_caption_button.h" +#include "ash/common/frame/caption_buttons/frame_size_button_delegate.h" +#include "base/macros.h" +#include "base/timer/timer.h" + +namespace views { +class Widget; +} + +namespace ash { +class FrameSizeButtonDelegate; +class PhantomWindowController; + +// The maximize/restore button. +// When the mouse is pressed over the size button or the size button is touched: +// - The minimize and close buttons are set to snap left and snap right +// respectively. +// - The size button stays pressed while the mouse is over the buttons to snap +// left and to snap right. The button underneath the mouse is hovered. +// When the drag terminates, the action for the button underneath the mouse +// is executed. For the sake of simplicity, the size button is the event +// handler for a click starting on the size button and the entire drag. +class ASH_EXPORT FrameSizeButton : public FrameCaptionButton { + public: + FrameSizeButton(views::ButtonListener* listener, + views::Widget* frame, + FrameSizeButtonDelegate* delegate); + + ~FrameSizeButton() override; + + // views::CustomButton overrides: + bool OnMousePressed(const ui::MouseEvent& event) override; + bool OnMouseDragged(const ui::MouseEvent& event) override; + void OnMouseReleased(const ui::MouseEvent& event) override; + void OnMouseCaptureLost() override; + void OnMouseMoved(const ui::MouseEvent& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + + void set_delay_to_set_buttons_to_snap_mode(int delay_ms) { + set_buttons_to_snap_mode_delay_ms_ = delay_ms; + } + + private: + enum SnapType { SNAP_LEFT, SNAP_RIGHT, SNAP_NONE }; + + // Starts |set_buttons_to_snap_mode_timer_|. + void StartSetButtonsToSnapModeTimer(const ui::LocatedEvent& event); + + // Animates the buttons adjacent to the size button to snap left and right. + void AnimateButtonsToSnapMode(); + + // Sets the buttons adjacent to the size button to snap left and right. + // Passing in ANIMATE_NO progresses the animation (if any) to the end. + void SetButtonsToSnapMode(FrameSizeButtonDelegate::Animate animate); + + // Updates |snap_type_|, whether the size button is pressed and whether any + // other buttons are hovered. + void UpdateSnapType(const ui::LocatedEvent& event); + + // Returns the button which should be hovered (if any) while in "snap mode" + // for |event_location_in_screen|. + const FrameCaptionButton* GetButtonToHover( + const gfx::Point& event_location_in_screen) const; + + // Snaps |frame_| according to |snap_type_|. Returns true if |frame_| was + // snapped. + bool CommitSnap(const ui::LocatedEvent& event); + + // Sets the buttons adjacent to the size button to minimize and close again. + // Clears any state set while snapping was enabled. |animate| indicates + // whether the buttons should animate back to their original icons. + void SetButtonsToNormalMode(FrameSizeButtonDelegate::Animate animate); + + // Widget that the size button acts on. + views::Widget* frame_; + + // Not owned. + FrameSizeButtonDelegate* delegate_; + + // Location of the event which started |set_buttons_to_snap_mode_timer_| in + // view coordinates. + gfx::Point set_buttons_to_snap_mode_timer_event_location_; + + // The delay between the user pressing the size button and the buttons + // adjacent to the size button morphing into buttons for snapping left and + // right. + int set_buttons_to_snap_mode_delay_ms_; + + base::OneShotTimer set_buttons_to_snap_mode_timer_; + + // Whether the buttons adjacent to the size button snap the window left and + // right. + bool in_snap_mode_; + + // The action to execute when the drag/click is ended. If + // |snap_type_| == SNAP_NONE, the size button's default action is run when the + // drag/click is ended. + SnapType snap_type_; + + // Displays a preview of how the window's bounds will change as a result of + // snapping the window left or right. The preview is only visible if the snap + // left or snap right button is pressed. + std::unique_ptr<PhantomWindowController> phantom_window_controller_; + + DISALLOW_COPY_AND_ASSIGN(FrameSizeButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_
diff --git a/ash/common/frame/caption_buttons/frame_size_button_delegate.h b/ash/common/frame/caption_buttons/frame_size_button_delegate.h new file mode 100644 index 0000000..026436ac --- /dev/null +++ b/ash/common/frame/caption_buttons/frame_size_button_delegate.h
@@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ +#define ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "ash/common/frame/caption_buttons/caption_button_types.h" + +namespace gfx { +class Point; +} + +namespace ash { +class FrameCaptionButton; + +// Delegate interface for FrameSizeButton. +class ASH_EXPORT FrameSizeButtonDelegate { + public: + enum Animate { ANIMATE_YES, ANIMATE_NO }; + + // Returns whether the minimize button is visible. + virtual bool IsMinimizeButtonVisible() const = 0; + + // Reset the caption button views::Button::ButtonState back to normal. If + // |animate| is ANIMATE_YES, the buttons will crossfade back to their + // original icons. + virtual void SetButtonsToNormal(Animate animate) = 0; + + // Sets the minimize and close button icons. The buttons will crossfade to + // their new icons if |animate| is ANIMATE_YES. + virtual void SetButtonIcons(CaptionButtonIcon minimize_button_icon, + CaptionButtonIcon close_button_icon, + Animate animate) = 0; + + // Returns the button closest to |position_in_screen|. + virtual const FrameCaptionButton* GetButtonClosestTo( + const gfx::Point& position_in_screen) const = 0; + + // Sets |to_hover| and |to_pressed| to STATE_HOVERED and STATE_PRESSED + // respectively. All other buttons are to set to STATE_NORMAL. + virtual void SetHoveredAndPressedButtons( + const FrameCaptionButton* to_hover, + const FrameCaptionButton* to_press) = 0; + + protected: + virtual ~FrameSizeButtonDelegate() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_
diff --git a/ash/common/frame/custom_frame_view_ash.cc b/ash/common/frame/custom_frame_view_ash.cc new file mode 100644 index 0000000..470dd01 --- /dev/null +++ b/ash/common/frame/custom_frame_view_ash.cc
@@ -0,0 +1,362 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/custom_frame_view_ash.h" + +#include <algorithm> +#include <vector> + +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/frame_border_hit_test.h" +#include "ash/common/frame/header_view.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_delegate.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/shared/immersive_fullscreen_controller.h" +#include "ash/shared/immersive_fullscreen_controller_delegate.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" +#include "ui/aura/window_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/view.h" +#include "ui/views/view_targeter.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +namespace { + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAshWindowStateDelegate + +// Handles a user's fullscreen request (Shift+F4/F4). Puts the window into +// immersive fullscreen if immersive fullscreen is enabled for non-browser +// windows. +class CustomFrameViewAshWindowStateDelegate : public wm::WindowStateDelegate, + public wm::WindowStateObserver, + public aura::WindowObserver { + public: + CustomFrameViewAshWindowStateDelegate(wm::WindowState* window_state, + CustomFrameViewAsh* custom_frame_view, + bool enable_immersive) + : window_state_(nullptr) { + // Add a window state observer to exit fullscreen properly in case + // fullscreen is exited without going through + // WindowState::ToggleFullscreen(). This is the case when exiting + // immersive fullscreen via the "Restore" window control. + // TODO(pkotwicz): This is a hack. Remove ASAP. http://crbug.com/319048 + window_state_ = window_state; + window_state_->AddObserver(this); + window_state_->window()->aura_window()->AddObserver(this); + + if (!enable_immersive) + return; + + immersive_fullscreen_controller_ = + WmShell::Get()->CreateImmersiveFullscreenController(); + if (immersive_fullscreen_controller_) { + custom_frame_view->InitImmersiveFullscreenControllerForView( + immersive_fullscreen_controller_.get()); + } + } + ~CustomFrameViewAshWindowStateDelegate() override { + if (window_state_) { + window_state_->RemoveObserver(this); + window_state_->window()->aura_window()->RemoveObserver(this); + } + } + + private: + // Overridden from wm::WindowStateDelegate: + bool ToggleFullscreen(wm::WindowState* window_state) override { + bool enter_fullscreen = !window_state->IsFullscreen(); + if (enter_fullscreen) + window_state_->window()->SetShowState(ui::SHOW_STATE_FULLSCREEN); + else + window_state->Restore(); + if (immersive_fullscreen_controller_) { + immersive_fullscreen_controller_->SetEnabled( + ImmersiveFullscreenController::WINDOW_TYPE_OTHER, enter_fullscreen); + } + return true; + } + // Overridden from aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override { + window_state_->RemoveObserver(this); + window->RemoveObserver(this); + window_state_ = nullptr; + } + // Overridden from wm::WindowStateObserver: + void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) override { + if (!window_state->IsFullscreen() && !window_state->IsMinimized() && + immersive_fullscreen_controller_ && + immersive_fullscreen_controller_->IsEnabled()) { + immersive_fullscreen_controller_->SetEnabled( + ImmersiveFullscreenController::WINDOW_TYPE_OTHER, false); + } + } + + wm::WindowState* window_state_; + std::unique_ptr<ImmersiveFullscreenController> + immersive_fullscreen_controller_; + + DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshWindowStateDelegate); +}; + +} // namespace + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh::OverlayView + +// View which takes up the entire widget and contains the HeaderView. HeaderView +// is a child of OverlayView to avoid creating a larger texture than necessary +// when painting the HeaderView to its own layer. +class CustomFrameViewAsh::OverlayView : public views::View, + public views::ViewTargeterDelegate { + public: + explicit OverlayView(HeaderView* header_view); + ~OverlayView() override; + + // views::View: + void Layout() override; + + private: + // views::ViewTargeterDelegate: + bool DoesIntersectRect(const views::View* target, + const gfx::Rect& rect) const override; + + HeaderView* header_view_; + + DISALLOW_COPY_AND_ASSIGN(OverlayView); +}; + +CustomFrameViewAsh::OverlayView::OverlayView(HeaderView* header_view) + : header_view_(header_view) { + AddChildView(header_view); + SetEventTargeter( + std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); +} + +CustomFrameViewAsh::OverlayView::~OverlayView() {} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh::OverlayView, views::View overrides: + +void CustomFrameViewAsh::OverlayView::Layout() { + // Layout |header_view_| because layout affects the result of + // GetPreferredOnScreenHeight(). + header_view_->Layout(); + + int onscreen_height = header_view_->GetPreferredOnScreenHeight(); + if (onscreen_height == 0) { + header_view_->SetVisible(false); + } else { + int height = header_view_->GetPreferredHeight(); + header_view_->SetBounds(0, onscreen_height - height, width(), height); + header_view_->SetVisible(true); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh::OverlayView, views::ViewTargeterDelegate overrides: + +bool CustomFrameViewAsh::OverlayView::DoesIntersectRect( + const views::View* target, + const gfx::Rect& rect) const { + CHECK_EQ(target, this); + // Grab events in the header view. Return false for other events so that they + // can be handled by the client view. + return header_view_->HitTestRect(rect); +} + +//////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh, public: + +// static +const char CustomFrameViewAsh::kViewClassName[] = "CustomFrameViewAsh"; + +CustomFrameViewAsh::CustomFrameViewAsh( + views::Widget* frame, + ImmersiveFullscreenControllerDelegate* immersive_delegate, + bool enable_immersive) + : frame_(frame), + header_view_(new HeaderView(frame)), + immersive_delegate_(immersive_delegate ? immersive_delegate + : header_view_) { + WmWindow* frame_window = WmWindow::Get(frame->GetNativeWindow()); + frame_window->InstallResizeHandleWindowTargeter(nullptr); + // |header_view_| is set as the non client view's overlay view so that it can + // overlay the web contents in immersive fullscreen. + frame->non_client_view()->SetOverlayView(new OverlayView(header_view_)); + frame_window->aura_window()->SetProperty( + aura::client::kTopViewColor, header_view_->GetInactiveFrameColor()); + + // A delegate for a more complex way of fullscreening the window may already + // be set. This is the case for packaged apps. + wm::WindowState* window_state = frame_window->GetWindowState(); + if (!window_state->HasDelegate()) { + window_state->SetDelegate(std::unique_ptr<wm::WindowStateDelegate>( + new CustomFrameViewAshWindowStateDelegate(window_state, this, + enable_immersive))); + } +} + +CustomFrameViewAsh::~CustomFrameViewAsh() {} + +void CustomFrameViewAsh::InitImmersiveFullscreenControllerForView( + ImmersiveFullscreenController* immersive_fullscreen_controller) { + immersive_fullscreen_controller->Init(immersive_delegate_, frame_, + header_view_); +} + +void CustomFrameViewAsh::SetFrameColors(SkColor active_frame_color, + SkColor inactive_frame_color) { + header_view_->SetFrameColors(active_frame_color, inactive_frame_color); + WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow()); + frame_window->aura_window()->SetProperty( + aura::client::kTopViewColor, header_view_->GetInactiveFrameColor()); +} + +//////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh, views::NonClientFrameView overrides: + +gfx::Rect CustomFrameViewAsh::GetBoundsForClientView() const { + gfx::Rect client_bounds = bounds(); + client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); + return client_bounds; +} + +gfx::Rect CustomFrameViewAsh::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + gfx::Rect window_bounds = client_bounds; + window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); + return window_bounds; +} + +int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) { + return FrameBorderNonClientHitTest( + this, header_view_->caption_button_container(), point); +} + +void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size, + gfx::Path* window_mask) { + // No window masks in Aura. +} + +void CustomFrameViewAsh::ResetWindowControls() { + header_view_->ResetWindowControls(); +} + +void CustomFrameViewAsh::UpdateWindowIcon() {} + +void CustomFrameViewAsh::UpdateWindowTitle() { + header_view_->SchedulePaintForTitle(); +} + +void CustomFrameViewAsh::SizeConstraintsChanged() { + header_view_->SizeConstraintsChanged(); +} + +void CustomFrameViewAsh::ActivationChanged(bool active) { + // The icons differ between active and inactive. + header_view_->SchedulePaint(); +} + +//////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh, views::View overrides: + +gfx::Size CustomFrameViewAsh::GetPreferredSize() const { + gfx::Size pref = frame_->client_view()->GetPreferredSize(); + gfx::Rect bounds(0, 0, pref.width(), pref.height()); + return frame_->non_client_view() + ->GetWindowBoundsForClientBounds(bounds) + .size(); +} + +void CustomFrameViewAsh::Layout() { + views::NonClientFrameView::Layout(); + WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow()); + frame_window->aura_window()->SetProperty(aura::client::kTopViewInset, + NonClientTopBorderHeight()); +} + +const char* CustomFrameViewAsh::GetClassName() const { + return kViewClassName; +} + +gfx::Size CustomFrameViewAsh::GetMinimumSize() const { + gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize()); + return gfx::Size( + std::max(header_view_->GetMinimumWidth(), min_client_view_size.width()), + NonClientTopBorderHeight() + min_client_view_size.height()); +} + +gfx::Size CustomFrameViewAsh::GetMaximumSize() const { + gfx::Size max_client_size(frame_->client_view()->GetMaximumSize()); + int width = 0; + int height = 0; + + if (max_client_size.width() > 0) + width = std::max(header_view_->GetMinimumWidth(), max_client_size.width()); + if (max_client_size.height() > 0) + height = NonClientTopBorderHeight() + max_client_size.height(); + + return gfx::Size(width, height); +} + +void CustomFrameViewAsh::SchedulePaintInRect(const gfx::Rect& r) { + // We may end up here before |header_view_| has been added to the Widget. + if (header_view_->GetWidget()) { + // The HeaderView is not a child of CustomFrameViewAsh. Redirect the paint + // to HeaderView instead. + gfx::RectF to_paint(r); + views::View::ConvertRectToTarget(this, header_view_, &to_paint); + header_view_->SchedulePaintInRect(gfx::ToEnclosingRect(to_paint)); + } else { + views::NonClientFrameView::SchedulePaintInRect(r); + } +} + +void CustomFrameViewAsh::VisibilityChanged(views::View* starting_from, + bool is_visible) { + if (is_visible) + header_view_->UpdateAvatarIcon(); +} + +views::View* CustomFrameViewAsh::GetHeaderView() { + return header_view_; +} + +const views::View* CustomFrameViewAsh::GetAvatarIconViewForTest() const { + return header_view_->avatar_icon(); +} + +//////////////////////////////////////////////////////////////////////////////// +// CustomFrameViewAsh, private: + +// views::NonClientFrameView: +bool CustomFrameViewAsh::DoesIntersectRect(const views::View* target, + const gfx::Rect& rect) const { + CHECK_EQ(target, this); + // NonClientView hit tests the NonClientFrameView first instead of going in + // z-order. Return false so that events get to the OverlayView. + return false; +} + +FrameCaptionButtonContainerView* +CustomFrameViewAsh::GetFrameCaptionButtonContainerViewForTest() { + return header_view_->caption_button_container(); +} + +int CustomFrameViewAsh::NonClientTopBorderHeight() const { + return frame_->IsFullscreen() ? 0 : header_view_->GetPreferredHeight(); +} + +} // namespace ash
diff --git a/ash/common/frame/custom_frame_view_ash.h b/ash/common/frame/custom_frame_view_ash.h new file mode 100644 index 0000000..b2e50be --- /dev/null +++ b/ash/common/frame/custom_frame_view_ash.h
@@ -0,0 +1,114 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_CUSTOM_FRAME_VIEW_ASH_H_ +#define ASH_COMMON_FRAME_CUSTOM_FRAME_VIEW_ASH_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/views/window/non_client_view.h" + +namespace views { +class Widget; +} + +namespace ash { + +class FrameCaptionButtonContainerView; +class HeaderView; +class ImmersiveFullscreenController; +class ImmersiveFullscreenControllerDelegate; + +// A NonClientFrameView used for packaged apps, dialogs and other non-browser +// windows. It supports immersive fullscreen. When in immersive fullscreen, the +// client view takes up the entire widget and the window header is an overlay. +// The window header overlay slides onscreen when the user hovers the mouse at +// the top of the screen. See also views::CustomFrameView and +// BrowserNonClientFrameViewAsh. +class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView { + public: + // Internal class name. + static const char kViewClassName[]; + + // |enable_immersive| controls whether ImmersiveFullscreenController is + // created for the CustomFrameViewAsh; if true and a WindowStateDelegate has + // not been set on the WindowState associated with |frame|, then an + // ImmersiveFullscreenController is created. + // If ImmersiveFullscreenControllerDelegate is not supplied, HeaderView is + // used as the ImmersiveFullscreenControllerDelegate. + explicit CustomFrameViewAsh( + views::Widget* frame, + ImmersiveFullscreenControllerDelegate* immersive_delegate = nullptr, + bool enable_immersive = true); + ~CustomFrameViewAsh() override; + + // Inits |immersive_fullscreen_controller| so that the controller reveals + // and hides |header_view_| in immersive fullscreen. + // CustomFrameViewAsh does not take ownership of + // |immersive_fullscreen_controller|. + void InitImmersiveFullscreenControllerForView( + ImmersiveFullscreenController* immersive_fullscreen_controller); + + // Sets the active and inactive frame colors. Note the inactive frame color + // will have some transparency added when the frame is drawn. + void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); + + // views::NonClientFrameView: + gfx::Rect GetBoundsForClientView() const override; + gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const override; + int NonClientHitTest(const gfx::Point& point) override; + void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override; + void ResetWindowControls() override; + void UpdateWindowIcon() override; + void UpdateWindowTitle() override; + void SizeConstraintsChanged() override; + void ActivationChanged(bool active) override; + + // views::View: + gfx::Size GetPreferredSize() const override; + void Layout() override; + const char* GetClassName() const override; + gfx::Size GetMinimumSize() const override; + gfx::Size GetMaximumSize() const override; + void SchedulePaintInRect(const gfx::Rect& r) override; + void VisibilityChanged(views::View* starting_from, bool is_visible) override; + + // Get the view of the header. + views::View* GetHeaderView(); + + const views::View* GetAvatarIconViewForTest() const; + + private: + class OverlayView; + friend class TestWidgetConstraintsDelegate; + + // views::NonClientFrameView: + bool DoesIntersectRect(const views::View* target, + const gfx::Rect& rect) const override; + + // Returns the container for the minimize/maximize/close buttons that is held + // by the HeaderView. Used in testing. + FrameCaptionButtonContainerView* GetFrameCaptionButtonContainerViewForTest(); + + // Height from top of window to top of client area. + int NonClientTopBorderHeight() const; + + // Not owned. + views::Widget* frame_; + + // View which contains the title and window controls. + HeaderView* header_view_; + + ImmersiveFullscreenControllerDelegate* immersive_delegate_; + + DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAsh); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_CUSTOM_FRAME_VIEW_ASH_H_
diff --git a/ash/common/frame/custom_frame_view_ash_unittest.cc b/ash/common/frame/custom_frame_view_ash_unittest.cc new file mode 100644 index 0000000..b5729ef3 --- /dev/null +++ b/ash/common/frame/custom_frame_view_ash_unittest.cc
@@ -0,0 +1,227 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/custom_frame_view_ash.h" + +#include <memory> + +#include "ash/common/ash_layout_constants.h" +#include "ash/common/frame/caption_buttons/frame_caption_button.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_unittest_util.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +// A views::WidgetDelegate which uses a CustomFrameViewAsh. +class TestWidgetDelegate : public views::WidgetDelegateView { + public: + TestWidgetDelegate() {} + ~TestWidgetDelegate() override {} + + views::NonClientFrameView* CreateNonClientFrameView( + views::Widget* widget) override { + custom_frame_view_ = new CustomFrameViewAsh(widget); + return custom_frame_view_; + } + + CustomFrameViewAsh* custom_frame_view() const { return custom_frame_view_; } + + private: + // Not owned. + CustomFrameViewAsh* custom_frame_view_; + + DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); +}; + +class TestWidgetConstraintsDelegate : public TestWidgetDelegate { + public: + TestWidgetConstraintsDelegate() {} + ~TestWidgetConstraintsDelegate() override {} + + // views::View: + gfx::Size GetMinimumSize() const override { return minimum_size_; } + + gfx::Size GetMaximumSize() const override { return maximum_size_; } + + views::View* GetContentsView() override { + // Set this instance as the contents view so that the maximum and minimum + // size constraints will be used. + return this; + } + + // views::WidgetDelegate: + bool CanMaximize() const override { return true; } + + bool CanMinimize() const override { return true; } + + void set_minimum_size(const gfx::Size& min_size) { minimum_size_ = min_size; } + + void set_maximum_size(const gfx::Size& max_size) { maximum_size_ = max_size; } + + const gfx::Rect& GetFrameCaptionButtonContainerViewBounds() { + return custom_frame_view() + ->GetFrameCaptionButtonContainerViewForTest() + ->bounds(); + } + + void EndFrameCaptionButtonContainerViewAnimations() { + FrameCaptionButtonContainerView::TestApi test( + custom_frame_view()->GetFrameCaptionButtonContainerViewForTest()); + test.EndAnimations(); + } + + int GetTitleBarHeight() const { + return custom_frame_view()->NonClientTopBorderHeight(); + } + + private: + gfx::Size minimum_size_; + gfx::Size maximum_size_; + + DISALLOW_COPY_AND_ASSIGN(TestWidgetConstraintsDelegate); +}; + +class CustomFrameViewAshTest : public test::AshTestBase { + public: + CustomFrameViewAshTest() {} + ~CustomFrameViewAshTest() override {} + + protected: + std::unique_ptr<views::Widget> CreateWidget(TestWidgetDelegate* delegate) { + std::unique_ptr<views::Widget> widget(new views::Widget); + views::Widget::InitParams params; + params.delegate = delegate; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = gfx::Rect(0, 0, 100, 100); + params.context = CurrentContext(); + widget->Init(params); + return widget; + } + + test::TestSessionStateDelegate* GetTestSessionStateDelegate() { + return static_cast<test::TestSessionStateDelegate*>( + WmShell::Get()->GetSessionStateDelegate()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest); +}; + +// Verifies the client view is not placed at a y location of 0. +TEST_F(CustomFrameViewAshTest, ClientViewCorrectlyPlaced) { + std::unique_ptr<views::Widget> widget(CreateWidget(new TestWidgetDelegate)); + widget->Show(); + EXPECT_NE(0, widget->client_view()->bounds().y()); +} + +// Test that the height of the header is correct upon initially displaying +// the widget. +TEST_F(CustomFrameViewAshTest, HeaderHeight) { + TestWidgetDelegate* delegate = new TestWidgetDelegate; + + std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); + widget->Show(); + + // The header should have enough room for the window controls. The + // header/content separator line overlays the window controls. + EXPECT_EQ( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON).height(), + delegate->custom_frame_view()->GetHeaderView()->height()); +} + +// Verify that CustomFrameViewAsh returns the correct minimum and maximum frame +// sizes when the client view does not specify any size constraints. +TEST_F(CustomFrameViewAshTest, NoSizeConstraints) { + TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; + std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); + + CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); + gfx::Size min_frame_size = custom_frame_view->GetMinimumSize(); + gfx::Size max_frame_size = custom_frame_view->GetMaximumSize(); + + EXPECT_EQ(delegate->GetTitleBarHeight(), min_frame_size.height()); + + // A width and height constraint of 0 denotes unbounded. + EXPECT_EQ(0, max_frame_size.width()); + EXPECT_EQ(0, max_frame_size.height()); +} + +// Verify that CustomFrameViewAsh returns the correct minimum and maximum frame +// sizes when the client view specifies size constraints. +TEST_F(CustomFrameViewAshTest, MinimumAndMaximumSize) { + gfx::Size min_client_size(500, 500); + gfx::Size max_client_size(800, 800); + TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; + delegate->set_minimum_size(min_client_size); + delegate->set_maximum_size(max_client_size); + std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); + + CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); + gfx::Size min_frame_size = custom_frame_view->GetMinimumSize(); + gfx::Size max_frame_size = custom_frame_view->GetMaximumSize(); + + EXPECT_EQ(min_client_size.width(), min_frame_size.width()); + EXPECT_EQ(max_client_size.width(), max_frame_size.width()); + EXPECT_EQ(min_client_size.height() + delegate->GetTitleBarHeight(), + min_frame_size.height()); + EXPECT_EQ(max_client_size.height() + delegate->GetTitleBarHeight(), + max_frame_size.height()); +} + +// Verify that CustomFrameViewAsh updates the avatar icon based on the +// state of the SessionStateDelegate after visibility change. +TEST_F(CustomFrameViewAshTest, AvatarIcon) { + TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; + std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); + + CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); + EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest()); + + // Avatar image becomes available. + GetTestSessionStateDelegate()->SetUserImage( + gfx::test::CreateImage(27, 27).AsImageSkia()); + widget->Hide(); + widget->Show(); + EXPECT_TRUE(custom_frame_view->GetAvatarIconViewForTest()); + + // Avatar image is gone; the ImageView for the avatar icon should be + // removed. + GetTestSessionStateDelegate()->SetUserImage(gfx::ImageSkia()); + widget->Hide(); + widget->Show(); + EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest()); +} + +// The visibility of the size button is updated when maximize mode is toggled. +// Verify that the layout of the HeaderView is updated for the size button's +// new visibility. +TEST_F(CustomFrameViewAshTest, HeaderViewNotifiedOfChildSizeChange) { + TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; + std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); + + const gfx::Rect initial = + delegate->GetFrameCaptionButtonContainerViewBounds(); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + delegate->EndFrameCaptionButtonContainerViewAnimations(); + const gfx::Rect maximize_mode_bounds = + delegate->GetFrameCaptionButtonContainerViewBounds(); + EXPECT_GT(initial.width(), maximize_mode_bounds.width()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + delegate->EndFrameCaptionButtonContainerViewAnimations(); + const gfx::Rect after_restore = + delegate->GetFrameCaptionButtonContainerViewBounds(); + EXPECT_EQ(initial, after_restore); +} + +} // namespace ash
diff --git a/ash/common/frame/default_header_painter.cc b/ash/common/frame/default_header_painter.cc new file mode 100644 index 0000000..519cfe2 --- /dev/null +++ b/ash/common/frame/default_header_painter.cc
@@ -0,0 +1,322 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/default_header_painter.h" + +#include "ash/common/ash_layout_constants.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/header_painter_util.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/debug/leak_annotations.h" +#include "base/logging.h" // DCHECK +#include "third_party/skia/include/core/SkPath.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/scoped_canvas.h" +#include "ui/gfx/skia_util.h" +#include "ui/views/view.h" +#include "ui/views/widget/native_widget_aura.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +using views::Widget; + +namespace { + +// Color for the window title text. +const SkColor kTitleTextColor = SkColorSetRGB(40, 40, 40); +// Color of the active window header/content separator line. +const SkColor kHeaderContentSeparatorColor = SkColorSetRGB(150, 150, 152); +// Color of the inactive window header/content separator line. +const SkColor kHeaderContentSeparatorInactiveColor = + SkColorSetRGB(180, 180, 182); +// The default color of the frame. +const SkColor kDefaultFrameColor = SkColorSetRGB(242, 242, 242); +// Duration of crossfade animation for activating and deactivating frame. +const int kActivationCrossfadeDurationMs = 200; + +// Tiles an image into an area, rounding the top corners. +void TileRoundRect(gfx::Canvas* canvas, + const cc::PaintFlags& flags, + const gfx::Rect& bounds, + int corner_radius) { + SkRect rect = gfx::RectToSkRect(bounds); + const SkScalar corner_radius_scalar = SkIntToScalar(corner_radius); + SkScalar radii[8] = {corner_radius_scalar, + corner_radius_scalar, // top-left + corner_radius_scalar, + corner_radius_scalar, // top-right + 0, + 0, // bottom-right + 0, + 0}; // bottom-left + SkPath path; + path.addRoundRect(rect, radii, SkPath::kCW_Direction); + canvas->DrawPath(path, flags); +} + +// Returns the FontList to use for the title. +const gfx::FontList& GetTitleFontList() { + static const gfx::FontList* title_font_list = + new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList()); + ANNOTATE_LEAKING_OBJECT_PTR(title_font_list); + return *title_font_list; +} + +} // namespace + +namespace ash { + +/////////////////////////////////////////////////////////////////////////////// +// DefaultHeaderPainter, public: + +DefaultHeaderPainter::DefaultHeaderPainter() + : frame_(NULL), + view_(NULL), + left_header_view_(NULL), + active_frame_color_(kDefaultFrameColor), + inactive_frame_color_(kDefaultFrameColor), + caption_button_container_(NULL), + painted_height_(0), + mode_(MODE_INACTIVE), + initial_paint_(true), + activation_animation_(new gfx::SlideAnimation(this)) {} + +DefaultHeaderPainter::~DefaultHeaderPainter() {} + +void DefaultHeaderPainter::Init( + views::Widget* frame, + views::View* header_view, + FrameCaptionButtonContainerView* caption_button_container) { + DCHECK(frame); + DCHECK(header_view); + DCHECK(caption_button_container); + frame_ = frame; + view_ = header_view; + caption_button_container_ = caption_button_container; + caption_button_container_->SetButtonSize( + GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); + UpdateAllButtonImages(); +} + +int DefaultHeaderPainter::GetMinimumHeaderWidth() const { + // Ensure we have enough space for the window icon and buttons. We allow + // the title string to collapse to zero width. + return GetTitleBounds().x() + + caption_button_container_->GetMinimumSize().width(); +} + +void DefaultHeaderPainter::PaintHeader(gfx::Canvas* canvas, Mode mode) { + Mode old_mode = mode_; + mode_ = mode; + + if (mode_ != old_mode) { + UpdateAllButtonImages(); + if (!initial_paint_ && HeaderPainterUtil::CanAnimateActivation(frame_)) { + activation_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); + if (mode_ == MODE_ACTIVE) + activation_animation_->Show(); + else + activation_animation_->Hide(); + } else { + if (mode_ == MODE_ACTIVE) + activation_animation_->Reset(1); + else + activation_animation_->Reset(0); + } + initial_paint_ = false; + } + + int corner_radius = (frame_->IsMaximized() || frame_->IsFullscreen()) + ? 0 + : HeaderPainterUtil::GetTopCornerRadiusWhenRestored(); + + cc::PaintFlags flags; + int active_alpha = activation_animation_->CurrentValueBetween(0, 255); + flags.setColor(color_utils::AlphaBlend(active_frame_color_, + inactive_frame_color_, active_alpha)); + flags.setAntiAlias(true); + TileRoundRect(canvas, flags, GetLocalBounds(), corner_radius); + + if (!frame_->IsMaximized() && !frame_->IsFullscreen() && + mode_ == MODE_INACTIVE && !UsesCustomFrameColors()) { + PaintHighlightForInactiveRestoredWindow(canvas); + } + if (frame_->widget_delegate()->ShouldShowWindowTitle()) + PaintTitleBar(canvas); + if (!UsesCustomFrameColors()) + PaintHeaderContentSeparator(canvas); +} + +void DefaultHeaderPainter::LayoutHeader() { + caption_button_container_->SetUseLightImages(ShouldUseLightImages()); + UpdateSizeButtonImages(); + caption_button_container_->Layout(); + + gfx::Size caption_button_container_size = + caption_button_container_->GetPreferredSize(); + caption_button_container_->SetBounds( + view_->width() - caption_button_container_size.width(), 0, + caption_button_container_size.width(), + caption_button_container_size.height()); + + if (left_header_view_) { + // Vertically center the left header view with respect to the caption button + // container. + // Floor when computing the center of |caption_button_container_|. + gfx::Size size = left_header_view_->GetPreferredSize(); + int icon_offset_y = + caption_button_container_->height() / 2 - size.height() / 2; + left_header_view_->SetBounds(HeaderPainterUtil::GetLeftViewXInset(), + icon_offset_y, size.width(), size.height()); + } + + // The header/content separator line overlays the caption buttons. + SetHeaderHeightForPainting(caption_button_container_->height()); +} + +int DefaultHeaderPainter::GetHeaderHeight() const { + return caption_button_container_->height(); +} + +int DefaultHeaderPainter::GetHeaderHeightForPainting() const { + return painted_height_; +} + +void DefaultHeaderPainter::SetHeaderHeightForPainting(int height) { + painted_height_ = height; +} + +void DefaultHeaderPainter::SchedulePaintForTitle() { + view_->SchedulePaintInRect(GetTitleBounds()); +} + +void DefaultHeaderPainter::SetFrameColors(SkColor active_frame_color, + SkColor inactive_frame_color) { + active_frame_color_ = active_frame_color; + inactive_frame_color_ = inactive_frame_color; + UpdateAllButtonImages(); +} + +SkColor DefaultHeaderPainter::GetActiveFrameColor() const { + return active_frame_color_; +} + +SkColor DefaultHeaderPainter::GetInactiveFrameColor() const { + return inactive_frame_color_; +} + +void DefaultHeaderPainter::UpdateLeftHeaderView(views::View* left_header_view) { + left_header_view_ = left_header_view; +} + +/////////////////////////////////////////////////////////////////////////////// +// gfx::AnimationDelegate overrides: + +void DefaultHeaderPainter::AnimationProgressed( + const gfx::Animation* animation) { + view_->SchedulePaintInRect(GetLocalBounds()); +} + +/////////////////////////////////////////////////////////////////////////////// +// DefaultHeaderPainter, private: + +void DefaultHeaderPainter::PaintHighlightForInactiveRestoredWindow( + gfx::Canvas* canvas) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia top_edge = + *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_TOP); + gfx::ImageSkia left_edge = + *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_LEFT); + gfx::ImageSkia right_edge = + *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT); + gfx::ImageSkia bottom_edge = + *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM); + + int left_edge_width = left_edge.width(); + int right_edge_width = right_edge.width(); + canvas->DrawImageInt(left_edge, 0, 0); + canvas->DrawImageInt(right_edge, view_->width() - right_edge_width, 0); + canvas->TileImageInt(top_edge, left_edge_width, 0, + view_->width() - left_edge_width - right_edge_width, + top_edge.height()); + + DCHECK_EQ(left_edge.height(), right_edge.height()); + int bottom = left_edge.height(); + int bottom_height = bottom_edge.height(); + canvas->TileImageInt(bottom_edge, left_edge_width, bottom - bottom_height, + view_->width() - left_edge_width - right_edge_width, + bottom_height); +} + +void DefaultHeaderPainter::PaintTitleBar(gfx::Canvas* canvas) { + // The window icon is painted by its own views::View. + gfx::Rect title_bounds = GetTitleBounds(); + title_bounds.set_x(view_->GetMirroredXForRect(title_bounds)); + canvas->DrawStringRectWithFlags( + frame_->widget_delegate()->GetWindowTitle(), GetTitleFontList(), + kTitleTextColor, title_bounds, gfx::Canvas::NO_SUBPIXEL_RENDERING); +} + +void DefaultHeaderPainter::PaintHeaderContentSeparator(gfx::Canvas* canvas) { + gfx::ScopedCanvas scoped_canvas(canvas); + const float scale = canvas->UndoDeviceScaleFactor(); + gfx::RectF rect(0, painted_height_ * scale - 1, view_->width() * scale, 1); + cc::PaintFlags flags; + flags.setColor((mode_ == MODE_ACTIVE) ? kHeaderContentSeparatorColor + : kHeaderContentSeparatorInactiveColor); + canvas->sk_canvas()->drawRect(gfx::RectFToSkRect(rect), flags); +} + +bool DefaultHeaderPainter::ShouldUseLightImages() { + return color_utils::IsDark(mode_ == MODE_INACTIVE ? inactive_frame_color_ + : active_frame_color_); +} + +void DefaultHeaderPainter::UpdateAllButtonImages() { + caption_button_container_->SetUseLightImages(ShouldUseLightImages()); + caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_MINIMIZE, + kWindowControlMinimizeIcon); + + UpdateSizeButtonImages(); + + caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_CLOSE, + kWindowControlCloseIcon); + + caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_LEFT_SNAPPED, + kWindowControlLeftSnappedIcon); + + caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_RIGHT_SNAPPED, + kWindowControlRightSnappedIcon); +} + +void DefaultHeaderPainter::UpdateSizeButtonImages() { + const gfx::VectorIcon& icon = frame_->IsMaximized() || frame_->IsFullscreen() + ? kWindowControlRestoreIcon + : kWindowControlMaximizeIcon; + caption_button_container_->SetButtonImage( + CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, icon); +} + +gfx::Rect DefaultHeaderPainter::GetLocalBounds() const { + return gfx::Rect(view_->width(), painted_height_); +} + +gfx::Rect DefaultHeaderPainter::GetTitleBounds() const { + return HeaderPainterUtil::GetTitleBounds( + left_header_view_, caption_button_container_, GetTitleFontList()); +} + +bool DefaultHeaderPainter::UsesCustomFrameColors() const { + return active_frame_color_ != kDefaultFrameColor || + inactive_frame_color_ != kDefaultFrameColor; +} + +} // namespace ash
diff --git a/ash/common/frame/default_header_painter.h b/ash/common/frame/default_header_painter.h new file mode 100644 index 0000000..c499929 --- /dev/null +++ b/ash/common/frame/default_header_painter.h
@@ -0,0 +1,121 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_DEFAULT_HEADER_PAINTER_H_ +#define ASH_COMMON_FRAME_DEFAULT_HEADER_PAINTER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/frame/header_painter.h" +#include "base/compiler_specific.h" // override +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/animation/animation_delegate.h" + +namespace gfx { +class Rect; +class SlideAnimation; +} +namespace views { +class View; +class Widget; +} + +namespace ash { +class FrameCaptionButtonContainerView; + +// Helper class for painting the default window header. +class ASH_EXPORT DefaultHeaderPainter : public HeaderPainter, + public gfx::AnimationDelegate { + public: + DefaultHeaderPainter(); + ~DefaultHeaderPainter() override; + + // DefaultHeaderPainter does not take ownership of any of the parameters. + void Init(views::Widget* frame, + views::View* header_view, + FrameCaptionButtonContainerView* caption_button_container); + + // HeaderPainter overrides: + int GetMinimumHeaderWidth() const override; + void PaintHeader(gfx::Canvas* canvas, Mode mode) override; + void LayoutHeader() override; + int GetHeaderHeight() const override; + int GetHeaderHeightForPainting() const override; + void SetHeaderHeightForPainting(int height) override; + void SchedulePaintForTitle() override; + + // Sets the left header view for the header. Passing NULL removes the view. + void UpdateLeftHeaderView(views::View* left_header_view); + + // Sets the active and inactive frame colors. Note the inactive frame color + // will have some transparency added when the frame is drawn. + void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); + SkColor GetActiveFrameColor() const; + SkColor GetInactiveFrameColor() const; + + private: + FRIEND_TEST_ALL_PREFIXES(DefaultHeaderPainterTest, TitleIconAlignment); + FRIEND_TEST_ALL_PREFIXES(DefaultHeaderPainterTest, LightIcons); + + // gfx::AnimationDelegate override: + void AnimationProgressed(const gfx::Animation* animation) override; + + // Paints highlight around the edge of the header for inactive restored + // windows. + void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas); + + // Paints the title bar, primarily the title string. + void PaintTitleBar(gfx::Canvas* canvas); + + // Paints the header/content separator. + void PaintHeaderContentSeparator(gfx::Canvas* canvas); + + // Whether light caption images should be used. This is the case when the + // background of the frame is dark. + bool ShouldUseLightImages(); + + // Update all the images in the caption buttons. + void UpdateAllButtonImages(); + + // Updates the size button's images. + void UpdateSizeButtonImages(); + + // Returns the header bounds in the coordinates of |view_|. The header is + // assumed to be positioned at the top left corner of |view_| and to have the + // same width as |view_|. + gfx::Rect GetLocalBounds() const; + + // Returns the bounds for the title. + gfx::Rect GetTitleBounds() const; + + // Returns whether the frame uses custom frame coloring. + bool UsesCustomFrameColors() const; + + views::Widget* frame_; + views::View* view_; + views::View* left_header_view_; // May be NULL. + SkColor active_frame_color_; + SkColor inactive_frame_color_; + FrameCaptionButtonContainerView* caption_button_container_; + + // The height of the header to paint. + int painted_height_; + + // Whether the header should be painted as active. + Mode mode_; + + // Whether the header is painted for the first time. + bool initial_paint_; + + std::unique_ptr<gfx::SlideAnimation> activation_animation_; + + DISALLOW_COPY_AND_ASSIGN(DefaultHeaderPainter); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_DEFAULT_HEADER_PAINTER_H_
diff --git a/ash/common/frame/default_header_painter_unittest.cc b/ash/common/frame/default_header_painter_unittest.cc new file mode 100644 index 0000000..85d5ddd --- /dev/null +++ b/ash/common/frame/default_header_painter_unittest.cc
@@ -0,0 +1,85 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/default_header_painter.h" + +#include <memory> + +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ui/views/test/test_views.h" +#include "ui/views/widget/widget.h" +#include "ui/views/window/non_client_view.h" + +using ash::HeaderPainter; +using views::NonClientFrameView; +using views::Widget; + +namespace ash { + +using DefaultHeaderPainterTest = test::AshTestBase; + +// Ensure the title text is vertically aligned with the window icon. +TEST_F(DefaultHeaderPainterTest, TitleIconAlignment) { + std::unique_ptr<Widget> w = CreateTestWidget( + nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); + ash::FrameCaptionButtonContainerView container(w.get()); + views::StaticSizedView window_icon(gfx::Size(16, 16)); + window_icon.SetBounds(0, 0, 16, 16); + w->SetBounds(gfx::Rect(0, 0, 500, 500)); + w->Show(); + + DefaultHeaderPainter painter; + painter.Init(w.get(), w->non_client_view()->frame_view(), &container); + painter.UpdateLeftHeaderView(&window_icon); + painter.LayoutHeader(); + gfx::Rect title_bounds = painter.GetTitleBounds(); + EXPECT_EQ(window_icon.bounds().CenterPoint().y(), + title_bounds.CenterPoint().y()); +} + +// Ensure the light icons are used when appropriate. +TEST_F(DefaultHeaderPainterTest, LightIcons) { + std::unique_ptr<Widget> w = CreateTestWidget( + nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); + ash::FrameCaptionButtonContainerView container(w.get()); + views::StaticSizedView window_icon(gfx::Size(16, 16)); + window_icon.SetBounds(0, 0, 16, 16); + w->SetBounds(gfx::Rect(0, 0, 500, 500)); + w->Show(); + + DefaultHeaderPainter painter; + painter.Init(w.get(), w->non_client_view()->frame_view(), &container); + + // Check by default light icons are not used. + painter.mode_ = HeaderPainter::MODE_ACTIVE; + EXPECT_FALSE(painter.ShouldUseLightImages()); + painter.mode_ = HeaderPainter::MODE_INACTIVE; + EXPECT_FALSE(painter.ShouldUseLightImages()); + + // Check that setting dark colors should use light icons. + painter.SetFrameColors(SkColorSetRGB(0, 0, 0), SkColorSetRGB(0, 0, 0)); + painter.mode_ = HeaderPainter::MODE_ACTIVE; + EXPECT_TRUE(painter.ShouldUseLightImages()); + painter.mode_ = HeaderPainter::MODE_INACTIVE; + EXPECT_TRUE(painter.ShouldUseLightImages()); + + // Check that inactive and active colors are used properly. + painter.SetFrameColors(SkColorSetRGB(0, 0, 0), SkColorSetRGB(255, 255, 255)); + painter.mode_ = HeaderPainter::MODE_ACTIVE; + EXPECT_TRUE(painter.ShouldUseLightImages()); + painter.mode_ = HeaderPainter::MODE_INACTIVE; + EXPECT_FALSE(painter.ShouldUseLightImages()); + + // Check not so light or dark colors. + painter.SetFrameColors(SkColorSetRGB(70, 70, 70), + SkColorSetRGB(200, 200, 200)); + painter.mode_ = HeaderPainter::MODE_ACTIVE; + EXPECT_TRUE(painter.ShouldUseLightImages()); + painter.mode_ = HeaderPainter::MODE_INACTIVE; + EXPECT_FALSE(painter.ShouldUseLightImages()); +} + +} // namespace ash
diff --git a/ash/common/frame/frame_border_hit_test.cc b/ash/common/frame/frame_border_hit_test.cc new file mode 100644 index 0000000..3f0116a1 --- /dev/null +++ b/ash/common/frame/frame_border_hit_test.cc
@@ -0,0 +1,67 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/frame_border_hit_test.h" + +#include "ash/common/ash_constants.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/wm_shell.h" +#include "ui/base/hit_test.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/views/window/non_client_view.h" + +namespace ash { + +int FrameBorderNonClientHitTest( + views::NonClientFrameView* view, + FrameCaptionButtonContainerView* caption_button_container, + const gfx::Point& point_in_widget) { + gfx::Rect expanded_bounds = view->bounds(); + int outside_bounds = kResizeOutsideBoundsSize; + + if (WmShell::Get()->IsTouchDown()) + outside_bounds *= kResizeOutsideBoundsScaleForTouch; + expanded_bounds.Inset(-outside_bounds, -outside_bounds); + + if (!expanded_bounds.Contains(point_in_widget)) + return HTNOWHERE; + + // Check the frame first, as we allow a small area overlapping the contents + // to be used for resize handles. + views::Widget* frame = view->GetWidget(); + bool can_ever_resize = frame->widget_delegate()->CanResize(); + // Don't allow overlapping resize handles when the window is maximized or + // fullscreen, as it can't be resized in those states. + int resize_border = kResizeInsideBoundsSize; + if (frame->IsMaximized() || frame->IsFullscreen()) { + resize_border = 0; + can_ever_resize = false; + } + int frame_component = view->GetHTComponentForFrame( + point_in_widget, resize_border, resize_border, kResizeAreaCornerSize, + kResizeAreaCornerSize, can_ever_resize); + if (frame_component != HTNOWHERE) + return frame_component; + + int client_component = + frame->client_view()->NonClientHitTest(point_in_widget); + if (client_component != HTNOWHERE) + return client_component; + + if (caption_button_container->visible()) { + gfx::Point point_in_caption_button_container(point_in_widget); + views::View::ConvertPointFromWidget(caption_button_container, + &point_in_caption_button_container); + int caption_button_component = caption_button_container->NonClientHitTest( + point_in_caption_button_container); + if (caption_button_component != HTNOWHERE) + return caption_button_component; + } + + // Caption is a safe default. + return HTCAPTION; +} + +} // namespace ash
diff --git a/ash/common/frame/frame_border_hit_test.h b/ash/common/frame/frame_border_hit_test.h new file mode 100644 index 0000000..4c79cad --- /dev/null +++ b/ash/common/frame/frame_border_hit_test.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_FRAME_BORDER_HIT_TEST_H_ +#define ASH_COMMON_FRAME_FRAME_BORDER_HIT_TEST_H_ + +#include "ash/ash_export.h" + +namespace gfx { +class Point; +} + +namespace views { +class NonClientFrameView; +} + +namespace ash { + +class FrameCaptionButtonContainerView; + +// Returns the HitTestCompat for the specified point. +ASH_EXPORT int FrameBorderNonClientHitTest( + views::NonClientFrameView* view, + FrameCaptionButtonContainerView* caption_button_container, + const gfx::Point& point_in_widget); + +} // namespace ash + +#endif // ASH_COMMON_FRAME_FRAME_BORDER_HIT_TEST_H_
diff --git a/ash/common/frame/header_painter.h b/ash/common/frame/header_painter.h new file mode 100644 index 0000000..f60d62f --- /dev/null +++ b/ash/common/frame/header_painter.h
@@ -0,0 +1,47 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_HEADER_PAINTER_H_ +#define ASH_COMMON_FRAME_HEADER_PAINTER_H_ + +#include "ash/ash_export.h" + +namespace gfx { +class Canvas; +} + +namespace ash { + +// Helper class for painting the window header. +class ASH_EXPORT HeaderPainter { + public: + enum Mode { MODE_ACTIVE, MODE_INACTIVE }; + + virtual ~HeaderPainter() {} + + // Returns the header's minimum width. + virtual int GetMinimumHeaderWidth() const = 0; + + // Paints the header. + virtual void PaintHeader(gfx::Canvas* canvas, Mode mode) = 0; + + // Performs layout for the header. + virtual void LayoutHeader() = 0; + + // Get the height of the header. + virtual int GetHeaderHeight() const = 0; + + // Gets / sets how much of the header is painted. This allows the header to + // paint under things (like the tabstrip) which have transparent / + // non-painting sections. This height does not affect LayoutHeader(). + virtual int GetHeaderHeightForPainting() const = 0; + virtual void SetHeaderHeightForPainting(int height_for_painting) = 0; + + // Schedule a re-paint of the entire title. + virtual void SchedulePaintForTitle() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_HEADER_PAINTER_H_
diff --git a/ash/common/frame/header_painter_util.cc b/ash/common/frame/header_painter_util.cc new file mode 100644 index 0000000..6d5a11f2 --- /dev/null +++ b/ash/common/frame/header_painter_util.cc
@@ -0,0 +1,98 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/header_painter_util.h" + +#include <algorithm> + +#include "ash/common/wm_window.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animator.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace { + +// Radius of the header's top corners when the window is restored. +const int kTopCornerRadiusWhenRestored = 2; + +// Distance between left edge of the window and the leftmost view. +const int kLeftViewXInset = 9; + +// Space between the title text and the caption buttons. +const int kTitleCaptionButtonSpacing = 5; + +// Space between window icon and title text. +const int kTitleIconOffsetX = 5; + +// Space between window edge and title text, when there is no icon. +const int kTitleNoIconOffsetX = 8; + +// In the pre-Ash era the web content area had a frame along the left edge, so +// user-generated theme images for the new tab page assume they are shifted +// right relative to the header. Now that we have removed the left edge frame +// we need to copy the theme image for the window header from a few pixels +// inset to preserve alignment with the NTP image, or else we'll break a bunch +// of existing themes. We do something similar on OS X for the same reason. +const int kThemeFrameImageInsetX = 5; + +} // namespace + +namespace ash { + +// static +int HeaderPainterUtil::GetTopCornerRadiusWhenRestored() { + return kTopCornerRadiusWhenRestored; +} + +// static +int HeaderPainterUtil::GetLeftViewXInset() { + return kLeftViewXInset; +} + +// static +int HeaderPainterUtil::GetThemeBackgroundXInset() { + return kThemeFrameImageInsetX; +} + +// static +gfx::Rect HeaderPainterUtil::GetTitleBounds( + const views::View* left_view, + const views::View* right_view, + const gfx::FontList& title_font_list) { + int x = left_view ? left_view->bounds().right() + kTitleIconOffsetX + : kTitleNoIconOffsetX; + int height = title_font_list.GetHeight(); + // Floor when computing the center of |caption_button_container| and when + // computing the center of the text. + int y = std::max(0, (right_view->height() / 2) - (height / 2)); + int width = std::max(0, right_view->x() - kTitleCaptionButtonSpacing - x); + return gfx::Rect(x, y, width, height); +} + +// static +bool HeaderPainterUtil::CanAnimateActivation(views::Widget* widget) { + // Do not animate the header if the parent (e.g. + // kShellWindowId_DefaultContainer) is already animating. All of the + // implementers of HeaderPainter animate activation by continuously painting + // during the animation. This gives the parent's animation a slower frame + // rate. + // TODO(sky): Expose a better way to determine this rather than assuming the + // parent is a toplevel container. + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + // TODO(sky): GetParent()->GetLayer() is for mash until animations ported. + if (!window || !window->GetParent() || !window->GetParent()->GetLayer()) + return true; + + ui::LayerAnimator* parent_layer_animator = + window->GetParent()->GetLayer()->GetAnimator(); + return !parent_layer_animator->IsAnimatingProperty( + ui::LayerAnimationElement::OPACITY) && + !parent_layer_animator->IsAnimatingProperty( + ui::LayerAnimationElement::VISIBILITY); +} + +} // namespace ash
diff --git a/ash/common/frame/header_painter_util.h b/ash/common/frame/header_painter_util.h new file mode 100644 index 0000000..71c42ad --- /dev/null +++ b/ash/common/frame/header_painter_util.h
@@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_HEADER_PAINTER_UTIL_H_ +#define ASH_COMMON_FRAME_HEADER_PAINTER_UTIL_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" + +namespace gfx { +class FontList; +class Rect; +} +namespace views { +class View; +class Widget; +} + +namespace ash { + +// Static-only helper class for functionality used accross multiple +// implementations of HeaderPainter. +class ASH_EXPORT HeaderPainterUtil { + public: + // Returns the radius of the header's corners when the window is restored. + static int GetTopCornerRadiusWhenRestored(); + + // Returns the default distance between the left edge of the window and the + // leftmost view in the header. + static int GetLeftViewXInset(); + + // Returns the amount that the frame background is inset from the left edge of + // the window. + static int GetThemeBackgroundXInset(); + + // Returns the bounds for the header's title given the views to the left and + // right of the title, and the font used. + // |left_view| should be NULL if there is no view to the left of the title. + static gfx::Rect GetTitleBounds(const views::View* left_view, + const views::View* right_view, + const gfx::FontList& title_font_list); + + // Returns true if the header for |widget| can animate to new visuals when the + // widget's activation changes. Returns false if the header should switch to + // new visuals instantaneously. + static bool CanAnimateActivation(views::Widget* widget); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPainterUtil); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_HEADER_PAINTER_UTIL_H_
diff --git a/ash/common/frame/header_view.cc b/ash/common/frame/header_view.cc new file mode 100644 index 0000000..fbd326a --- /dev/null +++ b/ash/common/frame/header_view.cc
@@ -0,0 +1,201 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/frame/header_view.h" + +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/default_header_painter.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/gfx/canvas.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +HeaderView::HeaderView(views::Widget* target_widget) + : target_widget_(target_widget), + header_painter_(new DefaultHeaderPainter), + avatar_icon_(nullptr), + caption_button_container_(nullptr), + fullscreen_visible_fraction_(0) { + caption_button_container_ = + new FrameCaptionButtonContainerView(target_widget_); + caption_button_container_->UpdateSizeButtonVisibility(); + AddChildView(caption_button_container_); + + header_painter_->Init(target_widget_, this, caption_button_container_); + UpdateAvatarIcon(); + + WmShell::Get()->AddShellObserver(this); +} + +HeaderView::~HeaderView() { + WmShell::Get()->RemoveShellObserver(this); +} + +void HeaderView::SchedulePaintForTitle() { + header_painter_->SchedulePaintForTitle(); +} + +void HeaderView::ResetWindowControls() { + caption_button_container_->ResetWindowControls(); +} + +int HeaderView::GetPreferredOnScreenHeight() { + if (is_immersive_delegate_ && target_widget_->IsFullscreen()) { + return static_cast<int>(GetPreferredHeight() * + fullscreen_visible_fraction_); + } + return GetPreferredHeight(); +} + +int HeaderView::GetPreferredHeight() { + // Calculating the preferred height requires at least one Layout(). + if (!did_layout_) + Layout(); + return header_painter_->GetHeaderHeightForPainting(); +} + +int HeaderView::GetMinimumWidth() const { + return header_painter_->GetMinimumHeaderWidth(); +} + +void HeaderView::UpdateAvatarIcon() { + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + WmWindow* window = WmWindow::Get(target_widget_->GetNativeWindow()); + bool show = delegate->ShouldShowAvatar(window); + if (!show) { + if (!avatar_icon_) + return; + delete avatar_icon_; + avatar_icon_ = nullptr; + } else { + gfx::ImageSkia image = delegate->GetAvatarImageForWindow(window); + DCHECK_EQ(image.width(), image.height()); + if (!avatar_icon_) { + avatar_icon_ = new views::ImageView(); + AddChildView(avatar_icon_); + } + avatar_icon_->SetImage(image); + } + header_painter_->UpdateLeftHeaderView(avatar_icon_); + Layout(); +} + +void HeaderView::SizeConstraintsChanged() { + caption_button_container_->ResetWindowControls(); + caption_button_container_->UpdateSizeButtonVisibility(); + Layout(); +} + +void HeaderView::SetFrameColors(SkColor active_frame_color, + SkColor inactive_frame_color) { + header_painter_->SetFrameColors(active_frame_color, inactive_frame_color); +} + +SkColor HeaderView::GetActiveFrameColor() const { + return header_painter_->GetActiveFrameColor(); +} + +SkColor HeaderView::GetInactiveFrameColor() const { + return header_painter_->GetInactiveFrameColor(); +} + +/////////////////////////////////////////////////////////////////////////////// +// HeaderView, views::View overrides: + +void HeaderView::Layout() { + did_layout_ = true; + header_painter_->LayoutHeader(); +} + +void HeaderView::OnPaint(gfx::Canvas* canvas) { + bool paint_as_active = + target_widget_->non_client_view()->frame_view()->ShouldPaintAsActive(); + caption_button_container_->SetPaintAsActive(paint_as_active); + + HeaderPainter::Mode header_mode = paint_as_active + ? HeaderPainter::MODE_ACTIVE + : HeaderPainter::MODE_INACTIVE; + header_painter_->PaintHeader(canvas, header_mode); +} + +void HeaderView::ChildPreferredSizeChanged(views::View* child) { + // FrameCaptionButtonContainerView animates the visibility changes in + // UpdateSizeButtonVisibility(false). Due to this a new size is not available + // until the completion of the animation. Layout in response to the preferred + // size changes. + if (child != caption_button_container_) + return; + parent()->Layout(); +} + +/////////////////////////////////////////////////////////////////////////////// +// HeaderView, ShellObserver overrides: + +void HeaderView::OnOverviewModeStarting() { + caption_button_container_->SetVisible(false); +} + +void HeaderView::OnOverviewModeEnded() { + caption_button_container_->SetVisible(true); +} + +void HeaderView::OnMaximizeModeStarted() { + caption_button_container_->UpdateSizeButtonVisibility(); + parent()->Layout(); +} + +void HeaderView::OnMaximizeModeEnded() { + caption_button_container_->UpdateSizeButtonVisibility(); + parent()->Layout(); +} + +views::View* HeaderView::avatar_icon() const { + return avatar_icon_; +} + +/////////////////////////////////////////////////////////////////////////////// +// HeaderView, +// ImmersiveFullscreenControllerDelegate overrides: + +void HeaderView::OnImmersiveRevealStarted() { + fullscreen_visible_fraction_ = 0; + SetPaintToLayer(); + parent()->Layout(); +} + +void HeaderView::OnImmersiveRevealEnded() { + fullscreen_visible_fraction_ = 0; + DestroyLayer(); + parent()->Layout(); +} + +void HeaderView::OnImmersiveFullscreenExited() { + fullscreen_visible_fraction_ = 0; + DestroyLayer(); + parent()->Layout(); +} + +void HeaderView::SetVisibleFraction(double visible_fraction) { + if (fullscreen_visible_fraction_ != visible_fraction) { + fullscreen_visible_fraction_ = visible_fraction; + parent()->Layout(); + } +} + +std::vector<gfx::Rect> HeaderView::GetVisibleBoundsInScreen() const { + // TODO(pkotwicz): Implement views::View::ConvertRectToScreen(). + gfx::Rect visible_bounds(GetVisibleBounds()); + gfx::Point visible_origin_in_screen(visible_bounds.origin()); + views::View::ConvertPointToScreen(this, &visible_origin_in_screen); + std::vector<gfx::Rect> bounds_in_screen; + bounds_in_screen.push_back( + gfx::Rect(visible_origin_in_screen, visible_bounds.size())); + return bounds_in_screen; +} + +} // namespace ash
diff --git a/ash/common/frame/header_view.h b/ash/common/frame/header_view.h new file mode 100644 index 0000000..d96a62a3 --- /dev/null +++ b/ash/common/frame/header_view.h
@@ -0,0 +1,116 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_FRAME_HEADER_VIEW_H_ +#define ASH_COMMON_FRAME_HEADER_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/shared/immersive_fullscreen_controller_delegate.h" +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/views/view.h" + +namespace views { +class ImageView; +class Widget; +} + +namespace ash { + +class DefaultHeaderPainter; +class FrameCaptionButtonContainerView; + +// View which paints the frame header (title, caption buttons...). It slides off +// and on screen in immersive fullscreen. +class ASH_EXPORT HeaderView : public views::View, + public ImmersiveFullscreenControllerDelegate, + public ShellObserver { + public: + // |target_widget| is the widget that the caption buttons act on. + // |target_widget| is not necessarily the same as the widget the header is + // placed in. For example, in immersive fullscreen this view may be painted in + // a widget that slides in and out on top of the main app or browser window. + // However, clicking a caption button should act on the target widget. + explicit HeaderView(views::Widget* target_widget); + ~HeaderView() override; + + void set_is_immersive_delegate(bool value) { is_immersive_delegate_ = value; } + + // Schedules a repaint for the entire title. + void SchedulePaintForTitle(); + + // Tells the window controls to reset themselves to the normal state. + void ResetWindowControls(); + + // Returns the amount of the view's pixels which should be on screen. + int GetPreferredOnScreenHeight(); + + // Returns the view's preferred height. + int GetPreferredHeight(); + + // Returns the view's minimum width. + int GetMinimumWidth() const; + + void UpdateAvatarIcon(); + + void SizeConstraintsChanged(); + + void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); + SkColor GetActiveFrameColor() const; + SkColor GetInactiveFrameColor() const; + + // views::View: + void Layout() override; + void OnPaint(gfx::Canvas* canvas) override; + void ChildPreferredSizeChanged(views::View* child) override; + + // ShellObserver: + void OnOverviewModeStarting() override; + void OnOverviewModeEnded() override; + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + + FrameCaptionButtonContainerView* caption_button_container() { + return caption_button_container_; + } + + views::View* avatar_icon() const; + + private: + // ImmersiveFullscreenControllerDelegate: + void OnImmersiveRevealStarted() override; + void OnImmersiveRevealEnded() override; + void OnImmersiveFullscreenExited() override; + void SetVisibleFraction(double visible_fraction) override; + std::vector<gfx::Rect> GetVisibleBoundsInScreen() const override; + + // The widget that the caption buttons act on. + views::Widget* target_widget_; + + // Helper for painting the header. + std::unique_ptr<DefaultHeaderPainter> header_painter_; + + views::ImageView* avatar_icon_; + + // View which contains the window caption buttons. + FrameCaptionButtonContainerView* caption_button_container_; + + // The fraction of the header's height which is visible while in fullscreen. + // This value is meaningless when not in fullscreen. + double fullscreen_visible_fraction_; + + // Has this instance been set as the ImmersiveFullscreenControllerDelegate? + bool is_immersive_delegate_ = true; + + bool did_layout_ = false; + + DISALLOW_COPY_AND_ASSIGN(HeaderView); +}; + +} // namespace ash + +#endif // ASH_COMMON_FRAME_HEADER_VIEW_H_
diff --git a/ash/common/keyboard/keyboard_ui.cc b/ash/common/keyboard/keyboard_ui.cc index 35af6b1..37fcc44 100644 --- a/ash/common/keyboard/keyboard_ui.cc +++ b/ash/common/keyboard/keyboard_ui.cc
@@ -6,10 +6,10 @@ #include "ash/common/accessibility_delegate.h" #include "ash/common/keyboard/keyboard_ui_observer.h" +#include "ash/common/system/accessibility_observer.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray_accessibility.h" #include "ash/common/wm_shell.h" -#include "ash/system/accessibility_observer.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray_accessibility.h" #include "base/memory/ptr_util.h" #include "ui/keyboard/keyboard_controller.h"
diff --git a/ash/common/metrics/OWNERS b/ash/common/metrics/OWNERS new file mode 100644 index 0000000..21cb7090 --- /dev/null +++ b/ash/common/metrics/OWNERS
@@ -0,0 +1 @@ +tdanderson@chromium.org
diff --git a/ash/common/metrics/gesture_action_type.h b/ash/common/metrics/gesture_action_type.h new file mode 100644 index 0000000..feee85a --- /dev/null +++ b/ash/common/metrics/gesture_action_type.h
@@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_METRICS_GESTURE_ACTION_TYPE_H_ +#define ASH_COMMON_METRICS_GESTURE_ACTION_TYPE_H_ + +namespace ash { + +enum GestureActionType { + GESTURE_UNKNOWN, + GESTURE_OMNIBOX_PINCH, + GESTURE_OMNIBOX_SCROLL, + GESTURE_TABSTRIP_PINCH, + GESTURE_TABSTRIP_SCROLL, + GESTURE_BEZEL_SCROLL, + GESTURE_DESKTOP_SCROLL, + GESTURE_DESKTOP_PINCH, + GESTURE_WEBPAGE_PINCH, + GESTURE_WEBPAGE_SCROLL, + GESTURE_WEBPAGE_TAP, + GESTURE_TABSTRIP_TAP, + GESTURE_BEZEL_DOWN, + GESTURE_TABSWITCH_TAP, + GESTURE_TABNOSWITCH_TAP, + GESTURE_TABCLOSE_TAP, + GESTURE_NEWTAB_TAP, + GESTURE_ROOTVIEWTOP_TAP, + GESTURE_FRAMEMAXIMIZE_TAP, + GESTURE_FRAMEVIEW_TAP, + GESTURE_MAXIMIZE_DOUBLETAP, + // NOTE: Add new action types only immediately above this line. Also, + // make sure the enum list in tools/histogram/histograms.xml is + // updated with any change in here. + GESTURE_ACTION_COUNT +}; + +} // namespace ash + +#endif // ASH_COMMON_METRICS_GESTURE_ACTION_TYPE_H_
diff --git a/ash/common/metrics/pointer_metrics_recorder.cc b/ash/common/metrics/pointer_metrics_recorder.cc new file mode 100644 index 0000000..be9e91cb3 --- /dev/null +++ b/ash/common/metrics/pointer_metrics_recorder.cc
@@ -0,0 +1,106 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/metrics/pointer_metrics_recorder.h" + +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/shared/app_types.h" +#include "base/metrics/histogram_macros.h" +#include "ui/events/event_constants.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { + +// Form factor of the down event. This enum is used to back an UMA histogram +// and new values should be inserted immediately above FORM_FACTOR_COUNT. +enum class DownEventFormFactor { + CLAMSHELL = 0, + TOUCH_VIEW, + FORM_FACTOR_COUNT, +}; + +// Input type of the down event. This enum is used to back an UMA +// histogram and new values should be inserted immediately above SOURCE_COUNT. +enum class DownEventSource { + UNKNOWN = 0, + MOUSE, + STYLUS, + TOUCH, + SOURCE_COUNT, +}; + +int GetDestination(views::Widget* target) { + if (!target) + return static_cast<int>(AppType::OTHERS); + + WmWindow* window = WmWindow::Get(target->GetNativeWindow()); + DCHECK(window); + return window->GetAppType(); +} + +void RecordUMA(ui::EventPointerType type, views::Widget* target) { + DownEventFormFactor form_factor = DownEventFormFactor::CLAMSHELL; + if (ash::WmShell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled()) { + form_factor = DownEventFormFactor::TOUCH_VIEW; + } + UMA_HISTOGRAM_ENUMERATION( + "Event.DownEventCount.PerFormFactor", + static_cast<base::HistogramBase::Sample>(form_factor), + static_cast<base::HistogramBase::Sample>( + DownEventFormFactor::FORM_FACTOR_COUNT)); + + DownEventSource input_type = DownEventSource::UNKNOWN; + switch (type) { + case ui::EventPointerType::POINTER_TYPE_UNKNOWN: + input_type = DownEventSource::UNKNOWN; + break; + case ui::EventPointerType::POINTER_TYPE_MOUSE: + input_type = DownEventSource::MOUSE; + break; + case ui::EventPointerType::POINTER_TYPE_PEN: + input_type = DownEventSource::STYLUS; + break; + case ui::EventPointerType::POINTER_TYPE_TOUCH: + input_type = DownEventSource::TOUCH; + break; + case ui::EventPointerType::POINTER_TYPE_ERASER: + input_type = DownEventSource::STYLUS; + break; + } + + UMA_HISTOGRAM_ENUMERATION( + "Event.DownEventCount.PerInput", + static_cast<base::HistogramBase::Sample>(input_type), + static_cast<base::HistogramBase::Sample>(DownEventSource::SOURCE_COUNT)); + + UMA_HISTOGRAM_ENUMERATION("Event.DownEventCount.PerDestination", + GetDestination(target), kAppCount); +} + +} // namespace + +PointerMetricsRecorder::PointerMetricsRecorder() { + ash::WmShell::Get()->AddPointerWatcher( + this, views::PointerWatcherEventTypes::BASIC); +} + +PointerMetricsRecorder::~PointerMetricsRecorder() { + ash::WmShell::Get()->RemovePointerWatcher(this); +} + +void PointerMetricsRecorder::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + if (event.type() == ui::ET_POINTER_DOWN) + RecordUMA(event.pointer_details().pointer_type, target); +} + +} // namespace ash
diff --git a/ash/common/metrics/pointer_metrics_recorder.h b/ash/common/metrics/pointer_metrics_recorder.h new file mode 100644 index 0000000..bf19e909 --- /dev/null +++ b/ash/common/metrics/pointer_metrics_recorder.h
@@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_ASH_COMMON_METRICS_POINTER_METRICS_RECORDER_H_ +#define UI_ASH_COMMON_METRICS_POINTER_METRICS_RECORDER_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/views/pointer_watcher.h" + +namespace gfx { +class Point; +} + +namespace ui { +class PointerEvent; +} + +namespace ash { + +// A metrics recorder that records pointer related metrics. +class ASH_EXPORT PointerMetricsRecorder : public views::PointerWatcher { + public: + PointerMetricsRecorder(); + ~PointerMetricsRecorder() override; + + // views::PointerWatcher: + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; + + private: + DISALLOW_COPY_AND_ASSIGN(PointerMetricsRecorder); +}; + +} // namespace ash + +#endif // UI_ASH_COMMON_METRICS_POINTER_METRICS_RECORDER_H_
diff --git a/ash/common/metrics/pointer_metrics_recorder_unittest.cc b/ash/common/metrics/pointer_metrics_recorder_unittest.cc new file mode 100644 index 0000000..ed212cd --- /dev/null +++ b/ash/common/metrics/pointer_metrics_recorder_unittest.cc
@@ -0,0 +1,185 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/metrics/pointer_metrics_recorder.h" + +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/shared/app_types.h" +#include "ash/test/ash_test_base.h" +#include "base/test/histogram_tester.h" +#include "ui/events/event.h" +#include "ui/views/pointer_watcher.h" +#include "ui/views/widget/widget.h" + +using views::PointerWatcher; + +namespace ash { +namespace { + +const char kFormFactorHistogramName[] = "Event.DownEventCount.PerFormFactor"; +const char kInputHistogramName[] = "Event.DownEventCount.PerInput"; +const char kDestinationHistogramName[] = "Event.DownEventCount.PerDestination"; + +// Test fixture for the PointerMetricsRecorder class. +class PointerMetricsRecorderTest : public test::AshTestBase { + public: + PointerMetricsRecorderTest(); + ~PointerMetricsRecorderTest() override; + + // test::AshTestBase: + void SetUp() override; + void TearDown() override; + + protected: + // The test target. + std::unique_ptr<PointerMetricsRecorder> pointer_metrics_recorder_; + + // Used to verify recorded data. + std::unique_ptr<base::HistogramTester> histogram_tester_; + + private: + DISALLOW_COPY_AND_ASSIGN(PointerMetricsRecorderTest); +}; + +PointerMetricsRecorderTest::PointerMetricsRecorderTest() {} + +PointerMetricsRecorderTest::~PointerMetricsRecorderTest() {} + +void PointerMetricsRecorderTest::SetUp() { + test::AshTestBase::SetUp(); + pointer_metrics_recorder_.reset(new PointerMetricsRecorder()); + histogram_tester_.reset(new base::HistogramTester()); +} + +void PointerMetricsRecorderTest::TearDown() { + pointer_metrics_recorder_.reset(); + test::AshTestBase::TearDown(); +} + +} // namespace + +// Verifies that histogram is not recorded when receiving events that are not +// down events. +TEST_F(PointerMetricsRecorderTest, NonDownEventsInAllPointerHistogram) { + std::unique_ptr<views::Widget> target = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + const ui::PointerEvent pointer_event( + ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), + base::TimeTicks()); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + + histogram_tester_->ExpectTotalCount(kFormFactorHistogramName, 0); + histogram_tester_->ExpectTotalCount(kInputHistogramName, 0); + histogram_tester_->ExpectTotalCount(kDestinationHistogramName, 0); +} + +// Verifies that down events from different inputs are recorded. +TEST_F(PointerMetricsRecorderTest, DownEventPerInput) { + std::unique_ptr<views::Widget> target = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + + const ui::PointerEvent unknown_event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_UNKNOWN), + base::TimeTicks()); + pointer_metrics_recorder_->OnPointerEventObserved(unknown_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kInputHistogramName, 0, 1); + + const ui::PointerEvent mouse_event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), + base::TimeTicks()); + pointer_metrics_recorder_->OnPointerEventObserved(mouse_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kInputHistogramName, 1, 1); + + const ui::PointerEvent stylus_event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN), + base::TimeTicks()); + pointer_metrics_recorder_->OnPointerEventObserved(stylus_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kInputHistogramName, 2, 1); + + const ui::PointerEvent stylus_event2( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_ERASER), + base::TimeTicks()); + pointer_metrics_recorder_->OnPointerEventObserved(stylus_event2, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kInputHistogramName, 2, 2); + + const ui::PointerEvent touch_event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), + base::TimeTicks()); + pointer_metrics_recorder_->OnPointerEventObserved(touch_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kInputHistogramName, 3, 1); +} + +// Verifies that down events in different form factors are recorded. +TEST_F(PointerMetricsRecorderTest, DownEventPerFormFactor) { + std::unique_ptr<views::Widget> target = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + const ui::PointerEvent pointer_event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), + base::TimeTicks()); + + // Enable maximize mode + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kFormFactorHistogramName, 1, 1); + + // Disable maximize mode + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kFormFactorHistogramName, 0, 1); +} + +// Verifies that down events dispatched to different destinations are recorded. +TEST_F(PointerMetricsRecorderTest, DownEventPerDestination) { + std::unique_ptr<views::Widget> target = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + const ui::PointerEvent pointer_event( + ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, + ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), + base::TimeTicks()); + + WmWindow* window = WmWindow::Get(target->GetNativeWindow()); + CHECK(window); + + window->SetAppType(static_cast<int>(AppType::OTHERS)); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 0, 1); + + window->SetAppType(static_cast<int>(AppType::BROWSER)); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 1, 1); + + window->SetAppType(static_cast<int>(AppType::CHROME_APP)); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 2, 1); + + window->SetAppType(static_cast<int>(AppType::ARC_APP)); + pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), + target.get()); + histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 3, 1); +} + +} // namespace ash
diff --git a/ash/common/metrics/task_switch_source.h b/ash/common/metrics/task_switch_source.h new file mode 100644 index 0000000..6b1bf0e --- /dev/null +++ b/ash/common/metrics/task_switch_source.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_METRICS_TASK_SWITCH_SOURCE_H_ +#define ASH_COMMON_METRICS_TASK_SWITCH_SOURCE_H_ + +namespace ash { + +// Enumeration of the different user interfaces that could be the source of +// a task switch. Note this is not necessarily comprehensive of all sources. +enum class TaskSwitchSource { + // Task switches caused by any two sources in this enum. NOTE: This value + // should NOT be used outside of TaskSwitchMetricsRecorder. + ANY, + // Task switches caused by the user activating a task window by clicking or + // tapping on it. + DESKTOP, + // Task switches caused by selecting a window from overview mode which is + // different from the previously-active window. + OVERVIEW_MODE, + // All task switches caused by shelf buttons, not including sub-menus. + SHELF, + // Task switches caused by the WindowCycleController (ie Alt+Tab). + WINDOW_CYCLE_CONTROLLER +}; + +} // namespace ash + +#endif // ASH_COMMON_METRICS_TASK_SWITCH_SOURCE_H_
diff --git a/ash/common/metrics/user_metrics_action.h b/ash/common/metrics/user_metrics_action.h new file mode 100644 index 0000000..0c6917a0 --- /dev/null +++ b/ash/common/metrics/user_metrics_action.h
@@ -0,0 +1,150 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_METRICS_USER_METRICS_ACTION_H_ +#define ASH_COMMON_METRICS_USER_METRICS_ACTION_H_ + +namespace ash { + +// Ash-owned user metrics. +enum UserMetricsAction { + UMA_ACCEL_EXIT_FIRST_Q, + UMA_ACCEL_EXIT_SECOND_Q, + UMA_ACCEL_KEYBOARD_BRIGHTNESS_DOWN_F6, + UMA_ACCEL_KEYBOARD_BRIGHTNESS_UP_F7, + UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON, + UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON, + UMA_ACCEL_MAXIMIZE_RESTORE_F4, + UMA_ACCEL_PREVWINDOW_F5, + UMA_ACCEL_RESTART_POWER_BUTTON, + UMA_ACCEL_SHUT_DOWN_POWER_BUTTON, + UMA_CLOSE_THROUGH_CONTEXT_MENU, + UMA_DESKTOP_SWITCH_TASK, + UMA_DRAG_MAXIMIZE_LEFT, + UMA_DRAG_MAXIMIZE_RIGHT, + UMA_LAUNCHER_BUTTON_PRESSED_WITH_MOUSE, + UMA_LAUNCHER_BUTTON_PRESSED_WITH_TOUCH, + UMA_LAUNCHER_CLICK_ON_APP, + UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON, + UMA_LAUNCHER_LAUNCH_TASK, + UMA_LAUNCHER_MINIMIZE_TASK, + UMA_LAUNCHER_SWITCH_TASK, + UMA_MAXIMIZE_MODE_DISABLED, + UMA_MAXIMIZE_MODE_ENABLED, + UMA_MAXIMIZE_MODE_INITIALLY_DISABLED, + UMA_MOUSE_DOWN, + UMA_PANEL_MINIMIZE_CAPTION_CLICK, + UMA_PANEL_MINIMIZE_CAPTION_GESTURE, + UMA_SHELF_ALIGNMENT_SET_BOTTOM, + UMA_SHELF_ALIGNMENT_SET_LEFT, + UMA_SHELF_ALIGNMENT_SET_RIGHT, + UMA_STATUS_AREA_AUDIO_CURRENT_INPUT_DEVICE, + UMA_STATUS_AREA_AUDIO_CURRENT_OUTPUT_DEVICE, + UMA_STATUS_AREA_AUDIO_SWITCH_INPUT_DEVICE, + UMA_STATUS_AREA_AUDIO_SWITCH_OUTPUT_DEVICE, + UMA_STATUS_AREA_BRIGHTNESS_CHANGED, + UMA_STATUS_AREA_BLUETOOTH_DISABLED, + UMA_STATUS_AREA_BLUETOOTH_ENABLED, + UMA_STATUS_AREA_CAPS_LOCK_DETAILED, + UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK, + UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK, + UMA_STATUS_AREA_CAPS_LOCK_POPUP, + UMA_STATUS_AREA_CAST_STOP_CAST, + UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK, + UMA_STATUS_AREA_CONNECT_TO_UNCONFIGURED_NETWORK, + UMA_STATUS_AREA_CONNECT_TO_VPN, + UMA_STATUS_AREA_CHANGED_VOLUME_MENU, + UMA_STATUS_AREA_CHANGED_VOLUME_POPUP, + UMA_STATUS_AREA_DETAILED_ACCESSABILITY, + UMA_STATUS_AREA_DETAILED_AUDIO_VIEW, + UMA_STATUS_AREA_DETAILED_BLUETOOTH_VIEW, + UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW, + UMA_STATUS_AREA_DETAILED_CAST_VIEW, + UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST, + UMA_STATUS_AREA_DETAILED_DRIVE_VIEW, + UMA_STATUS_AREA_DETAILED_NETWORK_VIEW, + UMA_STATUS_AREA_DETAILED_SMS_VIEW, + UMA_STATUS_AREA_DETAILED_VPN_VIEW, + UMA_STATUS_AREA_DISABLE_AUTO_CLICK, + UMA_STATUS_AREA_DISABLE_HIGH_CONTRAST, + UMA_STATUS_AREA_DISABLE_LARGE_CURSOR, + UMA_STATUS_AREA_DISABLE_MAGNIFIER, + UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK, + UMA_STATUS_AREA_DISABLE_WIFI, + UMA_STATUS_AREA_DISABLE_VIRTUAL_KEYBOARD, + UMA_STATUS_AREA_DISPLAY_DEFAULT_SELECTED, + UMA_STATUS_AREA_DISPLAY_DEFAULT_SHOW_SETTINGS, + UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED, + UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED, + UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS, + UMA_STATUS_AREA_DRIVE_CANCEL_OPERATION, + UMA_STATUS_AREA_DRIVE_SETTINGS, + UMA_STATUS_AREA_ENABLE_AUTO_CLICK, + UMA_STATUS_AREA_ENABLE_HIGH_CONTRAST, + UMA_STATUS_AREA_ENABLE_LARGE_CURSOR, + UMA_STATUS_AREA_ENABLE_MAGNIFIER, + UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK, + UMA_STATUS_AREA_ENABLE_WIFI, + UMA_STATUS_AREA_ENABLE_VIRTUAL_KEYBOARD, + UMA_STATUS_AREA_IME_SHOW_DETAILED, + UMA_STATUS_AREA_IME_SWITCH_MODE, + UMA_STATUS_AREA_MENU_OPENED, + UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED, + UMA_STATUS_AREA_NETWORK_SETTINGS_OPENED, + UMA_STATUS_AREA_OS_UPDATE_DEFAULT_SELECTED, + UMA_STATUS_AREA_SCREEN_CAPTURE_DEFAULT_STOP, + UMA_STATUS_AREA_SCREEN_CAPTURE_NOTIFICATION_STOP, + UMA_STATUS_AREA_SHOW_NETWORK_CONNECTION_DETAILS, + UMA_STATUS_AREA_SHOW_VPN_CONNECTION_DETAILS, + UMA_STATUS_AREA_SIGN_OUT, + UMA_STATUS_AREA_SMS_DETAILED_DISMISS_MSG, + UMA_STATUS_AREA_SMS_NOTIFICATION_DISMISS_MSG, + UMA_STATUS_AREA_TRACING_DEFAULT_SELECTED, + UMA_STATUS_AREA_VPN_ADD_BUILT_IN_CLICKED, + UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED, + UMA_STATUS_AREA_VPN_DISCONNECT_CLICKED, + UMA_STATUS_AREA_VPN_SETTINGS_OPENED, + UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK, + UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE, + UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK, + UMA_TOUCHPAD_GESTURE_OVERVIEW, + UMA_TOUCHSCREEN_TAP_DOWN, + UMA_TRAY_HELP, + UMA_TRAY_LOCK_SCREEN, + UMA_TRAY_OVERVIEW, + UMA_TRAY_SETTINGS, + UMA_TRAY_SHUT_DOWN, + UMA_WINDOW_APP_CLOSE_BUTTON_CLICK, + UMA_WINDOW_CLOSE_BUTTON_CLICK, + UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN, + UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE, + UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE, + UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE, + UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT, + UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT, + + // Window selection started by beginning an alt+tab cycle. This does not count + // each step through an alt+tab cycle. + UMA_WINDOW_CYCLE, + + // Thumbnail sized overview of windows triggered by pressing the overview key. + UMA_WINDOW_OVERVIEW, + + // User selected a window in overview mode different from the + // previously-active window. + UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED, + + // Selecting a window in overview mode by pressing the enter key. + UMA_WINDOW_OVERVIEW_ENTER_KEY, + + // Closing a window in overview mode by clicking the 'X' button. + UMA_WINDOW_OVERVIEW_CLOSE_BUTTON, + + // Closing a window in overview mode by pressing Ctrl+w shortcut. + UMA_WINDOW_OVERVIEW_CLOSE_KEY, +}; + +} // namespace ash + +#endif // ASH_COMMON_METRICS_USER_METRICS_ACTION_H_
diff --git a/ash/common/mojo_interface_factory.cc b/ash/common/mojo_interface_factory.cc index 74a87496..501c006 100644 --- a/ash/common/mojo_interface_factory.cc +++ b/ash/common/mojo_interface_factory.cc
@@ -6,20 +6,20 @@ #include <utility> -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/cast_config_controller.h" #include "ash/common/media_controller.h" #include "ash/common/new_window_controller.h" #include "ash/common/session/session_controller.h" +#include "ash/common/shelf/shelf_controller.h" #include "ash/common/shell_delegate.h" #include "ash/common/shutdown_controller.h" +#include "ash/common/system/chromeos/network/vpn_list.h" +#include "ash/common/system/locale/locale_notification_controller.h" +#include "ash/common/system/tray/system_tray_controller.h" #include "ash/common/wallpaper/wallpaper_controller.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_controller.h" -#include "ash/system/locale/locale_notification_controller.h" -#include "ash/system/network/vpn_list.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/bind.h" #include "services/service_manager/public/cpp/interface_registry.h" #include "ui/app_list/presenter/app_list.h"
diff --git a/ash/common/mus_property_mirror_ash_unittest.cc b/ash/common/mus_property_mirror_ash_unittest.cc index a869e86..e81f05b0 100644 --- a/ash/common/mus_property_mirror_ash_unittest.cc +++ b/ash/common/mus_property_mirror_ash_unittest.cc
@@ -6,9 +6,9 @@ #include <string> +#include "ash/common/test/ash_test.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/window_properties.h" -#include "ash/test/ash_test.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/client/aura_constants.h"
diff --git a/ash/common/shelf/app_list_button.cc b/ash/common/shelf/app_list_button.cc new file mode 100644 index 0000000..361d96b --- /dev/null +++ b/ash/common/shelf/app_list_button.cc
@@ -0,0 +1,216 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/app_list_button.h" + +#include "ash/common/shelf/ink_drop_button_listener.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/ptr_util.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/scoped_canvas.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/painter.h" + +namespace ash { + +AppListButton::AppListButton(InkDropButtonListener* listener, + ShelfView* shelf_view, + WmShelf* wm_shelf) + : views::ImageButton(nullptr), + is_showing_app_list_(false), + background_color_(kShelfDefaultBaseColor), + listener_(listener), + shelf_view_(shelf_view), + wm_shelf_(wm_shelf) { + DCHECK(listener_); + DCHECK(shelf_view_); + DCHECK(wm_shelf_); + + SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER); + set_ink_drop_base_color(kShelfInkDropBaseColor); + set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); + SetAccessibleName( + l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE)); + SetSize( + gfx::Size(GetShelfConstant(SHELF_SIZE), GetShelfConstant(SHELF_SIZE))); + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + set_notify_action(CustomButton::NOTIFY_ON_PRESS); +} + +AppListButton::~AppListButton() {} + +void AppListButton::OnAppListShown() { + AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr); + is_showing_app_list_ = true; + wm_shelf_->UpdateAutoHideState(); +} + +void AppListButton::OnAppListDismissed() { + AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr); + is_showing_app_list_ = false; + wm_shelf_->UpdateAutoHideState(); +} + +void AppListButton::UpdateShelfItemBackground(SkColor color) { + background_color_ = color; + SchedulePaint(); +} + +bool AppListButton::OnMousePressed(const ui::MouseEvent& event) { + ImageButton::OnMousePressed(event); + shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); + return true; +} + +void AppListButton::OnMouseReleased(const ui::MouseEvent& event) { + ImageButton::OnMouseReleased(event); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); +} + +void AppListButton::OnMouseCaptureLost() { + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, true); + ImageButton::OnMouseCaptureLost(); +} + +bool AppListButton::OnMouseDragged(const ui::MouseEvent& event) { + ImageButton::OnMouseDragged(event); + shelf_view_->PointerDraggedOnButton(this, ShelfView::MOUSE, event); + return true; +} + +void AppListButton::OnGestureEvent(ui::GestureEvent* event) { + switch (event->type()) { + case ui::ET_GESTURE_SCROLL_BEGIN: + AnimateInkDrop(views::InkDropState::HIDDEN, event); + shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); + event->SetHandled(); + return; + case ui::ET_GESTURE_SCROLL_UPDATE: + shelf_view_->PointerDraggedOnButton(this, ShelfView::TOUCH, *event); + event->SetHandled(); + return; + case ui::ET_GESTURE_SCROLL_END: + case ui::ET_SCROLL_FLING_START: + shelf_view_->PointerReleasedOnButton(this, ShelfView::TOUCH, false); + event->SetHandled(); + return; + case ui::ET_GESTURE_TAP_DOWN: + if (!WmShell::Get()->IsApplistVisible()) + AnimateInkDrop(views::InkDropState::ACTION_PENDING, event); + ImageButton::OnGestureEvent(event); + break; + default: + ImageButton::OnGestureEvent(event); + return; + } +} + +void AppListButton::OnPaint(gfx::Canvas* canvas) { + // Call the base class first to paint any background/borders. + View::OnPaint(canvas); + + gfx::PointF circle_center(GetCenterPoint()); + + // Paint the circular background. + cc::PaintFlags bg_flags; + bg_flags.setColor(background_color_); + bg_flags.setAntiAlias(true); + bg_flags.setStyle(cc::PaintFlags::kFill_Style); + canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); + + // Paint a white ring as the foreground. The ceil/dsf math assures that the + // ring draws sharply and is centered at all scale factors. + const float kRingOuterRadiusDp = 7.f; + const float kRingThicknessDp = 1.5f; + gfx::ScopedCanvas scoped_canvas(canvas); + const float dsf = canvas->UndoDeviceScaleFactor(); + circle_center.Scale(dsf); + + cc::PaintFlags fg_flags; + fg_flags.setAntiAlias(true); + fg_flags.setStyle(cc::PaintFlags::kStroke_Style); + fg_flags.setColor(kShelfIconColor); + const float thickness = std::ceil(kRingThicknessDp * dsf); + const float radius = std::ceil(kRingOuterRadiusDp * dsf) - thickness / 2; + fg_flags.setStrokeWidth(thickness); + // Make sure the center of the circle lands on pixel centers. + canvas->DrawCircle(circle_center, radius, fg_flags); + + views::Painter::PaintFocusPainter(this, canvas, focus_painter()); +} + +void AppListButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_BUTTON; + node_data->SetName(shelf_view_->GetTitleForView(this)); +} + +std::unique_ptr<views::InkDropRipple> AppListButton::CreateInkDropRipple() + const { + gfx::Point center = GetCenterPoint(); + gfx::Rect bounds(center.x() - kAppListButtonRadius, + center.y() - kAppListButtonRadius, 2 * kAppListButtonRadius, + 2 * kAppListButtonRadius); + return base::MakeUnique<views::FloodFillInkDropRipple>( + size(), GetLocalBounds().InsetsFrom(bounds), + GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(), + ink_drop_visible_opacity()); +} + +void AppListButton::NotifyClick(const ui::Event& event) { + ImageButton::NotifyClick(event); + if (listener_) + listener_->ButtonPressed(this, event, GetInkDrop()); +} + +bool AppListButton::ShouldEnterPushedState(const ui::Event& event) { + if (!shelf_view_->ShouldEventActivateButton(this, event)) + return false; + if (WmShell::Get()->IsApplistVisible()) + return false; + return views::ImageButton::ShouldEnterPushedState(event); +} + +std::unique_ptr<views::InkDrop> AppListButton::CreateInkDrop() { + std::unique_ptr<views::InkDropImpl> ink_drop = + CustomButton::CreateDefaultInkDropImpl(); + ink_drop->SetShowHighlightOnHover(false); + return std::move(ink_drop); +} + +std::unique_ptr<views::InkDropMask> AppListButton::CreateInkDropMask() const { + return base::MakeUnique<views::CircleInkDropMask>(size(), GetCenterPoint(), + kAppListButtonRadius); +} + +gfx::Point AppListButton::GetCenterPoint() const { + // For a bottom-aligned shelf, the button bounds could have a larger height + // than width (in the case of touch-dragging the shelf updwards) or a larger + // width than height (in the case of a shelf hide/show animation), so adjust + // the y-position of the circle's center to ensure correct layout. Similarly + // adjust the x-position for a left- or right-aligned shelf. + const int x_mid = width() / 2.f; + const int y_mid = height() / 2.f; + ShelfAlignment alignment = wm_shelf_->GetAlignment(); + if (alignment == SHELF_ALIGNMENT_BOTTOM || + alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { + return gfx::Point(x_mid, x_mid); + } else if (alignment == SHELF_ALIGNMENT_RIGHT) { + return gfx::Point(y_mid, y_mid); + } else { + DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT); + return gfx::Point(width() - y_mid, y_mid); + } +} + +} // namespace ash
diff --git a/ash/common/shelf/app_list_button.h b/ash/common/shelf/app_list_button.h new file mode 100644 index 0000000..d4a0fbe --- /dev/null +++ b/ash/common/shelf/app_list_button.h
@@ -0,0 +1,72 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_APP_LIST_BUTTON_H_ +#define ASH_COMMON_SHELF_APP_LIST_BUTTON_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/views/controls/button/image_button.h" + +namespace ash { +class InkDropButtonListener; +class ShelfView; +class WmShelf; + +// Button used for the AppList icon on the shelf. +class ASH_EXPORT AppListButton : public views::ImageButton { + public: + AppListButton(InkDropButtonListener* listener, + ShelfView* shelf_view, + WmShelf* wm_shelf); + ~AppListButton() override; + + void OnAppListShown(); + void OnAppListDismissed(); + + bool is_showing_app_list() const { return is_showing_app_list_; } + + // Updates background and schedules a paint. + void UpdateShelfItemBackground(SkColor color); + + protected: + // views::ImageButton overrides: + bool OnMousePressed(const ui::MouseEvent& event) override; + void OnMouseReleased(const ui::MouseEvent& event) override; + void OnMouseCaptureLost() override; + bool OnMouseDragged(const ui::MouseEvent& event) override; + void OnPaint(gfx::Canvas* canvas) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + void NotifyClick(const ui::Event& event) override; + bool ShouldEnterPushedState(const ui::Event& event) override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + + // ui::EventHandler overrides: + void OnGestureEvent(ui::GestureEvent* event) override; + + private: + // Get the center point of the app list button used to draw its background and + // ink drops. + gfx::Point GetCenterPoint() const; + + // True if the app list is currently showing for this display. + // This is useful because other IsApplistVisible functions aren't per-display. + bool is_showing_app_list_; + + // Color used to paint the background. + SkColor background_color_; + + InkDropButtonListener* listener_; + ShelfView* shelf_view_; + WmShelf* wm_shelf_; + + DISALLOW_COPY_AND_ASSIGN(AppListButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_APP_LIST_BUTTON_H_
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.cc b/ash/common/shelf/app_list_shelf_item_delegate.cc new file mode 100644 index 0000000..425ffecc --- /dev/null +++ b/ash/common/shelf/app_list_shelf_item_delegate.cc
@@ -0,0 +1,57 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/app_list_shelf_item_delegate.h" + +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/wm_shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/ptr_util.h" +#include "ui/app_list/app_list_switches.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +// static +void AppListShelfItemDelegate::CreateAppListItemAndDelegate(ShelfModel* model) { + // Add the app list item to the shelf model. + ShelfItem item; + item.type = TYPE_APP_LIST; + item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE); + int index = model->Add(item); + DCHECK_GE(index, 0); + + // Create an AppListShelfItemDelegate for that item. + ShelfID id = model->items()[index].id; + DCHECK_GE(id, 0); + model->SetShelfItemDelegate(id, base::MakeUnique<AppListShelfItemDelegate>()); +} + +AppListShelfItemDelegate::AppListShelfItemDelegate() {} + +AppListShelfItemDelegate::~AppListShelfItemDelegate() {} + +ShelfAction AppListShelfItemDelegate::ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) { + WmShell::Get()->ToggleAppList(); + return SHELF_ACTION_APP_LIST_SHOWN; +} + +ShelfAppMenuItemList AppListShelfItemDelegate::GetAppMenuItems( + int event_flags) { + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); +} + +void AppListShelfItemDelegate::ExecuteCommand(uint32_t command_id, + int event_flags) { + // This delegate does not support showing an application menu. + NOTIMPLEMENTED(); +} + +void AppListShelfItemDelegate::Close() {} + +} // namespace ash
diff --git a/ash/common/shelf/app_list_shelf_item_delegate.h b/ash/common/shelf/app_list_shelf_item_delegate.h new file mode 100644 index 0000000..88f09d2 --- /dev/null +++ b/ash/common/shelf/app_list_shelf_item_delegate.h
@@ -0,0 +1,39 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_ +#define ASH_COMMON_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_ + +#include "ash/common/shelf/shelf_item_delegate.h" +#include "base/macros.h" + +namespace ash { +class ShelfModel; + +// ShelfItemDelegate for TYPE_APP_LIST. +class AppListShelfItemDelegate : public ShelfItemDelegate { + public: + // Initializes the app list item in the shelf data model and creates an + // AppListShelfItemDelegate which will be owned by |model|. + static void CreateAppListItemAndDelegate(ShelfModel* model); + + AppListShelfItemDelegate(); + ~AppListShelfItemDelegate() override; + + // ShelfItemDelegate: + ShelfAction ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; + void ExecuteCommand(uint32_t command_id, int event_flags) override; + void Close() override; + + private: + DISALLOW_COPY_AND_ASSIGN(AppListShelfItemDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/common/shelf/ink_drop_button_listener.h b/ash/common/shelf/ink_drop_button_listener.h new file mode 100644 index 0000000..4b6e752 --- /dev/null +++ b/ash/common/shelf/ink_drop_button_listener.h
@@ -0,0 +1,41 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_INK_DROP_BUTTON_LISTENER_H_ +#define ASH_COMMON_SHELF_INK_DROP_BUTTON_LISTENER_H_ + +#include "ash/ash_export.h" + +namespace ui { +class Event; +} + +namespace views { +class Button; +class InkDrop; +} + +namespace ash { + +// An interface used by buttons on shelf to notify ShelfView when they are +// pressed. |ink_drop| is used to do appropriate ink drop animation based on the +// action performed. +// TODO(mohsen): A better approach would be to return a value indicating the +// type of action performed such that the button can animate the ink drop. +// Currently, it is not possible because showing menu is synchronous and blocks +// the call. Fix this after menu is converted to synchronous. Long-term, the +// return value can be merged into ButtonListener. +class ASH_EXPORT InkDropButtonListener { + public: + virtual void ButtonPressed(views::Button* sender, + const ui::Event& event, + views::InkDrop* ink_drop) = 0; + + protected: + virtual ~InkDropButtonListener() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_INK_DROP_BUTTON_LISTENER_H_
diff --git a/ash/common/shelf/overflow_bubble.cc b/ash/common/shelf/overflow_bubble.cc new file mode 100644 index 0000000..6f1e311f --- /dev/null +++ b/ash/common/shelf/overflow_bubble.cc
@@ -0,0 +1,94 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/overflow_bubble.h" + +#include "ash/common/shelf/overflow_bubble_view.h" +#include "ash/common/shelf/overflow_button.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "ash/common/wm_shell.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +OverflowBubble::OverflowBubble(WmShelf* wm_shelf) + : wm_shelf_(wm_shelf), + bubble_(nullptr), + overflow_button_(nullptr), + shelf_view_(nullptr) { + DCHECK(wm_shelf_); + WmShell::Get()->AddPointerWatcher(this, + views::PointerWatcherEventTypes::BASIC); +} + +OverflowBubble::~OverflowBubble() { + Hide(); + WmShell::Get()->RemovePointerWatcher(this); +} + +void OverflowBubble::Show(OverflowButton* overflow_button, + ShelfView* shelf_view) { + DCHECK(overflow_button); + DCHECK(shelf_view); + + Hide(); + + bubble_ = new OverflowBubbleView(wm_shelf_); + bubble_->InitOverflowBubble(overflow_button, shelf_view); + shelf_view_ = shelf_view; + overflow_button_ = overflow_button; + + TrayBackgroundView::InitializeBubbleAnimations(bubble_->GetWidget()); + bubble_->GetWidget()->AddObserver(this); + bubble_->GetWidget()->Show(); + + overflow_button->OnOverflowBubbleShown(); +} + +void OverflowBubble::Hide() { + if (!IsShowing()) + return; + + OverflowButton* overflow_button = overflow_button_; + + bubble_->GetWidget()->RemoveObserver(this); + bubble_->GetWidget()->Close(); + bubble_ = nullptr; + overflow_button_ = nullptr; + shelf_view_ = nullptr; + + overflow_button->OnOverflowBubbleHidden(); +} + +void OverflowBubble::ProcessPressedEvent( + const gfx::Point& event_location_in_screen) { + if (IsShowing() && !shelf_view_->IsShowingMenu() && + !bubble_->GetBoundsInScreen().Contains(event_location_in_screen) && + !overflow_button_->GetBoundsInScreen().Contains( + event_location_in_screen)) { + Hide(); + } +} + +void OverflowBubble::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + if (event.type() == ui::ET_POINTER_DOWN) + ProcessPressedEvent(location_in_screen); +} + +void OverflowBubble::OnWidgetDestroying(views::Widget* widget) { + DCHECK(widget == bubble_->GetWidget()); + // Update the overflow button in the parent ShelfView. + overflow_button_->SchedulePaint(); + bubble_ = nullptr; + overflow_button_ = nullptr; + shelf_view_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/shelf/overflow_bubble.h b/ash/common/shelf/overflow_bubble.h new file mode 100644 index 0000000..201018c --- /dev/null +++ b/ash/common/shelf/overflow_bubble.h
@@ -0,0 +1,65 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_OVERFLOW_BUBBLE_H_ +#define ASH_COMMON_SHELF_OVERFLOW_BUBBLE_H_ + +#include "base/macros.h" +#include "ui/views/pointer_watcher.h" +#include "ui/views/widget/widget_observer.h" + +namespace ui { +class PointerEvent; +} + +namespace ash { +class OverflowBubbleView; +class OverflowButton; +class ShelfView; +class WmShelf; + +// OverflowBubble shows shelf items that won't fit on the main shelf in a +// separate bubble. +class OverflowBubble : public views::PointerWatcher, + public views::WidgetObserver { + public: + // |wm_shelf| is the shelf that spawns the bubble. + explicit OverflowBubble(WmShelf* wm_shelf); + ~OverflowBubble() override; + + // Shows an bubble pointing to |overflow_button| with |shelf_view| as its + // content. This |shelf_view| is different than the main shelf's view and + // only contains the overflow items. + void Show(OverflowButton* overflow_button, ShelfView* shelf_view); + + void Hide(); + + bool IsShowing() const { return !!bubble_; } + ShelfView* shelf_view() { return shelf_view_; } + OverflowBubbleView* bubble_view() { return bubble_; } + + private: + void ProcessPressedEvent(const gfx::Point& event_location_in_screen); + + // views::PointerWatcher: + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; + + // Overridden from views::WidgetObserver: + void OnWidgetDestroying(views::Widget* widget) override; + + WmShelf* wm_shelf_; + OverflowBubbleView* bubble_; // Owned by views hierarchy. + OverflowButton* overflow_button_; // Owned by ShelfView. + + // ShelfView containing the overflow items. Owned by |bubble_|. + ShelfView* shelf_view_; + + DISALLOW_COPY_AND_ASSIGN(OverflowBubble); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_OVERFLOW_BUBBLE_H_
diff --git a/ash/common/shelf/overflow_bubble_view.cc b/ash/common/shelf/overflow_bubble_view.cc new file mode 100644 index 0000000..ebee64e --- /dev/null +++ b/ash/common/shelf/overflow_bubble_view.cc
@@ -0,0 +1,228 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/overflow_bubble_view.h" + +#include <algorithm> + +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/events/event.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +// Max bubble size to screen size ratio. +const float kMaxBubbleSizeToScreenRatio = 0.5f; + +// Inner padding in pixels for shelf view inside bubble. +const int kPadding = 2; + +// Padding space in pixels between ShelfView's left/top edge to its contents. +const int kShelfViewLeadingInset = 8; + +} // namespace + +OverflowBubbleView::OverflowBubbleView(WmShelf* wm_shelf) + : wm_shelf_(wm_shelf), shelf_view_(nullptr) { + DCHECK(wm_shelf_); +} + +OverflowBubbleView::~OverflowBubbleView() {} + +void OverflowBubbleView::InitOverflowBubble(views::View* anchor, + views::View* shelf_view) { + shelf_view_ = shelf_view; + + SetAnchorView(anchor); + set_arrow(GetBubbleArrow()); + set_mirror_arrow_in_rtl(false); + set_background(nullptr); + set_color(kShelfDefaultBaseColor); + set_margins(gfx::Insets(kPadding, kPadding, kPadding, kPadding)); + // Overflow bubble should not get focus. If it get focus when it is shown, + // active state item is changed to running state. + set_can_activate(false); + + // Makes bubble view has a layer and clip its children layers. + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + layer()->SetMasksToBounds(true); + + // Calls into OnBeforeBubbleWidgetInit to set the window parent container. + views::BubbleDialogDelegateView::CreateBubble(this); + AddChildView(shelf_view_); +} + +const gfx::Size OverflowBubbleView::GetContentsSize() const { + return shelf_view_->GetPreferredSize(); +} + +// Gets arrow location based on shelf alignment. +views::BubbleBorder::Arrow OverflowBubbleView::GetBubbleArrow() const { + switch (wm_shelf_->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + return views::BubbleBorder::BOTTOM_LEFT; + case SHELF_ALIGNMENT_LEFT: + return views::BubbleBorder::LEFT_TOP; + case SHELF_ALIGNMENT_RIGHT: + return views::BubbleBorder::RIGHT_TOP; + } + NOTREACHED(); + return views::BubbleBorder::NONE; +} + +void OverflowBubbleView::ScrollByXOffset(int x_offset) { + const gfx::Rect visible_bounds(GetContentsBounds()); + const gfx::Size contents_size(GetContentsSize()); + + DCHECK_GE(contents_size.width(), visible_bounds.width()); + int x = std::min(contents_size.width() - visible_bounds.width(), + std::max(0, scroll_offset_.x() + x_offset)); + scroll_offset_.set_x(x); +} + +void OverflowBubbleView::ScrollByYOffset(int y_offset) { + const gfx::Rect visible_bounds(GetContentsBounds()); + const gfx::Size contents_size(GetContentsSize()); + + DCHECK_GE(contents_size.width(), visible_bounds.width()); + int y = std::min(contents_size.height() - visible_bounds.height(), + std::max(0, scroll_offset_.y() + y_offset)); + scroll_offset_.set_y(y); +} + +gfx::Size OverflowBubbleView::GetPreferredSize() const { + gfx::Size preferred_size = GetContentsSize(); + + const gfx::Rect monitor_rect = + display::Screen::GetScreen() + ->GetDisplayNearestPoint(GetAnchorRect().CenterPoint()) + .work_area(); + if (!monitor_rect.IsEmpty()) { + if (wm_shelf_->IsHorizontalAlignment()) { + preferred_size.set_width( + std::min(preferred_size.width(), + static_cast<int>(monitor_rect.width() * + kMaxBubbleSizeToScreenRatio))); + } else { + preferred_size.set_height( + std::min(preferred_size.height(), + static_cast<int>(monitor_rect.height() * + kMaxBubbleSizeToScreenRatio))); + } + } + + return preferred_size; +} + +void OverflowBubbleView::Layout() { + shelf_view_->SetBoundsRect(gfx::Rect( + gfx::PointAtOffsetFromOrigin(-scroll_offset_), GetContentsSize())); +} + +void OverflowBubbleView::ChildPreferredSizeChanged(views::View* child) { + // When contents size is changed, ContentsBounds should be updated before + // calculating scroll offset. + SizeToContents(); + + // Ensures |shelf_view_| is still visible. + if (wm_shelf_->IsHorizontalAlignment()) + ScrollByXOffset(0); + else + ScrollByYOffset(0); + Layout(); +} + +bool OverflowBubbleView::OnMouseWheel(const ui::MouseWheelEvent& event) { + // The MouseWheelEvent was changed to support both X and Y offsets + // recently, but the behavior of this function was retained to continue + // using Y offsets only. Might be good to simply scroll in both + // directions as in OverflowBubbleView::OnScrollEvent. + if (wm_shelf_->IsHorizontalAlignment()) + ScrollByXOffset(-event.y_offset()); + else + ScrollByYOffset(-event.y_offset()); + Layout(); + + return true; +} + +void OverflowBubbleView::OnScrollEvent(ui::ScrollEvent* event) { + ScrollByXOffset(-event->x_offset()); + ScrollByYOffset(-event->y_offset()); + Layout(); + event->SetHandled(); +} + +int OverflowBubbleView::GetDialogButtons() const { + return ui::DIALOG_BUTTON_NONE; +} + +void OverflowBubbleView::OnBeforeBubbleWidgetInit( + views::Widget::InitParams* params, + views::Widget* bubble_widget) const { + // Place the bubble in the same root window as the anchor. + WmWindow::Get(anchor_widget()->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + bubble_widget, kShellWindowId_ShelfBubbleContainer, params); +} + +gfx::Rect OverflowBubbleView::GetBubbleBounds() { + views::BubbleBorder* border = GetBubbleFrameView()->bubble_border(); + gfx::Insets bubble_insets = border->GetInsets(); + + const int border_size = views::BubbleBorder::is_arrow_on_horizontal(arrow()) + ? bubble_insets.left() + : bubble_insets.top(); + const int arrow_offset = border_size + kPadding + kShelfViewLeadingInset + + GetShelfConstant(SHELF_SIZE) / 2; + + const gfx::Size content_size = GetPreferredSize(); + border->set_arrow_offset(arrow_offset); + + const gfx::Rect anchor_rect = GetAnchorRect(); + gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( + anchor_rect, content_size, false); + + gfx::Rect monitor_rect = + display::Screen::GetScreen() + ->GetDisplayNearestPoint(anchor_rect.CenterPoint()) + .work_area(); + + int offset = 0; + if (views::BubbleBorder::is_arrow_on_horizontal(arrow())) { + if (bubble_rect.x() < monitor_rect.x()) + offset = monitor_rect.x() - bubble_rect.x(); + else if (bubble_rect.right() > monitor_rect.right()) + offset = monitor_rect.right() - bubble_rect.right(); + + bubble_rect.Offset(offset, 0); + border->set_arrow_offset(anchor_rect.CenterPoint().x() - bubble_rect.x()); + } else { + if (bubble_rect.y() < monitor_rect.y()) + offset = monitor_rect.y() - bubble_rect.y(); + else if (bubble_rect.bottom() > monitor_rect.bottom()) + offset = monitor_rect.bottom() - bubble_rect.bottom(); + + bubble_rect.Offset(0, offset); + border->set_arrow_offset(anchor_rect.CenterPoint().y() - bubble_rect.y()); + } + + GetBubbleFrameView()->SchedulePaint(); + return bubble_rect; +} + +} // namespace ash
diff --git a/ash/common/shelf/overflow_bubble_view.h b/ash/common/shelf/overflow_bubble_view.h new file mode 100644 index 0000000..f9c1678 --- /dev/null +++ b/ash/common/shelf/overflow_bubble_view.h
@@ -0,0 +1,69 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_OVERFLOW_BUBBLE_VIEW_H_ +#define ASH_COMMON_SHELF_OVERFLOW_BUBBLE_VIEW_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" + +namespace views { +class View; +} + +namespace ash { +class WmShelf; + +namespace test { +class OverflowBubbleViewTestAPI; +} + +// OverflowBubbleView hosts a ShelfView to display overflown items. +// Exports to access this class from OverflowBubbleViewTestAPI. +class ASH_EXPORT OverflowBubbleView : public views::BubbleDialogDelegateView { + public: + explicit OverflowBubbleView(WmShelf* wm_shelf); + ~OverflowBubbleView() override; + + // |anchor| is the overflow button on the main shelf. |shelf_view| is the + // ShelfView containing the overflow items. + void InitOverflowBubble(views::View* anchor, views::View* shelf_view); + + // views::BubbleDialogDelegateView overrides: + int GetDialogButtons() const override; + void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, + views::Widget* bubble_widget) const override; + gfx::Rect GetBubbleBounds() override; + + private: + friend class test::OverflowBubbleViewTestAPI; + + const gfx::Size GetContentsSize() const; + + // Gets arrow location based on shelf alignment. + views::BubbleBorder::Arrow GetBubbleArrow() const; + + void ScrollByXOffset(int x_offset); + void ScrollByYOffset(int y_offset); + + // views::View overrides: + gfx::Size GetPreferredSize() const override; + void Layout() override; + void ChildPreferredSizeChanged(views::View* child) override; + bool OnMouseWheel(const ui::MouseWheelEvent& event) override; + + // ui::EventHandler overrides: + void OnScrollEvent(ui::ScrollEvent* event) override; + + WmShelf* wm_shelf_; + views::View* shelf_view_; // Owned by views hierarchy. + gfx::Vector2d scroll_offset_; + + DISALLOW_COPY_AND_ASSIGN(OverflowBubbleView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_OVERFLOW_BUBBLE_VIEW_H_
diff --git a/ash/common/shelf/overflow_button.cc b/ash/common/shelf/overflow_button.cc new file mode 100644 index 0000000..ccb585c --- /dev/null +++ b/ash/common/shelf/overflow_button.cc
@@ -0,0 +1,150 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/overflow_button.h" + +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/ptr_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/skbitmap_operations.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" + +namespace ash { + +OverflowButton::OverflowButton(ShelfView* shelf_view, WmShelf* wm_shelf) + : CustomButton(nullptr), + shelf_view_(shelf_view), + wm_shelf_(wm_shelf), + background_color_(kShelfDefaultBaseColor) { + DCHECK(shelf_view_); + + SetInkDropMode(InkDropMode::ON); + set_ink_drop_base_color(kShelfInkDropBaseColor); + set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); + set_hide_ink_drop_when_showing_context_menu(false); + bottom_image_ = gfx::CreateVectorIcon(kShelfOverflowIcon, kShelfIconColor); + + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); + SetAccessibleName(l10n_util::GetStringUTF16(IDS_ASH_SHELF_OVERFLOW_NAME)); +} + +OverflowButton::~OverflowButton() {} + +void OverflowButton::OnShelfAlignmentChanged() { + SchedulePaint(); +} + +void OverflowButton::OnOverflowBubbleShown() { + AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr); +} + +void OverflowButton::OnOverflowBubbleHidden() { + AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr); +} + +void OverflowButton::UpdateShelfItemBackground(SkColor color) { + background_color_ = color; + SchedulePaint(); +} + +void OverflowButton::OnPaint(gfx::Canvas* canvas) { + gfx::Rect bounds = CalculateButtonBounds(); + PaintBackground(canvas, bounds); + PaintForeground(canvas, bounds); +} + +std::unique_ptr<views::InkDrop> OverflowButton::CreateInkDrop() { + std::unique_ptr<views::InkDropImpl> ink_drop = + CreateDefaultFloodFillInkDropImpl(); + ink_drop->SetShowHighlightOnHover(false); + ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE); + return std::move(ink_drop); +} + +std::unique_ptr<views::InkDropRipple> OverflowButton::CreateInkDropRipple() + const { + gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds()); + return base::MakeUnique<views::FloodFillInkDropRipple>( + size(), insets, GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(), + ink_drop_visible_opacity()); +} + +bool OverflowButton::ShouldEnterPushedState(const ui::Event& event) { + if (shelf_view_->IsShowingOverflowBubble()) + return false; + + return CustomButton::ShouldEnterPushedState(event); +} + +void OverflowButton::NotifyClick(const ui::Event& event) { + CustomButton::NotifyClick(event); + shelf_view_->ButtonPressed(this, event, GetInkDrop()); +} + +std::unique_ptr<views::InkDropMask> OverflowButton::CreateInkDropMask() const { + gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds()); + return base::MakeUnique<views::RoundRectInkDropMask>( + size(), insets, kOverflowButtonCornerRadius); +} + +void OverflowButton::PaintBackground(gfx::Canvas* canvas, + const gfx::Rect& bounds) { + cc::PaintFlags flags; + flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + flags.setColor(background_color_); + canvas->DrawRoundRect(bounds, kOverflowButtonCornerRadius, flags); +} + +void OverflowButton::PaintForeground(gfx::Canvas* canvas, + const gfx::Rect& bounds) { + const gfx::ImageSkia* image = nullptr; + + switch (wm_shelf_->GetAlignment()) { + case SHELF_ALIGNMENT_LEFT: + if (left_image_.isNull()) { + left_image_ = gfx::ImageSkiaOperations::CreateRotatedImage( + bottom_image_, SkBitmapOperations::ROTATION_90_CW); + } + image = &left_image_; + break; + case SHELF_ALIGNMENT_RIGHT: + if (right_image_.isNull()) { + right_image_ = gfx::ImageSkiaOperations::CreateRotatedImage( + bottom_image_, SkBitmapOperations::ROTATION_270_CW); + } + image = &right_image_; + break; + default: + image = &bottom_image_; + break; + } + + canvas->DrawImageInt(*image, + bounds.x() + ((bounds.width() - image->width()) / 2), + bounds.y() + ((bounds.height() - image->height()) / 2)); +} + +gfx::Rect OverflowButton::CalculateButtonBounds() const { + ShelfAlignment alignment = wm_shelf_->GetAlignment(); + gfx::Rect content_bounds = GetContentsBounds(); + // Align the button to the top of a bottom-aligned shelf, to the right edge + // a left-aligned shelf, and to the left edge of a right-aligned shelf. + const int inset = (GetShelfConstant(SHELF_SIZE) - kOverflowButtonSize) / 2; + const int x = alignment == SHELF_ALIGNMENT_LEFT + ? content_bounds.right() - inset - kOverflowButtonSize + : content_bounds.x() + inset; + return gfx::Rect(x, content_bounds.y() + inset, kOverflowButtonSize, + kOverflowButtonSize); +} + +} // namespace ash
diff --git a/ash/common/shelf/overflow_button.h b/ash/common/shelf/overflow_button.h new file mode 100644 index 0000000..32bf382 --- /dev/null +++ b/ash/common/shelf/overflow_button.h
@@ -0,0 +1,67 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_OVERFLOW_BUTTON_H_ +#define ASH_COMMON_SHELF_OVERFLOW_BUTTON_H_ + +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/controls/button/custom_button.h" + +namespace ash { +class ShelfView; +class WmShelf; + +// Shelf overflow chevron button. +class OverflowButton : public views::CustomButton { + public: + // |shelf_view| is the view containing this button. + OverflowButton(ShelfView* shelf_view, WmShelf* wm_shelf); + ~OverflowButton() override; + + void OnShelfAlignmentChanged(); + void OnOverflowBubbleShown(); + void OnOverflowBubbleHidden(); + + // Updates background and schedules a paint. + void UpdateShelfItemBackground(SkColor color); + + private: + // views::CustomButton: + void OnPaint(gfx::Canvas* canvas) override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + bool ShouldEnterPushedState(const ui::Event& event) override; + void NotifyClick(const ui::Event& event) override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + + // Helper functions to paint the background and foreground of the button + // at |bounds|. + void PaintBackground(gfx::Canvas* canvas, const gfx::Rect& bounds); + void PaintForeground(gfx::Canvas* canvas, const gfx::Rect& bounds); + + // Calculates the bounds of the overflow button based on the shelf alignment. + gfx::Rect CalculateButtonBounds() const; + + // Used for bottom shelf alignment. + gfx::ImageSkia bottom_image_; + + // Cached rotations of |bottom_image_| used for left and right shelf + // alignments. + gfx::ImageSkia left_image_; + gfx::ImageSkia right_image_; + + ShelfView* shelf_view_; + WmShelf* wm_shelf_; + + // Color used to paint the background. + SkColor background_color_; + + DISALLOW_COPY_AND_ASSIGN(OverflowButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_OVERFLOW_BUTTON_H_
diff --git a/ash/common/shelf/shelf_alignment_menu.cc b/ash/common/shelf/shelf_alignment_menu.cc new file mode 100644 index 0000000..12c48b2 --- /dev/null +++ b/ash/common/shelf/shelf_alignment_menu.cc
@@ -0,0 +1,66 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_alignment_menu.h" + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_shell.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/strings/grit/ash_strings.h" + +namespace ash { + +ShelfAlignmentMenu::ShelfAlignmentMenu(WmShelf* wm_shelf) + : ui::SimpleMenuModel(nullptr), wm_shelf_(wm_shelf) { + DCHECK(wm_shelf_); + const int align_group_id = 1; + set_delegate(this); + AddRadioItemWithStringId( + MENU_ALIGN_LEFT, IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_LEFT, align_group_id); + AddRadioItemWithStringId(MENU_ALIGN_BOTTOM, + IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_BOTTOM, + align_group_id); + AddRadioItemWithStringId( + MENU_ALIGN_RIGHT, IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_RIGHT, align_group_id); +} + +ShelfAlignmentMenu::~ShelfAlignmentMenu() {} + +bool ShelfAlignmentMenu::IsCommandIdChecked(int command_id) const { + switch (wm_shelf_->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + return command_id == MENU_ALIGN_BOTTOM; + case SHELF_ALIGNMENT_LEFT: + return command_id == MENU_ALIGN_LEFT; + case SHELF_ALIGNMENT_RIGHT: + return command_id == MENU_ALIGN_RIGHT; + } + return false; +} + +bool ShelfAlignmentMenu::IsCommandIdEnabled(int command_id) const { + return true; +} + +void ShelfAlignmentMenu::ExecuteCommand(int command_id, int event_flags) { + WmShell* shell = WmShell::Get(); + switch (static_cast<MenuItem>(command_id)) { + case MENU_ALIGN_LEFT: + shell->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_LEFT); + wm_shelf_->SetAlignment(SHELF_ALIGNMENT_LEFT); + break; + case MENU_ALIGN_BOTTOM: + shell->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_BOTTOM); + wm_shelf_->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + break; + case MENU_ALIGN_RIGHT: + shell->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_RIGHT); + wm_shelf_->SetAlignment(SHELF_ALIGNMENT_RIGHT); + break; + } +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_alignment_menu.h b/ash/common/shelf/shelf_alignment_menu.h new file mode 100644 index 0000000..e315317 --- /dev/null +++ b/ash/common/shelf/shelf_alignment_menu.h
@@ -0,0 +1,43 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_ALIGNMENT_MENU_H_ +#define ASH_COMMON_SHELF_SHELF_ALIGNMENT_MENU_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/base/models/simple_menu_model.h" + +namespace ash { + +class WmShelf; + +// Submenu for choosing the alignment of the shelf. +class ASH_EXPORT ShelfAlignmentMenu : public ui::SimpleMenuModel, + public ui::SimpleMenuModel::Delegate { + public: + explicit ShelfAlignmentMenu(WmShelf* wm_shelf); + ~ShelfAlignmentMenu() override; + + // ui::SimpleMenuModel::Delegate overrides: + bool IsCommandIdChecked(int command_id) const override; + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + + private: + enum MenuItem { + // Offset so as not to interfere with other menus. + MENU_ALIGN_LEFT = 500, + MENU_ALIGN_RIGHT, + MENU_ALIGN_BOTTOM, + }; + + WmShelf* wm_shelf_; + + DISALLOW_COPY_AND_ASSIGN(ShelfAlignmentMenu); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_ALIGNMENT_MENU_H_
diff --git a/ash/common/shelf/shelf_application_menu_model.cc b/ash/common/shelf/shelf_application_menu_model.cc new file mode 100644 index 0000000..7bf323c --- /dev/null +++ b/ash/common/shelf/shelf_application_menu_model.cc
@@ -0,0 +1,73 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_application_menu_model.h" + +#include <stddef.h> + +#include <limits> +#include <utility> + +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "base/metrics/histogram_macros.h" + +namespace { + +const int kInvalidCommandId = std::numeric_limits<int>::max(); + +} // namespace + +namespace ash { + +ShelfApplicationMenuModel::ShelfApplicationMenuModel( + const base::string16& title, + ShelfAppMenuItemList items, + ShelfItemDelegate* delegate) + : ui::SimpleMenuModel(this), items_(std::move(items)), delegate_(delegate) { + AddSeparator(ui::SPACING_SEPARATOR); + AddItem(kInvalidCommandId, title); + AddSeparator(ui::SPACING_SEPARATOR); + + for (size_t i = 0; i < items_.size(); i++) { + ShelfApplicationMenuItem* item = items_[i].get(); + AddItem(i, item->title()); + if (!item->icon().IsEmpty()) + SetIcon(GetIndexOfCommandId(i), item->icon()); + } + + // SimpleMenuModel does not allow two consecutive spacing separator items. + // This only occurs in tests; users should not see menus with no |items_|. + if (!items_.empty()) + AddSeparator(ui::SPACING_SEPARATOR); +} + +ShelfApplicationMenuModel::~ShelfApplicationMenuModel() {} + +bool ShelfApplicationMenuModel::IsCommandIdChecked(int command_id) const { + return false; +} + +bool ShelfApplicationMenuModel::IsCommandIdEnabled(int command_id) const { + return command_id >= 0 && static_cast<size_t>(command_id) < items_.size(); +} + +void ShelfApplicationMenuModel::ExecuteCommand(int command_id, + int event_flags) { + DCHECK(delegate_); + DCHECK(IsCommandIdEnabled(command_id)); + // Have the delegate execute its own custom command id for the given item. + delegate_->ExecuteCommand(items_[command_id]->command_id(), event_flags); + RecordMenuItemSelectedMetrics(command_id, items_.size()); +} + +void ShelfApplicationMenuModel::RecordMenuItemSelectedMetrics( + int command_id, + int num_menu_items_enabled) { + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Menu.SelectedMenuItemIndex", command_id); + UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Menu.NumItemsEnabledUponSelection", + num_menu_items_enabled); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_application_menu_model.h b/ash/common/shelf/shelf_application_menu_model.h new file mode 100644 index 0000000..7abe8b5 --- /dev/null +++ b/ash/common/shelf/shelf_application_menu_model.h
@@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_APPLICATION_MENU_MODEL_H_ +#define ASH_COMMON_SHELF_SHELF_APPLICATION_MENU_MODEL_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "base/macros.h" +#include "ui/base/models/simple_menu_model.h" + +namespace ash { + +class ShelfApplicationMenuModelTestAPI; +class ShelfItemDelegate; + +// A menu model listing open applications associated with a shelf item. Layout: +// +---------------------------+ +// | | +// | App Title | +// | | +// | [Icon] Item Title | +// | [Icon] Item Title | +// | | +// +---------------------------+ +class ASH_EXPORT ShelfApplicationMenuModel + : public ui::SimpleMenuModel, + public ui::SimpleMenuModel::Delegate { + public: + // Makes a menu with a |title|, separators, and |items| for |delegate|. + // |delegate| may be null in unit tests that do not execute commands. + ShelfApplicationMenuModel(const base::string16& title, + ShelfAppMenuItemList items, + ShelfItemDelegate* delegate); + ~ShelfApplicationMenuModel() override; + + // ui::SimpleMenuModel::Delegate: + bool IsCommandIdChecked(int command_id) const override; + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + + private: + friend class ShelfApplicationMenuModelTestAPI; + + // Records UMA metrics when a menu item is selected. + void RecordMenuItemSelectedMetrics(int command_id, + int num_menu_items_enabled); + + // The list of menu items as returned from the shelf item's controller. + ShelfAppMenuItemList items_; + + // The shelf item delegate that created the menu and executes its commands. + ShelfItemDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModel); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_APPLICATION_MENU_MODEL_H_
diff --git a/ash/common/shelf/shelf_application_menu_model_unittest.cc b/ash/common/shelf/shelf_application_menu_model_unittest.cc new file mode 100644 index 0000000..aebee58 --- /dev/null +++ b/ash/common/shelf/shelf_application_menu_model_unittest.cc
@@ -0,0 +1,133 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_application_menu_model.h" + +#include <utility> + +#include "ash/common/test/test_shelf_item_delegate.h" +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/histogram_tester.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +namespace { + +const char kNumItemsEnabledHistogramName[] = + "Ash.Shelf.Menu.NumItemsEnabledUponSelection"; + +const char kSelectedMenuItemIndexHistogramName[] = + "Ash.Shelf.Menu.SelectedMenuItemIndex"; + +} // namespace + +// Test API to provide internal access to a ShelfApplicationMenuModel. +class ShelfApplicationMenuModelTestAPI { + public: + // Creates a test api to access the internals of the |menu|. + explicit ShelfApplicationMenuModelTestAPI(ShelfApplicationMenuModel* menu) + : menu_(menu) {} + ~ShelfApplicationMenuModelTestAPI() {} + + // Give public access to this metrics recording functions. + void RecordMenuItemSelectedMetrics(int command_id, + int num_menu_items_enabled) { + menu_->RecordMenuItemSelectedMetrics(command_id, num_menu_items_enabled); + } + + private: + // The ShelfApplicationMenuModel to provide internal access to. Not owned. + ShelfApplicationMenuModel* menu_; + + DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModelTestAPI); +}; + +// Verifies the menu contents given an empty item list. +TEST(ShelfApplicationMenuModelTest, VerifyContentsWithNoMenuItems) { + base::string16 title = base::ASCIIToUTF16("title"); + ShelfApplicationMenuModel menu(title, ShelfAppMenuItemList(), nullptr); + // Expect the title with separators. + ASSERT_EQ(static_cast<int>(3), menu.GetItemCount()); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(1)); + EXPECT_EQ(title, menu.GetLabelAt(1)); + EXPECT_FALSE(menu.IsEnabledAt(1)); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(2)); +} + +// Verifies the menu contents given a non-empty item list. +TEST(ShelfApplicationMenuModelTest, VerifyContentsWithMenuItems) { + ShelfAppMenuItemList items; + base::string16 title1 = base::ASCIIToUTF16("title1"); + base::string16 title2 = base::ASCIIToUTF16("title2"); + base::string16 title3 = base::ASCIIToUTF16("title3"); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title1)); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(1, title2)); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(2, title3)); + + base::string16 title = base::ASCIIToUTF16("title"); + ShelfApplicationMenuModel menu(title, std::move(items), nullptr); + ShelfApplicationMenuModelTestAPI menu_test_api(&menu); + + // Expect the title with separators, the enabled items, and another separator. + ASSERT_EQ(static_cast<int>(7), menu.GetItemCount()); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(1)); + EXPECT_EQ(title, menu.GetLabelAt(1)); + EXPECT_FALSE(menu.IsEnabledAt(1)); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(2)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(3)); + EXPECT_EQ(title1, menu.GetLabelAt(3)); + EXPECT_TRUE(menu.IsEnabledAt(3)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(4)); + EXPECT_EQ(title2, menu.GetLabelAt(4)); + EXPECT_TRUE(menu.IsEnabledAt(4)); + EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(5)); + EXPECT_EQ(title3, menu.GetLabelAt(5)); + EXPECT_TRUE(menu.IsEnabledAt(5)); + EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(6)); +} + +// Verifies RecordMenuItemSelectedMetrics uses the correct histogram buckets. +TEST(ShelfApplicationMenuModelTest, VerifyHistogramBuckets) { + const int kCommandId = 3; + const int kNumMenuItemsEnabled = 7; + + base::HistogramTester histogram_tester; + + ShelfAppMenuItemList items; + ShelfApplicationMenuModel menu(base::ASCIIToUTF16("title"), std::move(items), + nullptr); + ShelfApplicationMenuModelTestAPI menu_test_api(&menu); + menu_test_api.RecordMenuItemSelectedMetrics(kCommandId, kNumMenuItemsEnabled); + + histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); + histogram_tester.ExpectBucketCount(kNumItemsEnabledHistogramName, + kNumMenuItemsEnabled, 1); + + histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); + histogram_tester.ExpectBucketCount(kSelectedMenuItemIndexHistogramName, + kCommandId, 1); +} + +// Verify histogram data is recorded when ExecuteCommand is called. +TEST(ShelfApplicationMenuModelTest, VerifyHistogramOnExecute) { + base::HistogramTester histogram_tester; + + ShelfAppMenuItemList items; + base::string16 title = base::ASCIIToUTF16("title"); + items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title)); + test::TestShelfItemDelegate test_delegate(nullptr); + ShelfApplicationMenuModel menu(title, std::move(items), &test_delegate); + menu.ExecuteCommand(0, 0); + + histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); + histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_background_animator.cc b/ash/common/shelf/shelf_background_animator.cc new file mode 100644 index 0000000..ad0311e --- /dev/null +++ b/ash/common/shelf/shelf_background_animator.cc
@@ -0,0 +1,245 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_background_animator.h" + +#include <algorithm> + +#include "ash/animation/animation_change_type.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wallpaper/wallpaper_controller.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/color_utils.h" + +namespace ash { + +ShelfBackgroundAnimator::AnimationValues::AnimationValues() {} + +ShelfBackgroundAnimator::AnimationValues::~AnimationValues() {} + +void ShelfBackgroundAnimator::AnimationValues::UpdateCurrentValues(double t) { + current_color_ = + gfx::Tween::ColorValueBetween(t, initial_color_, target_color_); +} + +void ShelfBackgroundAnimator::AnimationValues::SetTargetValues( + SkColor target_color) { + initial_color_ = current_color_; + target_color_ = target_color; +} + +bool ShelfBackgroundAnimator::AnimationValues::InitialValuesEqualTargetValuesOf( + const AnimationValues& other) const { + return initial_color_ == other.target_color_; +} + +ShelfBackgroundAnimator::ShelfBackgroundAnimator( + ShelfBackgroundType background_type, + WmShelf* wm_shelf, + WallpaperController* wallpaper_controller) + : wm_shelf_(wm_shelf), wallpaper_controller_(wallpaper_controller) { + if (wallpaper_controller_) + wallpaper_controller_->AddObserver(this); + if (wm_shelf_) + wm_shelf_->AddObserver(this); + + // Initialize animators so that adding observers get notified with consistent + // values. + AnimateBackground(background_type, AnimationChangeType::IMMEDIATE); +} + +ShelfBackgroundAnimator::~ShelfBackgroundAnimator() { + if (wallpaper_controller_) + wallpaper_controller_->RemoveObserver(this); + if (wm_shelf_) + wm_shelf_->RemoveObserver(this); +} + +void ShelfBackgroundAnimator::AddObserver( + ShelfBackgroundAnimatorObserver* observer) { + observers_.AddObserver(observer); + NotifyObserver(observer); +} + +void ShelfBackgroundAnimator::RemoveObserver( + ShelfBackgroundAnimatorObserver* observer) { + observers_.RemoveObserver(observer); +} + +void ShelfBackgroundAnimator::NotifyObserver( + ShelfBackgroundAnimatorObserver* observer) { + observer->UpdateShelfBackground(shelf_background_values_.current_color()); + observer->UpdateShelfItemBackground(item_background_values_.current_color()); +} + +void ShelfBackgroundAnimator::PaintBackground( + ShelfBackgroundType background_type, + AnimationChangeType change_type) { + if (target_background_type_ == background_type && + change_type == AnimationChangeType::ANIMATE) { + return; + } + + AnimateBackground(background_type, change_type); +} + +void ShelfBackgroundAnimator::AnimationProgressed( + const gfx::Animation* animation) { + DCHECK_EQ(animation, animator_.get()); + SetAnimationValues(animation->GetCurrentValue()); +} + +void ShelfBackgroundAnimator::AnimationEnded(const gfx::Animation* animation) { + DCHECK_EQ(animation, animator_.get()); + SetAnimationValues(animation->GetCurrentValue()); + animator_.reset(); +} + +void ShelfBackgroundAnimator::AnimationCanceled( + const gfx::Animation* animation) { + DCHECK_EQ(animation, animator_.get()); + SetAnimationValues(animator_->IsShowing() ? 1.0 : 0.0); + // Animations are only cancelled when they are being pre-empted so we don't + // destroy the |animator_| because it may be re-used immediately. +} + +void ShelfBackgroundAnimator::OnWallpaperDataChanged() {} + +void ShelfBackgroundAnimator::OnWallpaperColorsChanged() { + AnimateBackground(target_background_type_, AnimationChangeType::ANIMATE); +} + +void ShelfBackgroundAnimator::OnBackgroundTypeChanged( + ShelfBackgroundType background_type, + AnimationChangeType change_type) { + PaintBackground(background_type, change_type); +} + +void ShelfBackgroundAnimator::NotifyObservers() { + for (auto& observer : observers_) + NotifyObserver(&observer); +} + +void ShelfBackgroundAnimator::AnimateBackground( + ShelfBackgroundType background_type, + AnimationChangeType change_type) { + StopAnimator(); + + if (change_type == AnimationChangeType::IMMEDIATE) { + animator_.reset(); + SetTargetValues(background_type); + SetAnimationValues(1.0); + } else if (CanReuseAnimator(background_type)) { + // |animator_| should not be null here as CanReuseAnimator() returns false + // when it is null. + if (animator_->IsShowing()) + animator_->Hide(); + else + animator_->Show(); + } else { + CreateAnimator(background_type); + SetTargetValues(background_type); + animator_->Show(); + } + + if (target_background_type_ != background_type) { + previous_background_type_ = target_background_type_; + target_background_type_ = background_type; + } +} + +bool ShelfBackgroundAnimator::CanReuseAnimator( + ShelfBackgroundType background_type) const { + if (!animator_) + return false; + + AnimationValues target_shelf_background_values; + AnimationValues target_item_background_values; + GetTargetValues(background_type, &target_shelf_background_values, + &target_item_background_values); + + return previous_background_type_ == background_type && + shelf_background_values_.InitialValuesEqualTargetValuesOf( + target_shelf_background_values) && + item_background_values_.InitialValuesEqualTargetValuesOf( + target_item_background_values); +} + +void ShelfBackgroundAnimator::CreateAnimator( + ShelfBackgroundType background_type) { + int duration_ms = 0; + + switch (background_type) { + case SHELF_BACKGROUND_DEFAULT: + duration_ms = 500; + break; + case SHELF_BACKGROUND_OVERLAP: + duration_ms = 500; + break; + case SHELF_BACKGROUND_MAXIMIZED: + duration_ms = 250; + break; + } + + animator_.reset(new gfx::SlideAnimation(this)); + animator_->SetSlideDuration(duration_ms); +} + +void ShelfBackgroundAnimator::StopAnimator() { + if (animator_) + animator_->Stop(); +} + +void ShelfBackgroundAnimator::SetTargetValues( + ShelfBackgroundType background_type) { + GetTargetValues(background_type, &shelf_background_values_, + &item_background_values_); +} + +void ShelfBackgroundAnimator::GetTargetValues( + ShelfBackgroundType background_type, + AnimationValues* shelf_background_values, + AnimationValues* item_background_values) const { + int target_shelf_background_alpha = 0; + int target_shelf_item_background_alpha = 0; + + switch (background_type) { + case SHELF_BACKGROUND_DEFAULT: + target_shelf_background_alpha = 0; + target_shelf_item_background_alpha = kShelfTranslucentAlpha; + break; + case SHELF_BACKGROUND_OVERLAP: + target_shelf_background_alpha = kShelfTranslucentAlpha; + target_shelf_item_background_alpha = 0; + break; + case SHELF_BACKGROUND_MAXIMIZED: + target_shelf_background_alpha = kMaxAlpha; + target_shelf_item_background_alpha = 0; + break; + } + + SkColor target_color = wallpaper_controller_ + ? wallpaper_controller_->prominent_color() + : kShelfDefaultBaseColor; + + if (target_color == SK_ColorTRANSPARENT) + target_color = kShelfDefaultBaseColor; + + shelf_background_values->SetTargetValues( + SkColorSetA(target_color, target_shelf_background_alpha)); + item_background_values->SetTargetValues( + SkColorSetA(target_color, target_shelf_item_background_alpha)); +} + +void ShelfBackgroundAnimator::SetAnimationValues(double t) { + DCHECK_GE(t, 0.0); + DCHECK_LE(t, 1.0); + shelf_background_values_.UpdateCurrentValues(t); + item_background_values_.UpdateCurrentValues(t); + NotifyObservers(); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_background_animator.h b/ash/common/shelf/shelf_background_animator.h new file mode 100644 index 0000000..72747494 --- /dev/null +++ b/ash/common/shelf/shelf_background_animator.h
@@ -0,0 +1,187 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_BACKGROUND_ANIMATOR_H_ +#define ASH_COMMON_SHELF_SHELF_BACKGROUND_ANIMATOR_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "ash/common/wallpaper/wallpaper_controller_observer.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/animation/animation_delegate.h" + +namespace gfx { +class SlideAnimation; +} // namespace gfx + +namespace ash { + +enum class AnimationChangeType; +class ShelfBackgroundAnimatorObserver; +class ShelfBackgroundAnimatorTestApi; +class WallpaperController; +class WmShelf; + +// Central controller for the Shelf and Dock opacity animations. +// +// The ShelfBackgroundAnimator is capable of observing a WmShelf instance for +// background type changes or clients can call PaintBackground() directly. +// +// The Shelf uses 2 surfaces for the animations: +// +// Material Design: +// 1. Shelf button backgrounds +// 2. Overlay for the SHELF_BACKGROUND_OVERLAP and SHELF_BACKGROUND_MAXIMIZED +// states. +class ASH_EXPORT ShelfBackgroundAnimator : public WmShelfObserver, + public gfx::AnimationDelegate, + public WallpaperControllerObserver { + public: + // The maximum alpha value that can be used. + static const int kMaxAlpha = SK_AlphaOPAQUE; + + // Initializes this with the given |background_type|. This will observe the + // |wm_shelf| for background type changes and the |wallpaper_controller| for + // wallpaper changes if not null. + ShelfBackgroundAnimator(ShelfBackgroundType background_type, + WmShelf* wm_shelf, + WallpaperController* wallpaper_controller); + ~ShelfBackgroundAnimator() override; + + ShelfBackgroundType target_background_type() const { + return target_background_type_; + } + + // Initializes |observer| with current values using the Initialize() function. + void AddObserver(ShelfBackgroundAnimatorObserver* observer); + void RemoveObserver(ShelfBackgroundAnimatorObserver* observer); + + // Updates |observer| with current values. + void NotifyObserver(ShelfBackgroundAnimatorObserver* observer); + + // Conditionally animates the background to the specified |background_type| + // and notifies observers of the new background parameters (e.g. color). + // If |change_type| is BACKGROUND_CHANGE_IMMEDIATE then the + // observers will only receive one notification with the final background + // state, otherwise the observers will be notified multiple times in order to + // animate the changes to the backgrounds. + // + // NOTE: If a second request to paint the same |background_type| using the + // BACKGROUND_CHANGE_ANIMATE change type is received it will be ignored and + // observers will NOT be notified. + void PaintBackground(ShelfBackgroundType background_type, + AnimationChangeType change_type); + + // gfx::AnimationDelegate: + void AnimationProgressed(const gfx::Animation* animation) override; + void AnimationEnded(const gfx::Animation* animation) override; + void AnimationCanceled(const gfx::Animation* animation) override; + + protected: + // WmShelfObserver: + void OnBackgroundTypeChanged(ShelfBackgroundType background_type, + AnimationChangeType change_type) override; + + // WallpaperControllerObserver: + void OnWallpaperDataChanged() override; + void OnWallpaperColorsChanged() override; + + private: + friend class ShelfBackgroundAnimatorTestApi; + + // Track the values related to a single animation (e.g. Shelf background, + // shelf item background) + class AnimationValues { + public: + AnimationValues(); + ~AnimationValues(); + + SkColor current_color() const { return current_color_; } + SkColor target_color() const { return target_color_; } + + // Updates the |current_color_| based on |t| value between 0 and 1. + void UpdateCurrentValues(double t); + + // Set the target color and assign the current color to the initial color. + void SetTargetValues(SkColor target_color); + + // Returns true if the initial values of |this| equal the target values of + // |other|. + bool InitialValuesEqualTargetValuesOf(const AnimationValues& other) const; + + private: + SkColor initial_color_ = SK_ColorTRANSPARENT; + SkColor current_color_ = SK_ColorTRANSPARENT; + SkColor target_color_ = SK_ColorTRANSPARENT; + + DISALLOW_COPY_AND_ASSIGN(AnimationValues); + }; + + // Helper function used by PaintBackground() to animate the background. + void AnimateBackground(ShelfBackgroundType background_type, + AnimationChangeType change_type); + + // Returns true if the current |animator_| should be re-used to animate to the + // given |background_type|. This allows for pre-empted animations to take the + // same amount of time to reverse to the |previous_background_type_|. + bool CanReuseAnimator(ShelfBackgroundType background_type) const; + + // Creates a new |animator_| configured with the correct duration. If the + // |animator_| is currently animating it will be stopped. + void CreateAnimator(ShelfBackgroundType background_type); + + // Stops the animator owned by this. + void StopAnimator(); + + // Updates the |shelf_background_values_| and |shelf_item_background_values_|. + void SetTargetValues(ShelfBackgroundType background_type); + + // Sets the target values for |shelf_background_values| and + // |item_background_values| according to |background_type|. + void GetTargetValues(ShelfBackgroundType background_type, + AnimationValues* shelf_background_values, + AnimationValues* item_background_values) const; + + // Updates the animation values corresponding to the |t| value between 0 and + // 1. + void SetAnimationValues(double t); + + // Called when observers need to be notified. + void NotifyObservers(); + + // The shelf to observe for changes to the shelf background type, can be null. + WmShelf* wm_shelf_; + + // The wallpaper controller to observe for changes and to extract colors from. + WallpaperController* wallpaper_controller_; + + // The background type that this is animating towards or has reached. + ShelfBackgroundType target_background_type_ = SHELF_BACKGROUND_DEFAULT; + + // The last background type this is animating away from. + ShelfBackgroundType previous_background_type_ = SHELF_BACKGROUND_MAXIMIZED; + + // Drives the animtion. + std::unique_ptr<gfx::SlideAnimation> animator_; + + // Tracks the shelf background animation values. + AnimationValues shelf_background_values_; + + // Tracks the item background animation values. + AnimationValues item_background_values_; + + base::ObserverList<ShelfBackgroundAnimatorObserver> observers_; + + DISALLOW_COPY_AND_ASSIGN(ShelfBackgroundAnimator); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_BACKGROUND_ANIMATOR_H_
diff --git a/ash/common/shelf/shelf_background_animator_observer.h b/ash/common/shelf/shelf_background_animator_observer.h new file mode 100644 index 0000000..bf8ca105 --- /dev/null +++ b/ash/common/shelf/shelf_background_animator_observer.h
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_BACKGROUND_ANIMATOR_OBSERVER_H_ +#define ASH_COMMON_SHELF_SHELF_BACKGROUND_ANIMATOR_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace ash { + +// Observer for the ShelfBackgroundAnimator class. +class ASH_EXPORT ShelfBackgroundAnimatorObserver { + public: + // Called when the Shelf's background should be updated. + virtual void UpdateShelfBackground(SkColor color) {} + + // Called when the Shelf item (aka button) backgrounds should be updated. + virtual void UpdateShelfItemBackground(SkColor color) {} + + protected: + virtual ~ShelfBackgroundAnimatorObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_BACKGROUND_ANIMATOR_OBSERVER_H_
diff --git a/ash/common/shelf/shelf_background_animator_unittest.cc b/ash/common/shelf/shelf_background_animator_unittest.cc new file mode 100644 index 0000000..9a3784c --- /dev/null +++ b/ash/common/shelf/shelf_background_animator_unittest.cc
@@ -0,0 +1,305 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_background_animator.h" + +#include <memory> + +#include "ash/animation/animation_change_type.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/wallpaper/wallpaper_controller.h" +#include "ash/common/wm_shell.h" +#include "base/bind.h" +#include "base/macros.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/animation/slide_animation.h" + +namespace ash { +namespace { + +static auto kMaxAlpha = ShelfBackgroundAnimator::kMaxAlpha; + +// A valid color value that is distinct from any final animation state values. +// Used to check if color values are changed during animations. +const SkColor kDummyColor = SK_ColorBLUE; + +// Observer that caches color values for the last observation. +class TestShelfBackgroundObserver : public ShelfBackgroundAnimatorObserver { + public: + TestShelfBackgroundObserver() {} + ~TestShelfBackgroundObserver() override {} + + SkColor background_color() const { return background_color_; } + + // Convenience function to get the alpha value from |background_color_|. + int GetBackgroundAlpha() const; + + SkColor item_background_color() const { return item_background_color_; } + + // Convenience function to get the alpha value from |item_background_color_|. + int GetItemBackgroundAlpha() const; + + // ShelfBackgroundObserver: + void UpdateShelfBackground(SkColor color) override; + void UpdateShelfItemBackground(SkColor color) override; + + private: + int background_color_ = SK_ColorTRANSPARENT; + int item_background_color_ = SK_ColorTRANSPARENT; + + DISALLOW_COPY_AND_ASSIGN(TestShelfBackgroundObserver); +}; + +int TestShelfBackgroundObserver::GetBackgroundAlpha() const { + return SkColorGetA(background_color_); +} + +int TestShelfBackgroundObserver::GetItemBackgroundAlpha() const { + return SkColorGetA(item_background_color_); +} + +void TestShelfBackgroundObserver::UpdateShelfBackground(SkColor color) { + background_color_ = color; +} + +void TestShelfBackgroundObserver::UpdateShelfItemBackground(SkColor color) { + item_background_color_ = color; +} + +} // namespace + +// Provides internal access to a ShelfBackgroundAnimator instance. +class ShelfBackgroundAnimatorTestApi { + public: + explicit ShelfBackgroundAnimatorTestApi(ShelfBackgroundAnimator* animator) + : animator_(animator) {} + + ~ShelfBackgroundAnimatorTestApi() {} + + ShelfBackgroundType previous_background_type() const { + return animator_->previous_background_type_; + } + + gfx::SlideAnimation* animator() const { return animator_->animator_.get(); } + + private: + // The instance to provide internal access to. + ShelfBackgroundAnimator* animator_; + + DISALLOW_COPY_AND_ASSIGN(ShelfBackgroundAnimatorTestApi); +}; + +class ShelfBackgroundAnimatorTest : public testing::Test { + public: + ShelfBackgroundAnimatorTest() {} + ~ShelfBackgroundAnimatorTest() override {} + + // testing::Test: + void SetUp() override; + + protected: + // Convenience wrapper for |animator_|'s PaintBackground(). + void PaintBackground( + ShelfBackgroundType background_type, + AnimationChangeType change_type = AnimationChangeType::IMMEDIATE); + + // Set all of the color values for the |observer_|. + void SetColorValuesOnObserver(SkColor color); + + // Completes all the animations. + void CompleteAnimations(); + + TestShelfBackgroundObserver observer_; + + // Test target. + std::unique_ptr<ShelfBackgroundAnimator> animator_; + + // Provides internal access to |animator_|. + std::unique_ptr<ShelfBackgroundAnimatorTestApi> test_api_; + + // Used to control the animations. + scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; + + private: + std::unique_ptr<base::ThreadTaskRunnerHandle> task_runner_handle_; + + DISALLOW_COPY_AND_ASSIGN(ShelfBackgroundAnimatorTest); +}; + +void ShelfBackgroundAnimatorTest::SetUp() { + task_runner_ = new base::TestMockTimeTaskRunner(); + task_runner_handle_.reset(new base::ThreadTaskRunnerHandle(task_runner_)); + + animator_.reset( + new ShelfBackgroundAnimator(SHELF_BACKGROUND_DEFAULT, nullptr, nullptr)); + animator_->AddObserver(&observer_); + + test_api_.reset(new ShelfBackgroundAnimatorTestApi(animator_.get())); +} + +void ShelfBackgroundAnimatorTest::PaintBackground( + ShelfBackgroundType background_type, + AnimationChangeType change_type) { + animator_->PaintBackground(background_type, change_type); +} + +void ShelfBackgroundAnimatorTest::SetColorValuesOnObserver(SkColor color) { + observer_.UpdateShelfBackground(color); + observer_.UpdateShelfItemBackground(color); +} + +void ShelfBackgroundAnimatorTest::CompleteAnimations() { + task_runner_->FastForwardUntilNoTasksRemain(); +} + +// Verify the |previous_background_type_| and |target_background_type_| values +// when animating to the same target type multiple times. +TEST_F(ShelfBackgroundAnimatorTest, BackgroundTypesWhenAnimatingToSameTarget) { + PaintBackground(SHELF_BACKGROUND_MAXIMIZED); + EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, animator_->target_background_type()); + + PaintBackground(SHELF_BACKGROUND_DEFAULT); + EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, animator_->target_background_type()); + EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, test_api_->previous_background_type()); + + PaintBackground(SHELF_BACKGROUND_DEFAULT); + EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, animator_->target_background_type()); + EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, test_api_->previous_background_type()); +} + +// Verify subsequent calls to PaintBackground() using the +// AnimationChangeType::ANIMATE change type are ignored. +TEST_F(ShelfBackgroundAnimatorTest, + MultipleAnimateCallsToSameTargetAreIgnored) { + PaintBackground(SHELF_BACKGROUND_MAXIMIZED); + SetColorValuesOnObserver(kDummyColor); + animator_->PaintBackground(SHELF_BACKGROUND_DEFAULT, + AnimationChangeType::ANIMATE); + CompleteAnimations(); + + EXPECT_NE(observer_.background_color(), kDummyColor); + EXPECT_NE(observer_.item_background_color(), kDummyColor); + + SetColorValuesOnObserver(kDummyColor); + animator_->PaintBackground(SHELF_BACKGROUND_DEFAULT, + AnimationChangeType::ANIMATE); + CompleteAnimations(); + + EXPECT_EQ(observer_.background_color(), kDummyColor); + EXPECT_EQ(observer_.item_background_color(), kDummyColor); +} + +// Verify observers are updated with the current values when they are added. +TEST_F(ShelfBackgroundAnimatorTest, ObserversUpdatedWhenAdded) { + animator_->RemoveObserver(&observer_); + SetColorValuesOnObserver(kDummyColor); + + animator_->AddObserver(&observer_); + + EXPECT_NE(observer_.background_color(), kDummyColor); + EXPECT_NE(observer_.item_background_color(), kDummyColor); +} + +// Verify the alpha values for the SHELF_BACKGROUND_DEFAULT state. +TEST_F(ShelfBackgroundAnimatorTest, DefaultBackground) { + PaintBackground(SHELF_BACKGROUND_DEFAULT); + + EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, animator_->target_background_type()); + EXPECT_EQ(0, observer_.GetBackgroundAlpha()); + EXPECT_EQ(kShelfTranslucentAlpha, observer_.GetItemBackgroundAlpha()); +} + +// Verify the alpha values for the SHELF_BACKGROUND_OVERLAP state. +TEST_F(ShelfBackgroundAnimatorTest, OverlapBackground) { + PaintBackground(SHELF_BACKGROUND_OVERLAP); + + EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, animator_->target_background_type()); + EXPECT_EQ(kShelfTranslucentAlpha, observer_.GetBackgroundAlpha()); + EXPECT_EQ(0, observer_.GetItemBackgroundAlpha()); +} + +// Verify the alpha values for the SHELF_BACKGROUND_MAXIMIZED state. +TEST_F(ShelfBackgroundAnimatorTest, MaximizedBackground) { + PaintBackground(SHELF_BACKGROUND_MAXIMIZED); + + EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, animator_->target_background_type()); + EXPECT_EQ(kMaxAlpha, observer_.GetBackgroundAlpha()); + EXPECT_EQ(0, observer_.GetItemBackgroundAlpha()); +} + +TEST_F(ShelfBackgroundAnimatorTest, + AnimatorIsDetroyedWhenCompletingSuccessfully) { + PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); + EXPECT_TRUE(test_api_->animator()); + CompleteAnimations(); + EXPECT_FALSE(test_api_->animator()); +} + +TEST_F(ShelfBackgroundAnimatorTest, + AnimatorDestroyedWhenChangingBackgroundImmediately) { + PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); + EXPECT_TRUE(test_api_->animator()); + + PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::IMMEDIATE); + EXPECT_FALSE(test_api_->animator()); +} + +// Verify that existing animator is used when animating to the previous state. +TEST_F(ShelfBackgroundAnimatorTest, + ExistingAnimatorIsReusedWhenAnimatingToPreviousState) { + PaintBackground(SHELF_BACKGROUND_DEFAULT, AnimationChangeType::ANIMATE); + PaintBackground(SHELF_BACKGROUND_MAXIMIZED, AnimationChangeType::ANIMATE); + + const gfx::SlideAnimation* animator = test_api_->animator(); + EXPECT_TRUE(animator); + + PaintBackground(SHELF_BACKGROUND_DEFAULT, AnimationChangeType::ANIMATE); + + EXPECT_EQ(animator, test_api_->animator()); +} + +// Verify that existing animator is not re-used when the target background isn't +// the same as the previous background. +TEST_F(ShelfBackgroundAnimatorTest, + ExistingAnimatorNotReusedWhenTargetBackgroundNotPreviousBackground) { + PaintBackground(SHELF_BACKGROUND_DEFAULT, AnimationChangeType::ANIMATE); + PaintBackground(SHELF_BACKGROUND_MAXIMIZED, AnimationChangeType::ANIMATE); + + const gfx::SlideAnimation* animator = test_api_->animator(); + EXPECT_TRUE(animator); + + EXPECT_NE(SHELF_BACKGROUND_OVERLAP, test_api_->previous_background_type()); + PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); + + EXPECT_NE(animator, test_api_->animator()); +} + +TEST_F(ShelfBackgroundAnimatorTest, + AnimationProgressesToTargetWhenStoppingUnfinishedAnimator) { + PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); + + EXPECT_NE(kShelfTranslucentAlpha, observer_.GetBackgroundAlpha()); + EXPECT_NE(0, observer_.GetItemBackgroundAlpha()); + + test_api_->animator()->Stop(); + + EXPECT_EQ(kShelfTranslucentAlpha, observer_.GetBackgroundAlpha()); + EXPECT_EQ(0, observer_.GetItemBackgroundAlpha()); +} + +// Verify observers are always notified, even when alpha values don't change. +TEST_F(ShelfBackgroundAnimatorTest, + ObserversAreNotifiedWhenSnappingToSameTargetBackground) { + PaintBackground(SHELF_BACKGROUND_DEFAULT); + SetColorValuesOnObserver(kDummyColor); + PaintBackground(SHELF_BACKGROUND_DEFAULT); + + EXPECT_NE(observer_.background_color(), kDummyColor); + EXPECT_NE(observer_.item_background_color(), kDummyColor); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_button.cc b/ash/common/shelf/shelf_button.cc new file mode 100644 index 0000000..d5d32ff7 --- /dev/null +++ b/ash/common/shelf/shelf_button.cc
@@ -0,0 +1,514 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_button.h" + +#include <algorithm> + +#include "ash/common/ash_constants.h" +#include "ash/common/shelf/ink_drop_button_listener.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "base/memory/ptr_util.h" +#include "base/time/time.h" +#include "skia/ext/image_operations.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/animation/animation_delegate.h" +#include "ui/gfx/animation/throb_animation.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/scoped_canvas.h" +#include "ui/gfx/skbitmap_operations.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/square_ink_drop_ripple.h" +#include "ui/views/controls/image_view.h" + +namespace { + +const int kIconSize = 32; +const int kAttentionThrobDurationMS = 800; +const int kMaxAnimationSeconds = 10; +const int kIndicatorOffsetFromBottom = 3; +const int kIndicatorRadiusDip = 2; +const SkColor kIndicatorColor = SK_ColorWHITE; + +// Shelf item ripple constants. +const int kInkDropSmallSize = 48; +const int kInkDropLargeSize = 60; + +// Padding from the edge of the shelf to the application icon when the shelf +// is horizontally and vertically aligned, respectively. +const int kIconPaddingHorizontal = 7; +const int kIconPaddingVertical = 8; + +// Simple AnimationDelegate that owns a single ThrobAnimation instance to +// keep all Draw Attention animations in sync. +class ShelfButtonAnimation : public gfx::AnimationDelegate { + public: + class Observer { + public: + virtual void AnimationProgressed() = 0; + + protected: + virtual ~Observer() {} + }; + + static ShelfButtonAnimation* GetInstance() { + static ShelfButtonAnimation* s_instance = new ShelfButtonAnimation(); + return s_instance; + } + + void AddObserver(Observer* observer) { observers_.AddObserver(observer); } + + void RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); + if (!observers_.might_have_observers()) + animation_.Stop(); + } + + bool HasObserver(Observer* observer) const { + return observers_.HasObserver(observer); + } + + SkAlpha GetAlpha() { + return GetThrobAnimation().CurrentValueBetween(SK_AlphaTRANSPARENT, + SK_AlphaOPAQUE); + } + + double GetAnimation() { return GetThrobAnimation().GetCurrentValue(); } + + private: + ShelfButtonAnimation() : animation_(this) { + animation_.SetThrobDuration(kAttentionThrobDurationMS); + animation_.SetTweenType(gfx::Tween::SMOOTH_IN_OUT); + } + + ~ShelfButtonAnimation() override {} + + gfx::ThrobAnimation& GetThrobAnimation() { + if (!animation_.is_animating()) { + animation_.Reset(); + animation_.StartThrobbing(-1 /*throb indefinitely*/); + } + return animation_; + } + + // gfx::AnimationDelegate + void AnimationProgressed(const gfx::Animation* animation) override { + if (animation != &animation_) + return; + if (!animation_.is_animating()) + return; + for (auto& observer : observers_) + observer.AnimationProgressed(); + } + + gfx::ThrobAnimation animation_; + base::ObserverList<Observer> observers_; + + DISALLOW_COPY_AND_ASSIGN(ShelfButtonAnimation); +}; + +} // namespace + +namespace ash { + +//////////////////////////////////////////////////////////////////////////////// +// ShelfButton::AppStatusIndicatorView + +class ShelfButton::AppStatusIndicatorView + : public views::View, + public ShelfButtonAnimation::Observer { + public: + AppStatusIndicatorView() + : show_attention_(false), animation_end_time_(base::TimeTicks()) { + // Make sure the events reach the parent view for handling. + set_can_process_events_within_subtree(false); + } + + ~AppStatusIndicatorView() override { + ShelfButtonAnimation::GetInstance()->RemoveObserver(this); + } + + // views::View: + void OnPaint(gfx::Canvas* canvas) override { + gfx::ScopedCanvas scoped(canvas); + if (show_attention_) { + SkAlpha alpha = ShelfButtonAnimation::GetInstance()->HasObserver(this) + ? ShelfButtonAnimation::GetInstance()->GetAlpha() + : SK_AlphaOPAQUE; + canvas->SaveLayerAlpha(alpha); + } + + DCHECK_EQ(width(), height()); + DCHECK_EQ(kIndicatorRadiusDip, width() / 2); + const float dsf = canvas->UndoDeviceScaleFactor(); + const int kStrokeWidthPx = 1; + gfx::PointF center = gfx::RectF(GetLocalBounds()).CenterPoint(); + center.Scale(dsf); + + // Fill the center. + cc::PaintFlags flags; + flags.setColor(kIndicatorColor); + flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); + canvas->DrawCircle(center, dsf * kIndicatorRadiusDip - kStrokeWidthPx, + flags); + + // Stroke the border. + flags.setColor(SkColorSetA(SK_ColorBLACK, 0x4D)); + flags.setStyle(SkPaint::kStroke_Style); + canvas->DrawCircle( + center, dsf * kIndicatorRadiusDip - kStrokeWidthPx / 2.0f, flags); + } + + // ShelfButtonAnimation::Observer + void AnimationProgressed() override { + UpdateAnimating(); + SchedulePaint(); + } + + void ShowAttention(bool show) { + if (show_attention_ == show) + return; + + show_attention_ = show; + if (show_attention_) { + animation_end_time_ = base::TimeTicks::Now() + + base::TimeDelta::FromSeconds(kMaxAnimationSeconds); + ShelfButtonAnimation::GetInstance()->AddObserver(this); + } else { + ShelfButtonAnimation::GetInstance()->RemoveObserver(this); + } + } + + private: + void UpdateAnimating() { + if (base::TimeTicks::Now() > animation_end_time_) + ShelfButtonAnimation::GetInstance()->RemoveObserver(this); + } + + bool show_attention_; + base::TimeTicks animation_end_time_; // For attention throbbing underline. + + DISALLOW_COPY_AND_ASSIGN(AppStatusIndicatorView); +}; + +//////////////////////////////////////////////////////////////////////////////// +// ShelfButton + +// static +const char ShelfButton::kViewClassName[] = "ash/ShelfButton"; + +ShelfButton::ShelfButton(InkDropButtonListener* listener, ShelfView* shelf_view) + : CustomButton(nullptr), + listener_(listener), + shelf_view_(shelf_view), + icon_view_(new views::ImageView()), + indicator_(new AppStatusIndicatorView()), + state_(STATE_NORMAL), + destroyed_flag_(nullptr) { + SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); + SetInkDropMode(InkDropMode::ON); + set_ink_drop_base_color(kShelfInkDropBaseColor); + set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); + + const gfx::ShadowValue kShadows[] = { + gfx::ShadowValue(gfx::Vector2d(0, 2), 0, SkColorSetARGB(0x1A, 0, 0, 0)), + gfx::ShadowValue(gfx::Vector2d(0, 3), 1, SkColorSetARGB(0x1A, 0, 0, 0)), + gfx::ShadowValue(gfx::Vector2d(0, 0), 1, SkColorSetARGB(0x54, 0, 0, 0)), + }; + icon_shadows_.assign(kShadows, kShadows + arraysize(kShadows)); + + // TODO: refactor the layers so each button doesn't require 2. + icon_view_->SetPaintToLayer(); + icon_view_->layer()->SetFillsBoundsOpaquely(false); + icon_view_->SetHorizontalAlignment(views::ImageView::CENTER); + icon_view_->SetVerticalAlignment(views::ImageView::LEADING); + // Do not make this interactive, so that events are sent to ShelfView. + icon_view_->set_can_process_events_within_subtree(false); + + AddChildView(indicator_); + AddChildView(icon_view_); +} + +ShelfButton::~ShelfButton() { + if (destroyed_flag_) + *destroyed_flag_ = true; +} + +void ShelfButton::SetShadowedImage(const gfx::ImageSkia& image) { + icon_view_->SetImage(gfx::ImageSkiaOperations::CreateImageWithDropShadow( + image, icon_shadows_)); +} + +void ShelfButton::SetImage(const gfx::ImageSkia& image) { + if (image.isNull()) { + // TODO: need an empty image. + icon_view_->SetImage(image); + return; + } + + // Resize the image maintaining our aspect ratio. + float aspect_ratio = + static_cast<float>(image.width()) / static_cast<float>(image.height()); + int height = kIconSize; + int width = static_cast<int>(aspect_ratio * height); + if (width > kIconSize) { + width = kIconSize; + height = static_cast<int>(width / aspect_ratio); + } + + if (width == image.width() && height == image.height()) { + SetShadowedImage(image); + return; + } + + SetShadowedImage(gfx::ImageSkiaOperations::CreateResizedImage( + image, skia::ImageOperations::RESIZE_BEST, gfx::Size(width, height))); +} + +const gfx::ImageSkia& ShelfButton::GetImage() const { + return icon_view_->GetImage(); +} + +void ShelfButton::AddState(State state) { + if (!(state_ & state)) { + state_ |= state; + Layout(); + if (state & STATE_ATTENTION) + indicator_->ShowAttention(true); + } +} + +void ShelfButton::ClearState(State state) { + if (state_ & state) { + state_ &= ~state; + Layout(); + if (state & STATE_ATTENTION) + indicator_->ShowAttention(false); + } +} + +gfx::Rect ShelfButton::GetIconBounds() const { + return icon_view_->bounds(); +} + +void ShelfButton::OnDragStarted(const ui::LocatedEvent* event) { + AnimateInkDrop(views::InkDropState::HIDDEN, event); +} + +void ShelfButton::ShowContextMenu(const gfx::Point& p, + ui::MenuSourceType source_type) { + if (!context_menu_controller()) + return; + + bool destroyed = false; + destroyed_flag_ = &destroyed; + + CustomButton::ShowContextMenu(p, source_type); + + if (!destroyed) { + destroyed_flag_ = nullptr; + // The menu will not propagate mouse events while its shown. To address, + // the hover state gets cleared once the menu was shown (and this was not + // destroyed). + ClearState(STATE_HOVERED); + } +} + +const char* ShelfButton::GetClassName() const { + return kViewClassName; +} + +bool ShelfButton::OnMousePressed(const ui::MouseEvent& event) { + CustomButton::OnMousePressed(event); + shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); + return true; +} + +void ShelfButton::OnMouseReleased(const ui::MouseEvent& event) { + CustomButton::OnMouseReleased(event); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); +} + +void ShelfButton::OnMouseCaptureLost() { + ClearState(STATE_HOVERED); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, true); + CustomButton::OnMouseCaptureLost(); +} + +bool ShelfButton::OnMouseDragged(const ui::MouseEvent& event) { + CustomButton::OnMouseDragged(event); + shelf_view_->PointerDraggedOnButton(this, ShelfView::MOUSE, event); + return true; +} + +void ShelfButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_BUTTON; + node_data->SetName(shelf_view_->GetTitleForView(this)); +} + +void ShelfButton::Layout() { + const gfx::Rect button_bounds(GetContentsBounds()); + WmShelf* wm_shelf = shelf_view_->wm_shelf(); + const bool is_horizontal_shelf = wm_shelf->IsHorizontalAlignment(); + const int icon_pad = + is_horizontal_shelf ? kIconPaddingHorizontal : kIconPaddingVertical; + int x_offset = is_horizontal_shelf ? 0 : icon_pad; + int y_offset = is_horizontal_shelf ? icon_pad : 0; + + int icon_width = std::min(kIconSize, button_bounds.width() - x_offset); + int icon_height = std::min(kIconSize, button_bounds.height() - y_offset); + + // If on the left or top 'invert' the inset so the constant gap is on + // the interior (towards the center of display) edge of the shelf. + if (SHELF_ALIGNMENT_LEFT == wm_shelf->GetAlignment()) + x_offset = button_bounds.width() - (kIconSize + icon_pad); + + // Center icon with respect to the secondary axis. + if (is_horizontal_shelf) + x_offset = std::max(0, button_bounds.width() - icon_width) / 2; + else + y_offset = std::max(0, button_bounds.height() - icon_height) / 2; + + // Expand bounds to include shadows. + gfx::Insets insets_shadows = gfx::ShadowValue::GetMargin(icon_shadows_); + // Adjust offsets to center icon, not icon + shadow. + x_offset += (insets_shadows.left() - insets_shadows.right()) / 2; + y_offset += (insets_shadows.top() - insets_shadows.bottom()) / 2; + gfx::Rect icon_view_bounds = + gfx::Rect(button_bounds.x() + x_offset, button_bounds.y() + y_offset, + icon_width, icon_height); + // The indicator should be aligned with the icon, not the icon + shadow. + gfx::Point indicator_midpoint = icon_view_bounds.CenterPoint(); + icon_view_bounds.Inset(insets_shadows); + icon_view_bounds.AdjustToFit(gfx::Rect(size())); + icon_view_->SetBoundsRect(icon_view_bounds); + + // Icon size has been incorrect when running + // PanelLayoutManagerTest.PanelAlignmentSecondDisplay on valgrind bot, see + // http://crbug.com/234854. + DCHECK_LE(icon_width, kIconSize); + DCHECK_LE(icon_height, kIconSize); + + switch (wm_shelf->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + indicator_midpoint.set_y(button_bounds.bottom() - kIndicatorRadiusDip - + kIndicatorOffsetFromBottom); + break; + case SHELF_ALIGNMENT_LEFT: + indicator_midpoint.set_x(button_bounds.x() + kIndicatorRadiusDip + + kIndicatorOffsetFromBottom); + break; + case SHELF_ALIGNMENT_RIGHT: + indicator_midpoint.set_x(button_bounds.right() - kIndicatorRadiusDip - + kIndicatorOffsetFromBottom); + break; + } + + gfx::Rect indicator_bounds(indicator_midpoint, gfx::Size()); + indicator_bounds.Inset(gfx::Insets(-kIndicatorRadiusDip)); + indicator_->SetBoundsRect(indicator_bounds); + + UpdateState(); +} + +void ShelfButton::ChildPreferredSizeChanged(views::View* child) { + Layout(); +} + +void ShelfButton::OnFocus() { + AddState(STATE_FOCUSED); + CustomButton::OnFocus(); +} + +void ShelfButton::OnBlur() { + ClearState(STATE_FOCUSED); + CustomButton::OnBlur(); +} + +void ShelfButton::OnPaint(gfx::Canvas* canvas) { + CustomButton::OnPaint(canvas); + if (HasFocus()) { + canvas->DrawSolidFocusRect(gfx::RectF(GetLocalBounds()), kFocusBorderColor, + kFocusBorderThickness); + } +} + +void ShelfButton::OnGestureEvent(ui::GestureEvent* event) { + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: + AddState(STATE_HOVERED); + return CustomButton::OnGestureEvent(event); + case ui::ET_GESTURE_END: + ClearState(STATE_HOVERED); + return CustomButton::OnGestureEvent(event); + case ui::ET_GESTURE_SCROLL_BEGIN: + shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); + event->SetHandled(); + return; + case ui::ET_GESTURE_SCROLL_UPDATE: + shelf_view_->PointerDraggedOnButton(this, ShelfView::TOUCH, *event); + event->SetHandled(); + return; + case ui::ET_GESTURE_SCROLL_END: + case ui::ET_SCROLL_FLING_START: + shelf_view_->PointerReleasedOnButton(this, ShelfView::TOUCH, false); + event->SetHandled(); + return; + default: + return CustomButton::OnGestureEvent(event); + } +} + +std::unique_ptr<views::InkDropRipple> ShelfButton::CreateInkDropRipple() const { + return base::MakeUnique<views::SquareInkDropRipple>( + gfx::Size(kInkDropLargeSize, kInkDropLargeSize), + kInkDropLargeCornerRadius, + gfx::Size(kInkDropSmallSize, kInkDropSmallSize), + kInkDropSmallCornerRadius, GetLocalBounds().CenterPoint(), + GetInkDropBaseColor(), ink_drop_visible_opacity()); +} + +bool ShelfButton::ShouldEnterPushedState(const ui::Event& event) { + if (!shelf_view_->ShouldEventActivateButton(this, event)) + return false; + + return CustomButton::ShouldEnterPushedState(event); +} + +std::unique_ptr<views::InkDrop> ShelfButton::CreateInkDrop() { + std::unique_ptr<views::InkDropImpl> ink_drop = + CustomButton::CreateDefaultInkDropImpl(); + ink_drop->SetShowHighlightOnHover(false); + return std::move(ink_drop); +} + +void ShelfButton::NotifyClick(const ui::Event& event) { + CustomButton::NotifyClick(event); + if (listener_) + listener_->ButtonPressed(this, event, GetInkDrop()); +} + +void ShelfButton::UpdateState() { + indicator_->SetVisible(!(state_ & STATE_HIDDEN) && + (state_ & STATE_ACTIVE || state_ & STATE_ATTENTION || + state_ & STATE_RUNNING)); + + const bool is_horizontal_shelf = + shelf_view_->wm_shelf()->IsHorizontalAlignment(); + icon_view_->SetHorizontalAlignment(is_horizontal_shelf + ? views::ImageView::CENTER + : views::ImageView::LEADING); + icon_view_->SetVerticalAlignment(is_horizontal_shelf + ? views::ImageView::LEADING + : views::ImageView::CENTER); + SchedulePaint(); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_button.h b/ash/common/shelf/shelf_button.h new file mode 100644 index 0000000..4f828ea18 --- /dev/null +++ b/ash/common/shelf/shelf_button.h
@@ -0,0 +1,129 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_BUTTON_H_ +#define ASH_COMMON_SHELF_SHELF_BUTTON_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/gfx/shadow_value.h" +#include "ui/views/controls/button/custom_button.h" + +namespace views { +class ImageView; +} + +namespace ash { +class InkDropButtonListener; +class ShelfView; + +// Button used for items on the launcher, except for the AppList. +class ASH_EXPORT ShelfButton : public views::CustomButton { + public: + static const char kViewClassName[]; + + // Used to indicate the current state of the button. + enum State { + // Nothing special. Usually represents an app shortcut item with no running + // instance. + STATE_NORMAL = 0, + // Button has mouse hovering on it. + STATE_HOVERED = 1 << 0, + // Underlying ShelfItem has a running instance. + STATE_RUNNING = 1 << 1, + // Underlying ShelfItem is active (i.e. has focus). + STATE_ACTIVE = 1 << 2, + // Underlying ShelfItem needs user's attention. + STATE_ATTENTION = 1 << 3, + STATE_FOCUSED = 1 << 4, + // Hide the status (temporarily for some animations). + STATE_HIDDEN = 1 << 5, + }; + + ShelfButton(InkDropButtonListener* listener, ShelfView* shelf_view); + ~ShelfButton() override; + + // Sets the image to display for this entry. + void SetImage(const gfx::ImageSkia& image); + + // Retrieve the image to show proxy operations. + const gfx::ImageSkia& GetImage() const; + + // |state| is or'd into the current state. + void AddState(State state); + void ClearState(State state); + int state() const { return state_; } + + // Returns the bounds of the icon. + gfx::Rect GetIconBounds() const; + + // Called when user started dragging the shelf button. + void OnDragStarted(const ui::LocatedEvent* event); + + // Overrides to views::CustomButton: + void ShowContextMenu(const gfx::Point& p, + ui::MenuSourceType source_type) override; + + // View override - needed by unit test. + void OnMouseCaptureLost() override; + + protected: + // View overrides: + const char* GetClassName() const override; + bool OnMousePressed(const ui::MouseEvent& event) override; + void OnMouseReleased(const ui::MouseEvent& event) override; + bool OnMouseDragged(const ui::MouseEvent& event) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void Layout() override; + void ChildPreferredSizeChanged(views::View* child) override; + void OnFocus() override; + void OnBlur() override; + void OnPaint(gfx::Canvas* canvas) override; + + // ui::EventHandler overrides: + void OnGestureEvent(ui::GestureEvent* event) override; + + // views::CustomButton overrides: + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + bool ShouldEnterPushedState(const ui::Event& event) override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + void NotifyClick(const ui::Event& event) override; + + // Sets the icon image with a shadow. + void SetShadowedImage(const gfx::ImageSkia& bitmap); + + private: + class AppStatusIndicatorView; + + // Updates the parts of the button to reflect the current |state_| and + // alignment. This may add or remove views, layout and paint. + void UpdateState(); + + InkDropButtonListener* listener_; + + // The shelf view hosting this button. + ShelfView* shelf_view_; + + // The icon part of a button can be animated independently of the rest. + views::ImageView* icon_view_; + + // Draws an indicator underneath the image to represent the state of the + // application. + AppStatusIndicatorView* indicator_; + + // The current application state, a bitfield of State enum values. + int state_; + + gfx::ShadowValues icon_shadows_; + + // If non-null the destuctor sets this to true. This is set while the menu is + // showing and used to detect if the menu was deleted while running. + bool* destroyed_flag_; + + DISALLOW_COPY_AND_ASSIGN(ShelfButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_BUTTON_H_
diff --git a/ash/common/shelf/shelf_button_pressed_metric_tracker.cc b/ash/common/shelf/shelf_button_pressed_metric_tracker.cc new file mode 100644 index 0000000..a27ff74 --- /dev/null +++ b/ash/common/shelf/shelf_button_pressed_metric_tracker.cc
@@ -0,0 +1,100 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_button_pressed_metric_tracker.h" + +#include "ash/common/wm_shell.h" +#include "base/metrics/histogram_macros.h" +#include "base/time/default_tick_clock.h" +#include "ui/views/controls/button/button.h" + +namespace ash { + +const char ShelfButtonPressedMetricTracker:: + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName[] = + "Ash.Shelf.TimeBetweenWindowMinimizedAndActivatedActions"; + +ShelfButtonPressedMetricTracker::ShelfButtonPressedMetricTracker() + : tick_clock_(new base::DefaultTickClock()), + time_of_last_minimize_(base::TimeTicks()), + last_minimized_source_button_(nullptr) {} + +ShelfButtonPressedMetricTracker::~ShelfButtonPressedMetricTracker() {} + +void ShelfButtonPressedMetricTracker::ButtonPressed( + const ui::Event& event, + const views::Button* sender, + ShelfAction performed_action) { + RecordButtonPressedSource(event); + RecordButtonPressedAction(performed_action); + + switch (performed_action) { + case SHELF_ACTION_WINDOW_MINIMIZED: + SetMinimizedData(sender); + break; + case SHELF_ACTION_WINDOW_ACTIVATED: + if (IsSubsequentActivationEvent(sender)) + RecordTimeBetweenMinimizedAndActivated(); + break; + default: + break; + } + + if (performed_action != SHELF_ACTION_WINDOW_MINIMIZED) + ResetMinimizedData(); +} + +void ShelfButtonPressedMetricTracker::RecordButtonPressedSource( + const ui::Event& event) { + if (event.IsMouseEvent()) { + WmShell::Get()->RecordUserMetricsAction( + UMA_LAUNCHER_BUTTON_PRESSED_WITH_MOUSE); + } else if (event.IsGestureEvent()) { + WmShell::Get()->RecordUserMetricsAction( + UMA_LAUNCHER_BUTTON_PRESSED_WITH_TOUCH); + } +} + +void ShelfButtonPressedMetricTracker::RecordButtonPressedAction( + ShelfAction performed_action) { + switch (performed_action) { + case SHELF_ACTION_NONE: + case SHELF_ACTION_APP_LIST_SHOWN: + break; + case SHELF_ACTION_NEW_WINDOW_CREATED: + WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_LAUNCH_TASK); + break; + case SHELF_ACTION_WINDOW_ACTIVATED: + WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_SWITCH_TASK); + break; + case SHELF_ACTION_WINDOW_MINIMIZED: + WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_MINIMIZE_TASK); + break; + } +} + +void ShelfButtonPressedMetricTracker::RecordTimeBetweenMinimizedAndActivated() { + UMA_HISTOGRAM_TIMES( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, + tick_clock_->NowTicks() - time_of_last_minimize_); +} + +bool ShelfButtonPressedMetricTracker::IsSubsequentActivationEvent( + const views::Button* sender) const { + return time_of_last_minimize_ != base::TimeTicks() && + last_minimized_source_button_ == sender; +} + +void ShelfButtonPressedMetricTracker::SetMinimizedData( + const views::Button* sender) { + last_minimized_source_button_ = sender; + time_of_last_minimize_ = tick_clock_->NowTicks(); +} + +void ShelfButtonPressedMetricTracker::ResetMinimizedData() { + last_minimized_source_button_ = nullptr; + time_of_last_minimize_ = base::TimeTicks(); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_button_pressed_metric_tracker.h b/ash/common/shelf/shelf_button_pressed_metric_tracker.h new file mode 100644 index 0000000..5cf1991 --- /dev/null +++ b/ash/common/shelf/shelf_button_pressed_metric_tracker.h
@@ -0,0 +1,91 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_H_ +#define ASH_COMMON_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_item_delegate.h" +#include "base/macros.h" +#include "base/time/tick_clock.h" +#include "base/time/time.h" +#include "ui/events/event.h" + +namespace views { +class Button; +} // namespace views + +namespace ash { + +namespace test { +class ShelfButtonPressedMetricTrackerTestAPI; +} // namespace test + +// Tracks UMA metrics based on shelf button press actions. More specifically +// data is added to the following user actions and histograms: +// +// User Actions: +// - Launcher_ButtonPressed_Mouse +// - Launcher_ButtonPressed_Touch +// - Launcher_LaunchTask +// - Launcher_MinimizeTask +// - Launcher_SwitchTask +// Histograms: +// - Ash.Shelf.TimeBetweenWindowMinimizedAndActivatedActions +// +class ASH_EXPORT ShelfButtonPressedMetricTracker { + public: + static const char + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName[]; + + ShelfButtonPressedMetricTracker(); + ~ShelfButtonPressedMetricTracker(); + + // Records metrics based on the |event|, |sender|, and |performed_action|. + void ButtonPressed(const ui::Event& event, + const views::Button* sender, + ShelfAction performed_action); + + private: + friend class test::ShelfButtonPressedMetricTrackerTestAPI; + + // Records UMA metrics for the input source when a button is pressed. + void RecordButtonPressedSource(const ui::Event& event); + + // Records UMA metrics for the action performed when a button is pressed. + void RecordButtonPressedAction(ShelfAction performed_action); + + // Records UMA metrics for the elapsed time since the last window minimize + // action. + void RecordTimeBetweenMinimizedAndActivated(); + + // Returns true if a window activation action triggered by |sender| would + // be subsequent to the last minimize window action. + bool IsSubsequentActivationEvent(const views::Button* sender) const; + + // Caches state data for a window minimized action. The |sender| is the button + // that caused the action. + void SetMinimizedData(const views::Button* sender); + + // Resets the state data associated with the last window minimize action. + void ResetMinimizedData(); + + // Time source for performed action times. + std::unique_ptr<base::TickClock> tick_clock_; + + // Stores the time of the last window minimize action. + base::TimeTicks time_of_last_minimize_; + + // Stores the source button of the last window minimize action. + // NOTE: This may become stale and should not be operated on. Not owned. + const views::Button* last_minimized_source_button_; + + DISALLOW_COPY_AND_ASSIGN(ShelfButtonPressedMetricTracker); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_H_
diff --git a/ash/common/shelf/shelf_button_pressed_metric_tracker_unittest.cc b/ash/common/shelf/shelf_button_pressed_metric_tracker_unittest.cc new file mode 100644 index 0000000..2461306 --- /dev/null +++ b/ash/common/shelf/shelf_button_pressed_metric_tracker_unittest.cc
@@ -0,0 +1,314 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_button_pressed_metric_tracker.h" + +#include <utility> + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/shelf_button_pressed_metric_tracker_test_api.h" +#include "ash/test/shelf_view_test_api.h" +#include "base/macros.h" +#include "base/test/histogram_tester.h" +#include "base/test/simple_test_tick_clock.h" +#include "base/test/user_action_tester.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/event.h" +#include "ui/views/controls/button/button.h" + +namespace ash { +namespace test { +namespace { + +// A simple light weight test double dummy for a views::Button. +class DummyButton : public views::Button { + public: + DummyButton(); + + private: + DISALLOW_COPY_AND_ASSIGN(DummyButton); +}; + +DummyButton::DummyButton() : views::Button(nullptr) {} + +// A simple light weight test double dummy for a ui::Event. +class DummyEvent : public ui::Event { + public: + DummyEvent(); + ~DummyEvent() override; + int unique_id() const { return unique_id_; } + + private: + static int next_unique_id_; + int unique_id_; + + DISALLOW_COPY_AND_ASSIGN(DummyEvent); +}; + +int DummyEvent::next_unique_id_ = 0; + +DummyEvent::DummyEvent() + : Event(ui::ET_GESTURE_TAP, base::TimeTicks(), 0), + unique_id_(next_unique_id_++) {} + +DummyEvent::~DummyEvent() {} + +// Test fixture for the ShelfButtonPressedMetricTracker class. Relies on +// AshTestBase to initilize the UserMetricsRecorder and it's dependencies. +class ShelfButtonPressedMetricTrackerTest : public AshTestBase { + public: + static const char* + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName; + + ShelfButtonPressedMetricTrackerTest(); + ~ShelfButtonPressedMetricTrackerTest() override; + + // AshTestBase: + void SetUp() override; + void TearDown() override; + + // Calls ButtonPressed on the test target with the given |event| + // and dummy values for the |sender| and |performed_action| parameters. + void ButtonPressed(const ui::Event& event); + + // Calls ButtonPressed on the test target with the given |performed_action| + // and dummy values for the |event| and |sender| parameters. + void ButtonPressed(ShelfAction performed_action); + + // Calls ButtonPressed on the test target with the given |sender| and + // |performed_action| and a dummy value for the |event| parameter. + void ButtonPressed(const views::Button* sender, ShelfAction performed_action); + + protected: + // The test target. Not owned. + ShelfButtonPressedMetricTracker* metric_tracker_; + + // The TickClock injected in to the test target. + base::SimpleTestTickClock* tick_clock_; + + private: + DISALLOW_COPY_AND_ASSIGN(ShelfButtonPressedMetricTrackerTest); +}; + +const char* ShelfButtonPressedMetricTrackerTest:: + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName = + ShelfButtonPressedMetricTracker:: + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName; + +ShelfButtonPressedMetricTrackerTest::ShelfButtonPressedMetricTrackerTest() {} + +ShelfButtonPressedMetricTrackerTest::~ShelfButtonPressedMetricTrackerTest() {} + +void ShelfButtonPressedMetricTrackerTest::SetUp() { + AshTestBase::SetUp(); + + WmShelf* wm_shelf = GetPrimaryShelf(); + ShelfViewTestAPI shelf_view_test_api(wm_shelf->GetShelfViewForTesting()); + + metric_tracker_ = shelf_view_test_api.shelf_button_pressed_metric_tracker(); + + ShelfButtonPressedMetricTrackerTestAPI test_api(metric_tracker_); + + std::unique_ptr<base::TickClock> test_tick_clock( + new base::SimpleTestTickClock()); + tick_clock_ = static_cast<base::SimpleTestTickClock*>(test_tick_clock.get()); + test_api.SetTickClock(std::move(test_tick_clock)); + + // Ensure the TickClock->NowTicks() doesn't return base::TimeTicks because + // ShelfButtonPressedMetricTracker interprets that value as unset. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(100)); +} + +void ShelfButtonPressedMetricTrackerTest::TearDown() { + tick_clock_ = nullptr; + + AshTestBase::TearDown(); +} + +void ShelfButtonPressedMetricTrackerTest::ButtonPressed( + const ui::Event& event) { + const DummyButton kDummyButton; + metric_tracker_->ButtonPressed(event, &kDummyButton, SHELF_ACTION_NONE); +} + +void ShelfButtonPressedMetricTrackerTest::ButtonPressed( + ShelfAction performed_action) { + const DummyEvent kDummyEvent; + const DummyButton kDummyButton; + metric_tracker_->ButtonPressed(kDummyEvent, &kDummyButton, performed_action); +} + +void ShelfButtonPressedMetricTrackerTest::ButtonPressed( + const views::Button* sender, + ShelfAction performed_action) { + const DummyEvent kDummyEvent; + metric_tracker_->ButtonPressed(kDummyEvent, sender, performed_action); +} + +} // namespace + +// Verifies that a Launcher_ButtonPressed_Mouse UMA user action is recorded when +// a button is pressed by a mouse event. +TEST_F(ShelfButtonPressedMetricTrackerTest, + Launcher_ButtonPressed_MouseIsRecordedWhenIconActivatedByMouse) { + // TODO: investigate failure in mash. http://crbug.com/695565. + if (WmShell::Get()->IsRunningInMash()) + return; + + const ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), + gfx::Point(), base::TimeTicks(), 0, 0); + + base::UserActionTester user_action_tester; + ButtonPressed(mouse_event); + EXPECT_EQ(1, + user_action_tester.GetActionCount("Launcher_ButtonPressed_Mouse")); +} + +// Verifies that a Launcher_ButtonPressed_Touch UMA user action is recorded when +// a button is pressed by a touch event. +TEST_F(ShelfButtonPressedMetricTrackerTest, + Launcher_ButtonPressed_MouseIsRecordedWhenIconActivatedByTouch) { + // TODO: investigate failure in mash. http://crbug.com/695565. + if (WmShell::Get()->IsRunningInMash()) + return; + + const ui::TouchEvent touch_event(ui::ET_GESTURE_TAP, gfx::Point(), 0, + base::TimeTicks()); + + base::UserActionTester user_action_tester; + ButtonPressed(touch_event); + EXPECT_EQ(1, + user_action_tester.GetActionCount("Launcher_ButtonPressed_Touch")); +} + +// Verifies that a Launcher_LaunchTask UMA user action is recorded when +// pressing a button causes a new window to be created. +TEST_F(ShelfButtonPressedMetricTrackerTest, + Launcher_LaunchTaskIsRecordedWhenNewWindowIsCreated) { + // TODO: investigate failure in mash. http://crbug.com/695565. + if (WmShell::Get()->IsRunningInMash()) + return; + + base::UserActionTester user_action_tester; + ButtonPressed(SHELF_ACTION_NEW_WINDOW_CREATED); + EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_LaunchTask")); +} + +// Verifies that a Launcher_MinimizeTask UMA user action is recorded when +// pressing a button causes an existing window to be minimized. +TEST_F(ShelfButtonPressedMetricTrackerTest, + Launcher_MinimizeTaskIsRecordedWhenWindowIsMinimized) { + // TODO: investigate failure in mash. http://crbug.com/695565. + if (WmShell::Get()->IsRunningInMash()) + return; + + base::UserActionTester user_action_tester; + ButtonPressed(SHELF_ACTION_WINDOW_MINIMIZED); + EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_MinimizeTask")); +} + +// Verifies that a Launcher_SwitchTask UMA user action is recorded when +// pressing a button causes an existing window to be activated. +TEST_F(ShelfButtonPressedMetricTrackerTest, + Launcher_SwitchTaskIsRecordedWhenExistingWindowIsActivated) { + // TODO: investigate failure in mash. http://crbug.com/695565. + if (WmShell::Get()->IsRunningInMash()) + return; + + base::UserActionTester user_action_tester; + ButtonPressed(SHELF_ACTION_WINDOW_ACTIVATED); + EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_SwitchTask")); +} + +// Verify that a window activation action will record a data point if it was +// subsequent to a minimize action. +TEST_F(ShelfButtonPressedMetricTrackerTest, + VerifyDataRecordedAfterMinimizedAndSubsequentActivatedAction) { + const DummyButton kDummyButton; + + base::HistogramTester histogram_tester; + + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); + histogram_tester.ExpectTotalCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0); + + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); + histogram_tester.ExpectTotalCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1); +} + +// Verify that a multiple window activation actions will record a single data +// point if they are subsequent to a minimize action. +TEST_F(ShelfButtonPressedMetricTrackerTest, + VerifyDataRecordedAfterMinimizedAndMultipleSubsequentActivatedActions) { + const DummyButton kDummyButton; + + base::HistogramTester histogram_tester; + + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); + + histogram_tester.ExpectTotalCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1); +} + +// Verify that a window activation action will not record a data point if it was +// not subsequent to a minimize action. +TEST_F(ShelfButtonPressedMetricTrackerTest, + VerifyDataRecordedAfterMinimizedAndNonSubsequentActivatedAction) { + const DummyButton kDummyButton; + + base::HistogramTester histogram_tester; + + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); + ButtonPressed(&kDummyButton, SHELF_ACTION_APP_LIST_SHOWN); + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); + + histogram_tester.ExpectTotalCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0); +} + +// Verify no data is recorded if a second source button is pressed in between +// subsequent minimized and activated actions on the same source. +TEST_F(ShelfButtonPressedMetricTrackerTest, + VerifyDataRecordedAfterMinimizedButtonA) { + const DummyButton kDummyButton; + const DummyButton kSecondDummyButton; + + base::HistogramTester histogram_tester; + + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); + ButtonPressed(&kSecondDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); + + histogram_tester.ExpectTotalCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0); +} + +// Verify the data value recorded when a window activation action is subsequent +// to a minimize action. +TEST_F(ShelfButtonPressedMetricTrackerTest, + VerifyTheValueRecordedBySubsequentMinimizedAndActivateActions) { + const int kTimeDeltaInMilliseconds = 17; + const DummyButton kDummyButton; + + base::HistogramTester histogram_tester; + + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); + tick_clock_->Advance( + base::TimeDelta::FromMilliseconds(kTimeDeltaInMilliseconds)); + ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); + + histogram_tester.ExpectTotalCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1); + histogram_tester.ExpectBucketCount( + kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, + kTimeDeltaInMilliseconds, 1); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/shelf/shelf_constants.cc b/ash/common/shelf/shelf_constants.cc new file mode 100644 index 0000000..80aafcd1 --- /dev/null +++ b/ash/common/shelf/shelf_constants.cc
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_constants.h" + +#include "base/logging.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace ash { + +const int kTimeToSwitchBackgroundMs = 1000; +const int kWorkspaceAreaVisibleInset = 2; +const int kWorkspaceAreaAutoHideInset = 5; +const int kShelfAutoHideSize = 3; +const SkColor kShelfDefaultBaseColor = SK_ColorBLACK; +const int kShelfButtonSize = 48; +const int kShelfButtonSpacing = 16; +const SkColor kShelfButtonActivatedHighlightColor = + SkColorSetA(SK_ColorWHITE, 100); +const SkColor kShelfInkDropBaseColor = SK_ColorWHITE; +const float kShelfInkDropVisibleOpacity = 0.2f; +const SkColor kShelfIconColor = SK_ColorWHITE; +const int kShelfTranslucentAlpha = 153; +const int kOverflowButtonSize = 32; +const int kOverflowButtonCornerRadius = 2; +const int kAppListButtonRadius = kOverflowButtonSize / 2; + +int GetShelfConstant(ShelfConstant shelf_constant) { + const int kShelfSize[] = {47, 48, 48}; + const int kShelfInsetsForAutoHide[] = {3, 0, 0}; + + // TODO(estade): clean this up --- remove unneeded constants and reduce + // remaining arrays to a single constant. + const int mode = 1; + switch (shelf_constant) { + case SHELF_SIZE: + return kShelfSize[mode]; + case SHELF_INSETS_FOR_AUTO_HIDE: + return kShelfInsetsForAutoHide[mode]; + } + NOTREACHED(); + return 0; +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_constants.h b/ash/common/shelf/shelf_constants.h new file mode 100644 index 0000000..bc783fe --- /dev/null +++ b/ash/common/shelf/shelf_constants.h
@@ -0,0 +1,82 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_CONSTANTS_H_ +#define ASH_COMMON_SHELF_SHELF_CONSTANTS_H_ + +#include "ash/ash_export.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace ash { + +enum ShelfConstant { + // Size of the shelf when visible (height when the shelf is horizontal and + // width when the shelf is vertical). + SHELF_SIZE, + + // Insets allocated for shelf when it is auto hidden. + SHELF_INSETS_FOR_AUTO_HIDE +}; + +// We reserve a small area on the edge of the workspace area to ensure that +// the resize handle at the edge of the window can be hit. +extern const int kWorkspaceAreaVisibleInset; + +// When autohidden we extend the touch hit target onto the screen so that the +// user can drag the shelf out. +extern const int kWorkspaceAreaAutoHideInset; + +// Size of the shelf when auto-hidden. +ASH_EXPORT extern const int kShelfAutoHideSize; + +// Animation duration for switching black shelf and dock background on and off. +ASH_EXPORT extern const int kTimeToSwitchBackgroundMs; + +// The default base color of the shelf to which different alpha values are +// applied based on the desired shelf opacity level. +ASH_EXPORT extern const SkColor kShelfDefaultBaseColor; + +// Size allocated for each app button on the shelf. +ASH_EXPORT extern const int kShelfButtonSize; + +// Size of the space between buttons on the shelf. +ASH_EXPORT extern const int kShelfButtonSpacing; + +// Highlight color used for shelf button activated states. +// TODO(bruthig|mohsen): Use of this color is temporary. Draw the active state +// using the material design ripple animation. +ASH_EXPORT extern const SkColor kShelfButtonActivatedHighlightColor; + +// Ink drop color for shelf items. +extern const SkColor kShelfInkDropBaseColor; + +// Opacity of the ink drop ripple for shelf items when the ripple is visible. +extern const float kShelfInkDropVisibleOpacity; + +// The foreground color of the icons used in the shelf (launcher, +// notifications, etc). +ASH_EXPORT extern const SkColor kShelfIconColor; + +// The alpha value for the shelf background when a window is overlapping. +ASH_EXPORT extern const int kShelfTranslucentAlpha; + +// The width and height of the material design overflow button. +// TODO(tdanderson): Refactor constants which are common between the shelf +// and the tray. See crbug.com/623987. +extern const int kOverflowButtonSize; + +// The radius of the rounded corners of the overflow button. +extern const int kOverflowButtonCornerRadius; + +// The radius of the circular material design app list button. +extern const int kAppListButtonRadius; + +// The direction of the focus cycling. +enum CycleDirection { CYCLE_FORWARD, CYCLE_BACKWARD }; + +ASH_EXPORT int GetShelfConstant(ShelfConstant shelf_constant); + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_CONSTANTS_H_
diff --git a/ash/common/shelf/shelf_controller.cc b/ash/common/shelf/shelf_controller.cc new file mode 100644 index 0000000..5bfece4 --- /dev/null +++ b/ash/common/shelf/shelf_controller.cc
@@ -0,0 +1,244 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_controller.h" + +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/resources/grit/ui_resources.h" + +namespace ash { + +namespace { + +// A ShelfItemDelegate used for pinned items in mash. +// TODO(mash): Support open windows, cooperate with ShelfWindowWatcher. +class ShelfItemDelegateMus : public ShelfItemDelegate { + public: + ShelfItemDelegateMus() {} + ~ShelfItemDelegateMus() override {} + + void SetDelegate(mojom::ShelfItemDelegateAssociatedPtrInfo delegate) { + delegate_.Bind(std::move(delegate)); + } + + bool pinned() const { return pinned_; } + void set_pinned(bool pinned) { pinned_ = pinned; } + + void AddWindow(uint32_t id, const base::string16& title) { + DCHECK(!window_id_to_title_.count(id)); + window_id_to_title_.insert(std::make_pair(id, title)); + } + void RemoveWindow(uint32_t id) { window_id_to_title_.erase(id); } + void SetWindowTitle(uint32_t id, const base::string16& title) { + DCHECK(window_id_to_title_.count(id)); + window_id_to_title_[id] = title; + } + const std::map<uint32_t, base::string16>& window_id_to_title() const { + return window_id_to_title_; + } + + const base::string16& title() { return title_; } + void set_title(const base::string16& title) { title_ = title; } + + private: + // ShelfItemDelegate: + ShelfAction ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) override { + if (window_id_to_title_.empty()) { + delegate_->LaunchItem(); + return SHELF_ACTION_NEW_WINDOW_CREATED; + } + if (window_id_to_title_.size() == 1) { + // TODO(mash): Activate the window and return + // SHELF_ACTION_WINDOW_ACTIVATED. + NOTIMPLEMENTED(); + } + return SHELF_ACTION_NONE; + } + + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override { + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); + } + + void ExecuteCommand(uint32_t command_id, int event_flags) override { + // This delegate does not support showing an application menu. + NOTIMPLEMENTED(); + } + + void Close() override { NOTIMPLEMENTED(); } + + mojom::ShelfItemDelegateAssociatedPtr delegate_; + bool pinned_ = false; + std::map<uint32_t, base::string16> window_id_to_title_; + base::string16 title_; + + DISALLOW_COPY_AND_ASSIGN(ShelfItemDelegateMus); +}; + +// Returns the ShelfItemDelegateMus instance for the given |shelf_id|. +ShelfItemDelegateMus* GetShelfItemDelegate(ShelfID shelf_id) { + return static_cast<ShelfItemDelegateMus*>( + WmShell::Get()->shelf_model()->GetShelfItemDelegate(shelf_id)); +} + +// Returns an icon image from an SkBitmap, or the default shelf icon image if +// the bitmap is empty. Assumes the bitmap is a 1x icon. +// TODO(jamescook): Support other scale factors. +gfx::ImageSkia GetShelfIconFromBitmap(const SkBitmap& bitmap) { + gfx::ImageSkia icon_image; + if (!bitmap.isNull()) { + icon_image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + } else { + // Use default icon. + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + icon_image = *rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON); + } + return icon_image; +} + +// Returns the WmShelf instance for the display with the given |display_id|. +WmShelf* GetShelfForDisplay(int64_t display_id) { + // The controller may be null for invalid ids or for displays being removed. + RootWindowController* root_window_controller = + Shell::GetRootWindowControllerWithDisplayId(display_id); + return root_window_controller ? root_window_controller->GetShelf() : nullptr; +} + +} // namespace + +ShelfController::ShelfController() {} + +ShelfController::~ShelfController() {} + +void ShelfController::BindRequest(mojom::ShelfControllerRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void ShelfController::NotifyShelfCreated(WmShelf* shelf) { + // Notify observers, Chrome will set alignment and auto-hide from prefs. + int64_t display_id = shelf->GetWindow()->GetDisplayNearestWindow().id(); + observers_.ForAllPtrs([display_id](mojom::ShelfObserver* observer) { + observer->OnShelfCreated(display_id); + }); +} + +void ShelfController::NotifyShelfAlignmentChanged(WmShelf* shelf) { + ShelfAlignment alignment = shelf->alignment(); + int64_t display_id = shelf->GetWindow()->GetDisplayNearestWindow().id(); + observers_.ForAllPtrs( + [alignment, display_id](mojom::ShelfObserver* observer) { + observer->OnAlignmentChanged(alignment, display_id); + }); +} + +void ShelfController::NotifyShelfAutoHideBehaviorChanged(WmShelf* shelf) { + ShelfAutoHideBehavior behavior = shelf->auto_hide_behavior(); + int64_t display_id = shelf->GetWindow()->GetDisplayNearestWindow().id(); + observers_.ForAllPtrs([behavior, display_id](mojom::ShelfObserver* observer) { + observer->OnAutoHideBehaviorChanged(behavior, display_id); + }); +} + +void ShelfController::AddObserver( + mojom::ShelfObserverAssociatedPtrInfo observer) { + mojom::ShelfObserverAssociatedPtr observer_ptr; + observer_ptr.Bind(std::move(observer)); + observers_.AddPtr(std::move(observer_ptr)); +} + +void ShelfController::SetAlignment(ShelfAlignment alignment, + int64_t display_id) { + if (!ash::WmShelf::CanChangeShelfAlignment()) + return; + + WmShelf* shelf = GetShelfForDisplay(display_id); + // TODO(jamescook): The initialization check should not be necessary, but + // otherwise this wrongly tries to set the alignment on a secondary display + // during login before the ShelfLockingManager and ShelfView are created. + if (shelf && shelf->IsShelfInitialized()) + shelf->SetAlignment(alignment); +} + +void ShelfController::SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide, + int64_t display_id) { + WmShelf* shelf = GetShelfForDisplay(display_id); + // TODO(jamescook): The initialization check should not be necessary, but + // otherwise this wrongly tries to set auto-hide state on a secondary display + // during login before the ShelfView is created. + if (shelf && shelf->IsShelfInitialized()) + shelf->SetAutoHideBehavior(auto_hide); +} + +void ShelfController::PinItem( + mojom::ShelfItemPtr item, + mojom::ShelfItemDelegateAssociatedPtrInfo delegate) { + if (app_id_to_shelf_id_.count(item->app_id)) { + ShelfID shelf_id = app_id_to_shelf_id_[item->app_id]; + ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); + item_delegate->SetDelegate(std::move(delegate)); + item_delegate->set_pinned(true); + return; + } + + ShelfID shelf_id = model_.next_id(); + app_id_to_shelf_id_.insert(std::make_pair(item->app_id, shelf_id)); + shelf_id_to_app_id_.insert(std::make_pair(shelf_id, item->app_id)); + + ShelfItem shelf_item; + shelf_item.type = TYPE_APP_SHORTCUT; + shelf_item.status = STATUS_CLOSED; + shelf_item.image = GetShelfIconFromBitmap(item->image); + shelf_item.title = base::UTF8ToUTF16(item->app_title); + model_.Add(shelf_item); + + std::unique_ptr<ShelfItemDelegateMus> item_delegate = + base::MakeUnique<ShelfItemDelegateMus>(); + item_delegate->SetDelegate(std::move(delegate)); + item_delegate->set_pinned(true); + item_delegate->set_title(shelf_item.title); + model_.SetShelfItemDelegate(shelf_id, std::move(item_delegate)); +} + +void ShelfController::UnpinItem(const std::string& app_id) { + if (!app_id_to_shelf_id_.count(app_id)) + return; + + ShelfID shelf_id = app_id_to_shelf_id_[app_id]; + ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); + DCHECK(item_delegate->pinned()); + item_delegate->set_pinned(false); + if (item_delegate->window_id_to_title().empty()) { + model_.RemoveItemAt(model_.ItemIndexByID(shelf_id)); + app_id_to_shelf_id_.erase(app_id); + shelf_id_to_app_id_.erase(shelf_id); + } +} + +void ShelfController::SetItemImage(const std::string& app_id, + const SkBitmap& image) { + if (!app_id_to_shelf_id_.count(app_id)) + return; + ShelfID shelf_id = app_id_to_shelf_id_[app_id]; + int index = model_.ItemIndexByID(shelf_id); + DCHECK_GE(index, 0); + ShelfItem item = *model_.ItemByID(shelf_id); + item.image = GetShelfIconFromBitmap(image); + model_.Set(index, item); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_controller.h b/ash/common/shelf/shelf_controller.h new file mode 100644 index 0000000..b058d4f --- /dev/null +++ b/ash/common/shelf/shelf_controller.h
@@ -0,0 +1,76 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_CONTROLLER_H_ +#define ASH_COMMON_SHELF_SHELF_CONTROLLER_H_ + +#include <map> +#include <string> + +#include "ash/common/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/public/interfaces/shelf.mojom.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/interface_ptr_set.h" + +namespace ash { + +class WmShelf; + +// Ash's implementation of the mojom::ShelfController interface. Chrome connects +// to this interface to observe and manage the per-display ash shelf instances. +class ShelfController : public mojom::ShelfController { + public: + ShelfController(); + ~ShelfController() override; + + // Binds the mojom::ShelfController interface request to this object. + void BindRequest(mojom::ShelfControllerRequest request); + + ShelfModel* model() { return &model_; } + + const std::map<std::string, ShelfID>& app_id_to_shelf_id() { + return app_id_to_shelf_id_; + } + + const std::map<ShelfID, std::string>& shelf_id_to_app_id() { + return shelf_id_to_app_id_; + } + + // Functions used to notify mojom::ShelfObserver instances of changes. + void NotifyShelfCreated(WmShelf* shelf); + void NotifyShelfAlignmentChanged(WmShelf* shelf); + void NotifyShelfAutoHideBehaviorChanged(WmShelf* shelf); + + // mojom::Shelf: + void AddObserver(mojom::ShelfObserverAssociatedPtrInfo observer) override; + void SetAlignment(ShelfAlignment alignment, int64_t display_id) override; + void SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide, + int64_t display_id) override; + void PinItem(mojom::ShelfItemPtr item, + mojom::ShelfItemDelegateAssociatedPtrInfo delegate) override; + void UnpinItem(const std::string& app_id) override; + void SetItemImage(const std::string& app_id, const SkBitmap& image) override; + + private: + // The shelf model shared by all shelf instances. + ShelfModel model_; + + // Bindings for the ShelfController interface. + mojo::BindingSet<mojom::ShelfController> bindings_; + + // The set of shelf observers notified about shelf state and settings changes. + mojo::AssociatedInterfacePtrSet<mojom::ShelfObserver> observers_; + + // Mappings between application and shelf ids. + std::map<std::string, ShelfID> app_id_to_shelf_id_; + std::map<ShelfID, std::string> shelf_id_to_app_id_; + + DISALLOW_COPY_AND_ASSIGN(ShelfController); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_CONTROLLER_H_
diff --git a/ash/common/shelf/shelf_delegate.h b/ash/common/shelf/shelf_delegate.h new file mode 100644 index 0000000..8f83b16 --- /dev/null +++ b/ash/common/shelf/shelf_delegate.h
@@ -0,0 +1,55 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_DELEGATE_H_ +#define ASH_COMMON_SHELF_SHELF_DELEGATE_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_item_types.h" + +namespace ash { + +// Delegate shared by all shelf instances. +class ASH_EXPORT ShelfDelegate { + public: + virtual ~ShelfDelegate() {} + + // Get the shelf ID from an application ID. + virtual ShelfID GetShelfIDForAppID(const std::string& app_id) = 0; + + // Get the shelf ID from an application ID and a launch ID. + // The launch ID can be passed to an app when launched in order to support + // multiple shelf items per app. This id is used together with the app_id to + // uniquely identify each shelf item that has the same app_id. + // For example, a single virtualization app might want to show different + // shelf icons for different remote apps. + virtual ShelfID GetShelfIDForAppIDAndLaunchID( + const std::string& app_id, + const std::string& launch_id) = 0; + + // Checks whether a mapping exists from the ShelfID |id| to an app id. + virtual bool HasShelfIDToAppIDMapping(ShelfID id) const = 0; + + // Get the application ID for a given shelf ID. + // |HasShelfIDToAppIDMapping(ShelfID)| should be called first to ensure the + // ShelfID can be successfully mapped to an app id. + virtual const std::string& GetAppIDForShelfID(ShelfID id) = 0; + + // Pins an app with |app_id| to shelf. A running instance will get pinned. + // In case there is no running instance a new shelf item is created and + // pinned. + virtual void PinAppWithID(const std::string& app_id) = 0; + + // Check if the app with |app_id_| is pinned to the shelf. + virtual bool IsAppPinned(const std::string& app_id) = 0; + + // Unpins app item with |app_id|. + virtual void UnpinAppWithID(const std::string& app_id) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_DELEGATE_H_
diff --git a/ash/common/shelf/shelf_item_delegate.cc b/ash/common/shelf/shelf_item_delegate.cc new file mode 100644 index 0000000..bc3ec8c3 --- /dev/null +++ b/ash/common/shelf/shelf_item_delegate.cc
@@ -0,0 +1,19 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_item_delegate.h" + +#include "ui/display/types/display_constants.h" + +namespace ash { + +ShelfItemDelegate::ShelfItemDelegate() {} +ShelfItemDelegate::~ShelfItemDelegate() {} + +ShelfAction ShelfItemDelegate::ItemSelectedBySource(ShelfLaunchSource source) { + return ItemSelected(ui::ET_UNKNOWN, ui::EF_NONE, display::kInvalidDisplayId, + source); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_item_delegate.h b/ash/common/shelf/shelf_item_delegate.h new file mode 100644 index 0000000..8ff4aed --- /dev/null +++ b/ash/common/shelf/shelf_item_delegate.h
@@ -0,0 +1,51 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_ITEM_DELEGATE_H_ +#define ASH_COMMON_SHELF_SHELF_ITEM_DELEGATE_H_ + +#include <stdint.h> + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_application_menu_item.h" +#include "ash/public/cpp/shelf_types.h" +#include "ui/events/event_constants.h" + +namespace ash { + +// Delegate for the ShelfItem. +class ASH_EXPORT ShelfItemDelegate { + public: + ShelfItemDelegate(); + virtual ~ShelfItemDelegate(); + + // Called when the user selects a shelf item. The event type and flags, the + // relevant display id, and the source of the selection should be provided if + // they are known to the caller; as some subclasses use these arguments. + // Defaults: (ET_UNKNOWN, EF_NONE, kInvalidDisplayId, LAUNCH_FROM_UNKNOWN) + // Returns the action performed by selecting the item. + virtual ShelfAction ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) = 0; + + // A helper to call ItemSelected with a source and default arguments. + ShelfAction ItemSelectedBySource(ShelfLaunchSource source); + + // Returns any application menu items that should appear for this shelf item. + // |event_flags| specifies the flags of the event which triggered this menu. + virtual ShelfAppMenuItemList GetAppMenuItems(int event_flags) = 0; + + // Called on invocation of a shelf item's application menu command. + virtual void ExecuteCommand(uint32_t command_id, int event_flags) = 0; + + // Closes all windows associated with this item. + virtual void Close() = 0; + + DISALLOW_COPY_AND_ASSIGN(ShelfItemDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/common/shelf/shelf_item_types.cc b/ash/common/shelf/shelf_item_types.cc new file mode 100644 index 0000000..36baad1 --- /dev/null +++ b/ash/common/shelf/shelf_item_types.cc
@@ -0,0 +1,13 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_item_types.h" + +namespace ash { + +ShelfItem::ShelfItem() {} +ShelfItem::ShelfItem(const ShelfItem& shelf_item) = default; +ShelfItem::~ShelfItem() {} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_item_types.h b/ash/common/shelf/shelf_item_types.h new file mode 100644 index 0000000..62d279eb --- /dev/null +++ b/ash/common/shelf/shelf_item_types.h
@@ -0,0 +1,53 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_ITEM_TYPES_H_ +#define ASH_COMMON_SHELF_SHELF_ITEM_TYPES_H_ + +// TODO(msw): Rename these files to shelf_item.*; audit users. + +#include <string> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/strings/string16.h" +#include "ui/gfx/image/image_skia.h" + +namespace ash { + +struct ASH_EXPORT ShelfItem { + ShelfItem(); + ShelfItem(const ShelfItem& shelf_item); + ~ShelfItem(); + + ShelfItemType type = TYPE_UNDEFINED; + + // Image to display in the shelf. + gfx::ImageSkia image; + + // Assigned by the model when the item is added. + ShelfID id = kInvalidShelfID; + + // Running status. + ShelfItemStatus status = STATUS_CLOSED; + + // The application id for this shelf item; only populated for some items. + std::string app_id; + + // The title to display for tooltips, etc. + base::string16 title; + + // Whether the tooltip should be shown on hover; generally true. + bool shows_tooltip = true; + + // Whether the item is pinned by a policy preference (ie. user cannot un-pin). + bool pinned_by_policy = false; +}; + +typedef std::vector<ShelfItem> ShelfItems; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_ITEM_TYPES_H_
diff --git a/ash/common/shelf/shelf_layout_manager.cc b/ash/common/shelf/shelf_layout_manager.cc new file mode 100644 index 0000000..f4ce3aea --- /dev/null +++ b/ash/common/shelf/shelf_layout_manager.cc
@@ -0,0 +1,1143 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_layout_manager.h" + +#include <algorithm> +#include <cmath> +#include <vector> + +#include "ash/animation/animation_change_type.h" +#include "ash/common/session/session_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_layout_manager_observer.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/wm/fullscreen_window_finder.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/auto_reset.h" +#include "base/command_line.h" +#include "base/i18n/rtl.h" +#include "ui/base/ui_base_switches.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/layer_animator.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/events/event.h" +#include "ui/events/event_handler.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_util.h" +#include "ui/views/border.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +// Delay before showing the shelf. This is after the mouse stops moving. +const int kAutoHideDelayMS = 200; + +// Duration of the animation to show or hide the shelf. +const int kAnimationDurationMS = 200; + +// To avoid hiding the shelf when the mouse transitions from a message bubble +// into the shelf, the hit test area is enlarged by this amount of pixels to +// keep the shelf from hiding. +const int kNotificationBubbleGapHeight = 6; + +// The maximum size of the region on the display opposing the shelf managed by +// this ShelfLayoutManager which can trigger showing the shelf. +// For instance: +// - Primary display is left of secondary display. +// - Shelf is left aligned +// - This ShelfLayoutManager manages the shelf for the secondary display. +// |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region +// from the right edge of the primary display which can trigger showing the +// auto hidden shelf. The region is used to make it easier to trigger showing +// the auto hidden shelf when the shelf is on the boundary between displays. +const int kMaxAutoHideShowShelfRegionSize = 10; + +ui::Layer* GetLayer(views::Widget* widget) { + return widget->GetNativeView()->layer(); +} + +// Returns true if the window is in the app list window container. +bool IsAppListWindow(WmWindow* window) { + return window->GetParent() && + window->GetParent()->GetShellWindowId() == + kShellWindowId_AppListContainer; +} + +} // namespace + +// ShelfLayoutManager::UpdateShelfObserver ------------------------------------- + +// UpdateShelfObserver is used to delay updating the background until the +// animation completes. +class ShelfLayoutManager::UpdateShelfObserver + : public ui::ImplicitAnimationObserver { + public: + explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) { + shelf_->update_shelf_observer_ = this; + } + + void Detach() { shelf_ = NULL; } + + void OnImplicitAnimationsCompleted() override { + if (shelf_) + shelf_->MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); + delete this; + } + + private: + ~UpdateShelfObserver() override { + if (shelf_) + shelf_->update_shelf_observer_ = NULL; + } + + // Shelf we're in. NULL if deleted before we're deleted. + ShelfLayoutManager* shelf_; + + DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver); +}; + +ShelfLayoutManager::State::State() + : visibility_state(SHELF_VISIBLE), + auto_hide_state(SHELF_AUTO_HIDE_HIDDEN), + window_state(wm::WORKSPACE_WINDOW_STATE_DEFAULT), + pre_lock_screen_animation_active(false), + session_state(session_manager::SessionState::UNKNOWN) {} + +bool ShelfLayoutManager::State::IsAddingSecondaryUser() const { + return session_state == session_manager::SessionState::LOGIN_SECONDARY; +} + +bool ShelfLayoutManager::State::IsScreenLocked() const { + return session_state == session_manager::SessionState::LOCKED; +} + +bool ShelfLayoutManager::State::Equals(const State& other) const { + return other.visibility_state == visibility_state && + (visibility_state != SHELF_AUTO_HIDE || + other.auto_hide_state == auto_hide_state) && + other.window_state == window_state && + other.pre_lock_screen_animation_active == + pre_lock_screen_animation_active && + other.session_state == session_state; +} + +// ShelfLayoutManager ---------------------------------------------------------- + +ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf_widget, + WmShelf* wm_shelf) + : updating_bounds_(false), + shelf_widget_(shelf_widget), + wm_shelf_(wm_shelf), + window_overlaps_shelf_(false), + mouse_over_shelf_when_auto_hide_timer_started_(false), + gesture_drag_status_(GESTURE_DRAG_NONE), + gesture_drag_amount_(0.f), + gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN), + update_shelf_observer_(NULL), + chromevox_panel_height_(0), + duration_override_in_ms_(0), + shelf_background_type_(SHELF_BACKGROUND_OVERLAP) { + DCHECK(shelf_widget_); + DCHECK(wm_shelf_); + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->AddLockStateObserver(this); + WmShell::Get()->AddActivationObserver(this); + WmShell::Get()->session_controller()->AddSessionStateObserver(this); + state_.session_state = + WmShell::Get()->session_controller()->GetSessionState(); +} + +ShelfLayoutManager::~ShelfLayoutManager() { + if (update_shelf_observer_) + update_shelf_observer_->Detach(); + + for (auto& observer : observers_) + observer.WillDeleteShelfLayoutManager(); + WmShell::Get()->RemoveShellObserver(this); + WmShell::Get()->RemoveLockStateObserver(this); + WmShell::Get()->session_controller()->RemoveSessionStateObserver(this); +} + +void ShelfLayoutManager::PrepareForShutdown() { + in_shutdown_ = true; + // Stop observing changes to avoid updating a partially destructed shelf. + WmShell::Get()->RemoveActivationObserver(this); +} + +bool ShelfLayoutManager::IsVisible() const { + // status_area_widget() may be NULL during the shutdown. + return shelf_widget_->status_area_widget() && + shelf_widget_->status_area_widget()->IsVisible() && + (state_.visibility_state == SHELF_VISIBLE || + (state_.visibility_state == SHELF_AUTO_HIDE && + state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN)); +} + +gfx::Rect ShelfLayoutManager::GetIdealBounds() { + const int shelf_size = GetShelfConstant(SHELF_SIZE); + WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + gfx::Rect rect(wm::GetDisplayBoundsInParent(shelf_window)); + return SelectValueForShelfAlignment( + gfx::Rect(rect.x(), rect.bottom() - shelf_size, rect.width(), shelf_size), + gfx::Rect(rect.x(), rect.y(), shelf_size, rect.height()), + gfx::Rect(rect.right() - shelf_size, rect.y(), shelf_size, + rect.height())); +} + +gfx::Size ShelfLayoutManager::GetPreferredSize() { + TargetBounds target_bounds; + CalculateTargetBounds(state_, &target_bounds); + return target_bounds.shelf_bounds_in_root.size(); +} + +void ShelfLayoutManager::LayoutShelfAndUpdateBounds(bool change_work_area) { + TargetBounds target_bounds; + CalculateTargetBounds(state_, &target_bounds); + UpdateBoundsAndOpacity(target_bounds, false, change_work_area, NULL); + + // Update insets in ShelfWindowTargeter when shelf bounds change. + for (auto& observer : observers_) + observer.WillChangeVisibilityState(visibility_state()); +} + +void ShelfLayoutManager::LayoutShelf() { + LayoutShelfAndUpdateBounds(true); +} + +ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() { + switch (wm_shelf_->auto_hide_behavior()) { + case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS: + return SHELF_AUTO_HIDE; + case SHELF_AUTO_HIDE_BEHAVIOR_NEVER: + return SHELF_VISIBLE; + case SHELF_AUTO_HIDE_ALWAYS_HIDDEN: + return SHELF_HIDDEN; + } + return SHELF_VISIBLE; +} + +void ShelfLayoutManager::UpdateVisibilityState() { + // Bail out early before the shelf is initialized or after it is destroyed. + WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + if (in_shutdown_ || !wm_shelf_->IsShelfInitialized() || !shelf_window) + return; + if (state_.IsScreenLocked() || state_.IsAddingSecondaryUser()) { + SetState(SHELF_VISIBLE); + } else if (WmShell::Get()->IsPinned()) { + SetState(SHELF_HIDDEN); + } else { + // TODO(zelidrag): Verify shelf drag animation still shows on the device + // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN. + wm::WorkspaceWindowState window_state( + shelf_window->GetRootWindowController()->GetWorkspaceWindowState()); + switch (window_state) { + case wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN: { + if (IsShelfHiddenForFullscreen()) { + SetState(SHELF_HIDDEN); + } else { + // The shelf is sometimes not hidden when in immersive fullscreen. + // Force the shelf to be auto hidden in this case. + SetState(SHELF_AUTO_HIDE); + } + break; + } + case wm::WORKSPACE_WINDOW_STATE_MAXIMIZED: + SetState(CalculateShelfVisibility()); + break; + + case wm::WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF: + case wm::WORKSPACE_WINDOW_STATE_DEFAULT: + SetState(CalculateShelfVisibility()); + SetWindowOverlapsShelf( + window_state == wm::WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF); + break; + } + } +} + +void ShelfLayoutManager::UpdateAutoHideState() { + ShelfAutoHideState auto_hide_state = + CalculateAutoHideState(state_.visibility_state); + if (auto_hide_state != state_.auto_hide_state) { + if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) { + // Hides happen immediately. + SetState(state_.visibility_state); + } else { + if (!auto_hide_timer_.IsRunning()) { + mouse_over_shelf_when_auto_hide_timer_started_ = + shelf_widget_->GetWindowBoundsInScreen().Contains( + display::Screen::GetScreen()->GetCursorScreenPoint()); + } + auto_hide_timer_.Start( + FROM_HERE, base::TimeDelta::FromMilliseconds(kAutoHideDelayMS), this, + &ShelfLayoutManager::UpdateAutoHideStateNow); + } + } else { + StopAutoHideTimer(); + } +} + +void ShelfLayoutManager::UpdateAutoHideForMouseEvent(ui::MouseEvent* event, + WmWindow* target) { + // This also checks IsShelfWindow() to make sure we don't attempt to hide the + // shelf if the mouse down occurs on the shelf. + in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED || + (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED && + event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) && + !IsShelfWindow(target); + + // Don't update during shutdown because synthetic mouse events (e.g. mouse + // exit) may be generated during status area widget teardown. + if (visibility_state() != SHELF_AUTO_HIDE || in_shutdown_) + return; + + if (event->type() == ui::ET_MOUSE_MOVED || + event->type() == ui::ET_MOUSE_ENTERED || + event->type() == ui::ET_MOUSE_EXITED) { + UpdateAutoHideState(); + } +} + +void ShelfLayoutManager::UpdateAutoHideForGestureEvent(ui::GestureEvent* event, + WmWindow* target) { + if (visibility_state() != SHELF_AUTO_HIDE || in_shutdown_) + return; + + if (IsShelfWindow(target) && ProcessGestureEvent(*event)) + event->StopPropagation(); +} + +void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) { + window_overlaps_shelf_ = value; + MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); +} + +void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) { + observers_.AddObserver(observer); +} + +void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) { + observers_.RemoveObserver(observer); +} + +bool ShelfLayoutManager::ProcessGestureEvent(const ui::GestureEvent& event) { + // The gestures are disabled in the lock/login screen. + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + if (!delegate->NumberOfLoggedInUsers() || delegate->IsScreenLocked()) + return false; + + if (IsShelfHiddenForFullscreen()) + return false; + + if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) { + StartGestureDrag(event); + return true; + } + + if (gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) + return false; + + if (event.type() == ui::ET_GESTURE_SCROLL_UPDATE) { + UpdateGestureDrag(event); + return true; + } + + if (event.type() == ui::ET_GESTURE_SCROLL_END || + event.type() == ui::ET_SCROLL_FLING_START) { + CompleteGestureDrag(event); + return true; + } + + // Unexpected event. Reset the state and let the event fall through. + CancelGestureDrag(); + return false; +} + +void ShelfLayoutManager::SetAnimationDurationOverride( + int duration_override_in_ms) { + duration_override_in_ms_ = duration_override_in_ms; +} + +//////////////////////////////////////////////////////////////////////////////// +// ShelfLayoutManager, wm::WmSnapToPixelLayoutManager implementation: + +void ShelfLayoutManager::OnWindowResized() { + LayoutShelf(); +} + +void ShelfLayoutManager::SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) { + wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); + // We may contain other widgets (such as frame maximize bubble) but they don't + // effect the layout in anyway. + if (!updating_bounds_ && + ((WmWindow::Get(shelf_widget_->GetNativeWindow()) == child) || + (WmWindow::Get(shelf_widget_->status_area_widget()->GetNativeWindow()) == + child))) { + LayoutShelf(); + } +} + +void ShelfLayoutManager::OnShelfAutoHideBehaviorChanged(WmWindow* root_window) { + UpdateVisibilityState(); +} + +void ShelfLayoutManager::OnPinnedStateChanged(WmWindow* pinned_window) { + // Shelf needs to be hidden on entering to pinned mode, or restored + // on exiting from pinned mode. + UpdateVisibilityState(); +} + +void ShelfLayoutManager::OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) { + UpdateAutoHideStateNow(); +} + +void ShelfLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) { + bool keyboard_is_about_to_hide = false; + if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) + keyboard_is_about_to_hide = true; + // If new window behavior flag enabled and in non-sticky mode, do not change + // the work area. + bool change_work_area = + (!base::CommandLine::ForCurrentProcess()->HasSwitch( + ::switches::kUseNewVirtualKeyboardBehavior) || + keyboard::KeyboardController::GetInstance()->keyboard_locked()); + + keyboard_bounds_ = new_bounds; + LayoutShelfAndUpdateBounds(change_work_area); + + // On login screen if keyboard has been just hidden, update bounds just once + // but ignore target_bounds.work_area_insets since shelf overlaps with login + // window. + if (WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked() && + keyboard_is_about_to_hide) { + WmWindow* window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets()); + } +} + +void ShelfLayoutManager::OnKeyboardClosed() {} + +ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const { + if (state_.pre_lock_screen_animation_active) + return SHELF_BACKGROUND_DEFAULT; + + // Handle all non active screen states, including OOBE and pre-login. + if (state_.session_state != session_manager::SessionState::ACTIVE) + return SHELF_BACKGROUND_OVERLAP; + + if (state_.visibility_state != SHELF_AUTO_HIDE && + state_.window_state == wm::WORKSPACE_WINDOW_STATE_MAXIMIZED) { + return SHELF_BACKGROUND_MAXIMIZED; + } + + if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS || + window_overlaps_shelf_ || state_.visibility_state == SHELF_AUTO_HIDE) { + return SHELF_BACKGROUND_OVERLAP; + } + + return SHELF_BACKGROUND_DEFAULT; +} + +void ShelfLayoutManager::SetChromeVoxPanelHeight(int height) { + chromevox_panel_height_ = height; + LayoutShelf(); +} + +//////////////////////////////////////////////////////////////////////////////// +// ShelfLayoutManager, private: + +ShelfLayoutManager::TargetBounds::TargetBounds() + : opacity(0.0f), status_opacity(0.0f) {} + +ShelfLayoutManager::TargetBounds::~TargetBounds() {} + +void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) { + State state; + state.visibility_state = visibility_state; + state.auto_hide_state = CalculateAutoHideState(visibility_state); + + WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + RootWindowController* controller = shelf_window->GetRootWindowController(); + state.window_state = controller ? controller->GetWorkspaceWindowState() + : wm::WORKSPACE_WINDOW_STATE_DEFAULT; + // Preserve the log in screen states. + state.session_state = state_.session_state; + state.pre_lock_screen_animation_active = + state_.pre_lock_screen_animation_active; + + // Force an update because gesture drags affect the shelf bounds and we + // should animate back to the normal bounds at the end of a gesture. + bool force_update = + (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS || + gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS); + + if (!force_update && state_.Equals(state)) + return; // Nothing changed. + + for (auto& observer : observers_) + observer.WillChangeVisibilityState(visibility_state); + + StopAutoHideTimer(); + + State old_state = state_; + state_ = state; + + AnimationChangeType change_type = AnimationChangeType::ANIMATE; + bool delay_background_change = false; + + // Do not animate the background when: + // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf + // in maximized mode. + // - Going from an auto hidden shelf in maximized mode to a visible shelf in + // maximized mode. + if (state.visibility_state == SHELF_VISIBLE && + state.window_state == wm::WORKSPACE_WINDOW_STATE_MAXIMIZED && + old_state.visibility_state != SHELF_VISIBLE) { + change_type = AnimationChangeType::IMMEDIATE; + } else { + // Delay the animation when the shelf was hidden, and has just been made + // visible (e.g. using a gesture-drag). + if (state.visibility_state == SHELF_VISIBLE && + old_state.visibility_state == SHELF_AUTO_HIDE && + old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) { + delay_background_change = true; + } + } + + if (delay_background_change) { + if (update_shelf_observer_) + update_shelf_observer_->Detach(); + // |update_shelf_observer_| deletes itself when the animation is done. + update_shelf_observer_ = new UpdateShelfObserver(this); + } else { + MaybeUpdateShelfBackground(change_type); + } + + TargetBounds target_bounds; + CalculateTargetBounds(state_, &target_bounds); + UpdateBoundsAndOpacity( + target_bounds, true /* animate */, true /* change_work_area */, + delay_background_change ? update_shelf_observer_ : NULL); + + // OnAutoHideStateChanged Should be emitted when: + // - firstly state changed to auto-hide from other state + // - or, auto_hide_state has changed + if ((old_state.visibility_state != state_.visibility_state && + state_.visibility_state == SHELF_AUTO_HIDE) || + old_state.auto_hide_state != state_.auto_hide_state) { + for (auto& observer : observers_) + observer.OnAutoHideStateChanged(state_.auto_hide_state); + } +} + +void ShelfLayoutManager::UpdateBoundsAndOpacity( + const TargetBounds& target_bounds, + bool animate, + bool change_work_area, + ui::ImplicitAnimationObserver* observer) { + base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true); + { + ui::ScopedLayerAnimationSettings shelf_animation_setter( + GetLayer(shelf_widget_)->GetAnimator()); + ui::ScopedLayerAnimationSettings status_animation_setter( + GetLayer(shelf_widget_->status_area_widget())->GetAnimator()); + if (animate) { + int duration = duration_override_in_ms_ ? duration_override_in_ms_ + : kAnimationDurationMS; + shelf_animation_setter.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(duration)); + shelf_animation_setter.SetTweenType(gfx::Tween::EASE_OUT); + shelf_animation_setter.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + status_animation_setter.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(duration)); + status_animation_setter.SetTweenType(gfx::Tween::EASE_OUT); + status_animation_setter.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + } else { + StopAnimating(); + shelf_animation_setter.SetTransitionDuration(base::TimeDelta()); + status_animation_setter.SetTransitionDuration(base::TimeDelta()); + } + if (observer) + status_animation_setter.AddObserver(observer); + + GetLayer(shelf_widget_)->SetOpacity(target_bounds.opacity); + WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + shelf_widget_->SetBounds(shelf_window->GetParent()->ConvertRectToScreen( + target_bounds.shelf_bounds_in_root)); + + GetLayer(shelf_widget_->status_area_widget()) + ->SetOpacity(target_bounds.status_opacity); + + // Having a window which is visible but does not have an opacity is an + // illegal state. We therefore hide the shelf here if required. + if (!target_bounds.status_opacity) + shelf_widget_->status_area_widget()->Hide(); + // Setting visibility during an animation causes the visibility property to + // animate. Override the animation settings to immediately set the + // visibility property. Opacity will still animate. + + // TODO(harrym): Once status area widget is a child view of shelf + // this can be simplified. + gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf; + status_bounds.Offset(target_bounds.shelf_bounds_in_root.OffsetFromOrigin()); + WmWindow* status_window = + WmWindow::Get(shelf_widget_->status_area_widget()->GetNativeWindow()); + shelf_widget_->status_area_widget()->SetBounds( + status_window->GetParent()->ConvertRectToScreen(status_bounds)); + + // For crbug.com/622431, when the shelf alignment is BOTTOM_LOCKED, we + // don't set display work area, as it is not real user-set alignment. + if (!state_.IsScreenLocked() && + wm_shelf_->GetAlignment() != SHELF_ALIGNMENT_BOTTOM_LOCKED && + change_work_area) { + gfx::Insets insets; + // If user session is blocked (login to new user session or add user to + // the existing session - multi-profile) then give 100% of work area only + // if keyboard is not shown. + if (!state_.IsAddingSecondaryUser() || !keyboard_bounds_.IsEmpty()) + insets = target_bounds.work_area_insets; + WmShell::Get()->SetDisplayWorkAreaInsets(shelf_window, insets); + } + } + + // Set an empty border to avoid the shelf view and status area overlapping. + // TODO(msw): Avoid setting bounds of views within the shelf widget here. + gfx::Rect shelf_bounds = gfx::Rect(target_bounds.shelf_bounds_in_root.size()); + shelf_widget_->GetContentsView()->SetBorder(views::CreateEmptyBorder( + shelf_bounds.InsetsFrom(target_bounds.shelf_bounds_in_shelf))); + shelf_widget_->GetContentsView()->Layout(); + + // Setting visibility during an animation causes the visibility property to + // animate. Set the visibility property without an animation. + if (target_bounds.status_opacity) + shelf_widget_->status_area_widget()->Show(); +} + +void ShelfLayoutManager::StopAnimating() { + GetLayer(shelf_widget_)->GetAnimator()->StopAnimating(); + GetLayer(shelf_widget_->status_area_widget())->GetAnimator()->StopAnimating(); +} + +void ShelfLayoutManager::CalculateTargetBounds(const State& state, + TargetBounds* target_bounds) { + int shelf_size = GetShelfConstant(SHELF_SIZE); + if (state.visibility_state == SHELF_AUTO_HIDE && + state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) { + // Auto-hidden shelf always starts with the default size. If a gesture-drag + // is in progress, then the call to UpdateTargetBoundsForGesture() below + // takes care of setting the height properly. + shelf_size = kShelfAutoHideSize; + } else if (state.visibility_state == SHELF_HIDDEN || + (!keyboard_bounds_.IsEmpty() && + !keyboard::IsKeyboardOverscrollEnabled())) { + shelf_size = 0; + } + + WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + gfx::Rect available_bounds = wm::GetDisplayBoundsWithShelf(shelf_window); + available_bounds.Inset(0, chromevox_panel_height_, 0, 0); + int shelf_width = PrimaryAxisValue(available_bounds.width(), shelf_size); + int shelf_height = PrimaryAxisValue(shelf_size, available_bounds.height()); + int bottom_shelf_vertical_offset = available_bounds.bottom(); + if (keyboard_bounds_.IsEmpty()) + bottom_shelf_vertical_offset -= shelf_height; + else + bottom_shelf_vertical_offset -= keyboard_bounds_.height(); + + gfx::Point shelf_origin = SelectValueForShelfAlignment( + gfx::Point(available_bounds.x(), bottom_shelf_vertical_offset), + gfx::Point(available_bounds.x(), available_bounds.y()), + gfx::Point(available_bounds.right() - shelf_width, available_bounds.y())); + target_bounds->shelf_bounds_in_root = + gfx::Rect(shelf_origin.x(), shelf_origin.y(), shelf_width, shelf_height); + + gfx::Size status_size( + shelf_widget_->status_area_widget()->GetWindowBoundsInScreen().size()); + if (wm_shelf_->IsHorizontalAlignment()) + status_size.set_height(GetShelfConstant(SHELF_SIZE)); + else + status_size.set_width(GetShelfConstant(SHELF_SIZE)); + + gfx::Point status_origin = SelectValueForShelfAlignment( + gfx::Point(0, 0), gfx::Point(shelf_width - status_size.width(), + shelf_height - status_size.height()), + gfx::Point(0, shelf_height - status_size.height())); + if (wm_shelf_->IsHorizontalAlignment() && !base::i18n::IsRTL()) + status_origin.set_x(shelf_width - status_size.width()); + target_bounds->status_bounds_in_shelf = gfx::Rect(status_origin, status_size); + + target_bounds->work_area_insets = SelectValueForShelfAlignment( + gfx::Insets(0, 0, GetWorkAreaInsets(state, shelf_height), 0), + gfx::Insets(0, GetWorkAreaInsets(state, shelf_width), 0, 0), + gfx::Insets(0, 0, 0, GetWorkAreaInsets(state, shelf_width))); + + // TODO(varkha): The functionality of managing insets for display areas + // should probably be pushed to a separate component. This would simplify or + // remove entirely the dependency on keyboard and dock. + + if (!keyboard_bounds_.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()) { + // Also push in the work area inset for the keyboard if it is visible. + gfx::Insets keyboard_insets(0, 0, keyboard_bounds_.height(), 0); + target_bounds->work_area_insets += keyboard_insets; + } + + // Also push in the work area inset for the dock if it is visible. + if (!dock_bounds_.IsEmpty()) { + gfx::Insets dock_insets( + 0, (dock_bounds_.x() > 0 ? 0 : dock_bounds_.width()), 0, + (dock_bounds_.x() > 0 ? dock_bounds_.width() : 0)); + target_bounds->work_area_insets += dock_insets; + } + + // Also push in the work area insets for the ChromeVox panel if it's visible. + if (chromevox_panel_height_) { + gfx::Insets chromevox_insets(chromevox_panel_height_, 0, 0, 0); + target_bounds->work_area_insets += chromevox_insets; + } + + target_bounds->opacity = ComputeTargetOpacity(state); + target_bounds->status_opacity = + (state.visibility_state == SHELF_AUTO_HIDE && + state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN && + gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) + ? 0.0f + : target_bounds->opacity; + + if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS) + UpdateTargetBoundsForGesture(target_bounds); + + // This needs to happen after calling UpdateTargetBoundsForGesture(), because + // that can change the size of the shelf. + target_bounds->shelf_bounds_in_shelf = SelectValueForShelfAlignment( + gfx::Rect(0, 0, shelf_width - status_size.width(), + target_bounds->shelf_bounds_in_root.height()), + gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(), + shelf_height - status_size.height()), + gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(), + shelf_height - status_size.height())); + + available_bounds.Subtract(target_bounds->shelf_bounds_in_root); + available_bounds.Subtract(keyboard_bounds_); + + WmWindow* root = shelf_window->GetRootWindow(); + user_work_area_bounds_ = root->ConvertRectToScreen(available_bounds); +} + +void ShelfLayoutManager::UpdateTargetBoundsForGesture( + TargetBounds* target_bounds) const { + CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_); + bool horizontal = wm_shelf_->IsHorizontalAlignment(); + WmWindow* window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + gfx::Rect available_bounds = wm::GetDisplayBoundsWithShelf(window); + int resistance_free_region = 0; + + if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN && + visibility_state() == SHELF_AUTO_HIDE && + auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) { + // If the shelf was hidden when the drag started (and the state hasn't + // changed since then, e.g. because the tray-menu was shown because of the + // drag), then allow the drag some resistance-free region at first to make + // sure the shelf sticks with the finger until the shelf is visible. + resistance_free_region = GetShelfConstant(SHELF_SIZE) - kShelfAutoHideSize; + } + + bool resist = SelectValueForShelfAlignment( + gesture_drag_amount_<-resistance_free_region, gesture_drag_amount_> + resistance_free_region, + gesture_drag_amount_ < -resistance_free_region); + + float translate = 0.f; + if (resist) { + float diff = fabsf(gesture_drag_amount_) - resistance_free_region; + diff = std::min(diff, sqrtf(diff)); + if (gesture_drag_amount_ < 0) + translate = -resistance_free_region - diff; + else + translate = resistance_free_region + diff; + } else { + translate = gesture_drag_amount_; + } + int shelf_insets = GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE); + if (horizontal) { + // Move and size the shelf with the gesture. + int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate; + shelf_height = std::max(shelf_height, shelf_insets); + target_bounds->shelf_bounds_in_root.set_height(shelf_height); + if (wm_shelf_->IsHorizontalAlignment()) { + target_bounds->shelf_bounds_in_root.set_y(available_bounds.bottom() - + shelf_height); + } + + target_bounds->status_bounds_in_shelf.set_y(0); + } else { + // Move and size the shelf with the gesture. + int shelf_width = target_bounds->shelf_bounds_in_root.width(); + bool right_aligned = wm_shelf_->GetAlignment() == SHELF_ALIGNMENT_RIGHT; + if (right_aligned) + shelf_width -= translate; + else + shelf_width += translate; + shelf_width = std::max(shelf_width, shelf_insets); + target_bounds->shelf_bounds_in_root.set_width(shelf_width); + if (right_aligned) { + target_bounds->shelf_bounds_in_root.set_x(available_bounds.right() - + shelf_width); + } + + if (right_aligned) { + target_bounds->status_bounds_in_shelf.set_x(0); + } else { + target_bounds->status_bounds_in_shelf.set_x( + target_bounds->shelf_bounds_in_root.width() - + GetShelfConstant(SHELF_SIZE)); + } + } +} + +void ShelfLayoutManager::MaybeUpdateShelfBackground(AnimationChangeType type) { + const ShelfBackgroundType new_background_type(GetShelfBackgroundType()); + + if (new_background_type == shelf_background_type_) + return; + + shelf_background_type_ = new_background_type; + for (auto& observer : observers_) + observer.OnBackgroundUpdated(shelf_background_type_, type); +} + +void ShelfLayoutManager::UpdateAutoHideStateNow() { + SetState(state_.visibility_state); + + // If the state did not change, the auto hide timer may still be running. + StopAutoHideTimer(); +} + +void ShelfLayoutManager::StopAutoHideTimer() { + auto_hide_timer_.Stop(); + mouse_over_shelf_when_auto_hide_timer_started_ = false; +} + +gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const { + gfx::Rect shelf_bounds_in_screen = shelf_widget_->GetWindowBoundsInScreen(); + gfx::Vector2d offset = SelectValueForShelfAlignment( + gfx::Vector2d(0, shelf_bounds_in_screen.height()), + gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0), + gfx::Vector2d(shelf_bounds_in_screen.width(), 0)); + + gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen; + show_shelf_region_in_screen += offset; + if (wm_shelf_->IsHorizontalAlignment()) + show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize); + else + show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize); + + // TODO: Figure out if we need any special handling when the keyboard is + // visible. + return show_shelf_region_in_screen; +} + +ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState( + ShelfVisibilityState visibility_state) const { + if (visibility_state != SHELF_AUTO_HIDE || !wm_shelf_->IsShelfInitialized()) + return SHELF_AUTO_HIDE_HIDDEN; + + if (shelf_widget_->IsShowingAppList()) + return SHELF_AUTO_HIDE_SHOWN; + + if (shelf_widget_->status_area_widget() && + shelf_widget_->status_area_widget()->ShouldShowShelf()) + return SHELF_AUTO_HIDE_SHOWN; + + if (shelf_widget_->IsShowingContextMenu()) + return SHELF_AUTO_HIDE_SHOWN; + + if (shelf_widget_->IsShowingOverflowBubble()) + return SHELF_AUTO_HIDE_SHOWN; + + if (shelf_widget_->IsActive() || + (shelf_widget_->status_area_widget() && + shelf_widget_->status_area_widget()->IsActive())) + return SHELF_AUTO_HIDE_SHOWN; + + const int64_t shelf_display_id = + WmWindow::Get(shelf_widget_->GetNativeWindow()) + ->GetDisplayNearestWindow() + .id(); + const std::vector<WmWindow*> windows = + WmShell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal(); + // Process the window list and check if there are any visible windows. + // Ignore app list windows that may be animating to hide after dismissal. + bool visible_window = false; + for (size_t i = 0; i < windows.size(); ++i) { + if (windows[i] && windows[i]->IsVisible() && !IsAppListWindow(windows[i]) && + !windows[i]->GetWindowState()->IsMinimized() && + windows[i]->GetDisplayNearestWindow().id() == shelf_display_id) { + visible_window = true; + break; + } + } + // If there are no visible windows do not hide the shelf. + if (!visible_window) + return SHELF_AUTO_HIDE_SHOWN; + + if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS) + return gesture_drag_auto_hide_state_; + + // Don't show if the user is dragging the mouse. + if (in_mouse_drag_) + return SHELF_AUTO_HIDE_HIDDEN; + + // Ignore the mouse position if mouse events are disabled. + if (!shelf_widget_->IsMouseEventsEnabled()) + return SHELF_AUTO_HIDE_HIDDEN; + + gfx::Rect shelf_region = shelf_widget_->GetWindowBoundsInScreen(); + if (shelf_widget_->status_area_widget() && + shelf_widget_->status_area_widget()->IsMessageBubbleShown() && + IsVisible()) { + // Increase the the hit test area to prevent the shelf from disappearing + // when the mouse is over the bubble gap. + ShelfAlignment alignment = wm_shelf_->GetAlignment(); + shelf_region.Inset( + alignment == SHELF_ALIGNMENT_RIGHT ? -kNotificationBubbleGapHeight : 0, + wm_shelf_->IsHorizontalAlignment() ? -kNotificationBubbleGapHeight : 0, + alignment == SHELF_ALIGNMENT_LEFT ? -kNotificationBubbleGapHeight : 0, + 0); + } + + gfx::Point cursor_position_in_screen = + display::Screen::GetScreen()->GetCursorScreenPoint(); + if (shelf_region.Contains(cursor_position_in_screen)) + return SHELF_AUTO_HIDE_SHOWN; + + // When the shelf is auto hidden and the shelf is on the boundary between two + // displays, it is hard to trigger showing the shelf. For instance, if a + // user's primary display is left of their secondary display, it is hard to + // unautohide a left aligned shelf on the secondary display. + // It is hard because: + // - It is hard to stop the cursor in the shelf "light bar" and not overshoot. + // - The cursor is warped to the other display if the cursor gets to the edge + // of the display. + // Show the shelf if the cursor started on the shelf and the user overshot the + // shelf slightly to make it easier to show the shelf in this situation. We + // do not check |auto_hide_timer_|.IsRunning() because it returns false when + // the timer's task is running. + if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN || + mouse_over_shelf_when_auto_hide_timer_started_) && + GetAutoHideShowShelfRegionInScreen().Contains( + cursor_position_in_screen)) { + return SHELF_AUTO_HIDE_SHOWN; + } + + return SHELF_AUTO_HIDE_HIDDEN; +} + +bool ShelfLayoutManager::IsShelfWindow(WmWindow* window) { + if (!window) + return false; + WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); + WmWindow* status_window = + WmWindow::Get(shelf_widget_->status_area_widget()->GetNativeWindow()); + return (shelf_window && shelf_window->Contains(window)) || + (status_window && status_window->Contains(window)); +} + +int ShelfLayoutManager::GetWorkAreaInsets(const State& state, int size) const { + if (state.visibility_state == SHELF_VISIBLE) + return size; + if (state.visibility_state == SHELF_AUTO_HIDE) + return GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE); + return 0; +} + +void ShelfLayoutManager::OnDockBoundsChanging( + const gfx::Rect& dock_bounds, + DockedWindowLayoutManagerObserver::Reason reason) { + // Skip shelf layout in case docked notification originates from this class. + if (reason == DISPLAY_INSETS_CHANGED) + return; + if (dock_bounds_ != dock_bounds) { + dock_bounds_ = dock_bounds; + OnWindowResized(); + UpdateVisibilityState(); + MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); + } +} + +void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event) { + if (event == EVENT_LOCK_ANIMATION_STARTED) { + // Enter the screen locked state and update the visibility to avoid an odd + // animation when transitioning the orientation from L/R to bottom. + state_.pre_lock_screen_animation_active = true; + UpdateShelfVisibilityAfterLoginUIChange(); + } else { + state_.pre_lock_screen_animation_active = false; + } + MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); +} + +void ShelfLayoutManager::SessionStateChanged( + session_manager::SessionState state) { + // Check transition changes to/from the add user to session and change the + // shelf alignment accordingly + const bool was_adding_user = state_.IsAddingSecondaryUser(); + const bool was_locked = state_.IsScreenLocked(); + state_.session_state = state; + MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); + if (was_adding_user != state_.IsAddingSecondaryUser()) { + UpdateShelfVisibilityAfterLoginUIChange(); + return; + } + + // Force the shelf to layout for alignment (bottom if locked, restore the + // previous alignment otherwise). + if (was_locked != state_.IsScreenLocked()) + UpdateShelfVisibilityAfterLoginUIChange(); + + TargetBounds target_bounds; + CalculateTargetBounds(state_, &target_bounds); + UpdateBoundsAndOpacity(target_bounds, true /* animate */, + true /* change_work_area */, NULL); + UpdateVisibilityState(); +} + +void ShelfLayoutManager::UpdateShelfVisibilityAfterLoginUIChange() { + UpdateVisibilityState(); + LayoutShelf(); +} + +float ShelfLayoutManager::ComputeTargetOpacity(const State& state) { + if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS || + state.visibility_state == SHELF_VISIBLE) { + return 1.0f; + } + // In Chrome OS Material Design, when shelf is hidden during auto hide state, + // target bounds are also hidden. So the window can extend to the edge of + // screen. + return (state.visibility_state == SHELF_AUTO_HIDE && + state.auto_hide_state == SHELF_AUTO_HIDE_SHOWN) + ? 1.0f + : 0.0f; +} + +bool ShelfLayoutManager::IsShelfHiddenForFullscreen() const { + const WmWindow* fullscreen_window = wm::GetWindowForFullscreenMode( + WmWindow::Get(shelf_widget_->GetNativeWindow())); + return fullscreen_window && + fullscreen_window->GetWindowState()->hide_shelf_when_fullscreen(); +} + +//////////////////////////////////////////////////////////////////////////////// +// ShelfLayoutManager, Gesture functions: + +void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) { + gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS; + gesture_drag_amount_ = 0.f; + gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE + ? auto_hide_state() + : SHELF_AUTO_HIDE_SHOWN; + MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); +} + +void ShelfLayoutManager::UpdateGestureDrag(const ui::GestureEvent& gesture) { + gesture_drag_amount_ += PrimaryAxisValue(gesture.details().scroll_y(), + gesture.details().scroll_x()); + LayoutShelf(); +} + +void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) { + bool horizontal = wm_shelf_->IsHorizontalAlignment(); + bool should_change = false; + if (gesture.type() == ui::ET_GESTURE_SCROLL_END) { + // The visibility of the shelf changes only if the shelf was dragged X% + // along the correct axis. If the shelf was already visible, then the + // direction of the drag does not matter. + const float kDragHideThreshold = 0.4f; + gfx::Rect bounds = GetIdealBounds(); + float drag_ratio = fabs(gesture_drag_amount_) / + (horizontal ? bounds.height() : bounds.width()); + if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) { + should_change = drag_ratio > kDragHideThreshold; + } else { + bool correct_direction = false; + switch (wm_shelf_->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + case SHELF_ALIGNMENT_RIGHT: + correct_direction = gesture_drag_amount_ < 0; + break; + case SHELF_ALIGNMENT_LEFT: + correct_direction = gesture_drag_amount_ > 0; + break; + } + should_change = correct_direction && drag_ratio > kDragHideThreshold; + } + } else if (gesture.type() == ui::ET_SCROLL_FLING_START) { + if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) { + should_change = horizontal ? fabs(gesture.details().velocity_y()) > 0 + : fabs(gesture.details().velocity_x()) > 0; + } else { + should_change = + SelectValueForShelfAlignment(gesture.details().velocity_y() < 0, + gesture.details().velocity_x() > 0, + gesture.details().velocity_x() < 0); + } + } else { + NOTREACHED(); + } + + if (!should_change) { + CancelGestureDrag(); + return; + } + + shelf_widget_->Deactivate(); + shelf_widget_->status_area_widget()->Deactivate(); + + gesture_drag_auto_hide_state_ = + gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN + ? SHELF_AUTO_HIDE_HIDDEN + : SHELF_AUTO_HIDE_SHOWN; + ShelfAutoHideBehavior new_auto_hide_behavior = + gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN + ? SHELF_AUTO_HIDE_BEHAVIOR_NEVER + : SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS; + + // When in fullscreen and the shelf is forced to be auto hidden, the auto hide + // behavior affects neither the visibility state nor the auto hide state. Set + // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto + // hide state to |gesture_drag_auto_hide_state_|. + gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS; + if (wm_shelf_->auto_hide_behavior() != new_auto_hide_behavior) + wm_shelf_->SetAutoHideBehavior(new_auto_hide_behavior); + else + UpdateVisibilityState(); + gesture_drag_status_ = GESTURE_DRAG_NONE; +} + +void ShelfLayoutManager::CancelGestureDrag() { + gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS; + UpdateVisibilityState(); + gesture_drag_status_ = GESTURE_DRAG_NONE; +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_layout_manager.h b/ash/common/shelf/shelf_layout_manager.h new file mode 100644 index 0000000..87f598a --- /dev/null +++ b/ash/common/shelf/shelf_layout_manager.h
@@ -0,0 +1,365 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_LAYOUT_MANAGER_H_ +#define ASH_COMMON_SHELF_SHELF_LAYOUT_MANAGER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/session/session_state_observer.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/dock/docked_window_layout_manager_observer.h" +#include "ash/common/wm/lock_state_observer.h" +#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h" +#include "ash/common/wm/workspace/workspace_types.h" +#include "ash/common/wm_activation_observer.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/timer/timer.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace ui { +class ImplicitAnimationObserver; +class MouseEvent; +} + +namespace ash { + +enum class AnimationChangeType; +class PanelLayoutManagerTest; +class ShelfLayoutManagerObserver; +class ShelfLayoutManagerTest; +class ShelfWidget; +class WmShelf; + +// ShelfLayoutManager is the layout manager responsible for the shelf and +// status widgets. The shelf is given the total available width and told the +// width of the status area. This allows the shelf to draw the background and +// layout to the status area. +// To respond to bounds changes in the status area StatusAreaLayoutManager works +// closely with ShelfLayoutManager. +// On mus, widget bounds management is handled by the window manager. +class ASH_EXPORT ShelfLayoutManager + : public ShellObserver, + public WmActivationObserver, + public DockedWindowLayoutManagerObserver, + public keyboard::KeyboardControllerObserver, + public LockStateObserver, + public wm::WmSnapToPixelLayoutManager, + public SessionStateObserver { + public: + ShelfLayoutManager(ShelfWidget* shelf_widget, WmShelf* wm_shelf); + ~ShelfLayoutManager() override; + + bool updating_bounds() const { return updating_bounds_; } + + // Clears internal data for shutdown process. + void PrepareForShutdown(); + + // Returns whether the shelf and its contents (shelf, status) are visible + // on the screen. + bool IsVisible() const; + + // Returns the ideal bounds of the shelf assuming it is visible. + gfx::Rect GetIdealBounds(); + + // Returns the preferred size of the shelf for the target visibility state. + gfx::Size GetPreferredSize(); + + // Returns the docked area bounds. + const gfx::Rect& dock_bounds() const { return dock_bounds_; } + + // Returns the bounds within the root window not occupied by the shelf nor the + // virtual keyboard. + const gfx::Rect& user_work_area_bounds() const { + return user_work_area_bounds_; + } + + // Stops any animations and sets the bounds of the shelf and status widgets. + void LayoutShelfAndUpdateBounds(bool change_work_area); + + // Stops any animations, sets the bounds of the shelf and status widgets, and + // changes the work area + void LayoutShelf(); + + // Returns shelf visibility state based on current value of auto hide + // behavior setting. + ShelfVisibilityState CalculateShelfVisibility(); + + // Updates the visibility state. + void UpdateVisibilityState(); + + // Invoked by the shelf when the auto-hide state may have changed. + void UpdateAutoHideState(); + + // Updates the auto-hide state for certain events. + // TODO(mash): Add similar event handling support for mash. + void UpdateAutoHideForMouseEvent(ui::MouseEvent* event, WmWindow* target); + void UpdateAutoHideForGestureEvent(ui::GestureEvent* event, WmWindow* target); + + ShelfVisibilityState visibility_state() const { + return state_.visibility_state; + } + ShelfAutoHideState auto_hide_state() const { return state_.auto_hide_state; } + + ShelfWidget* shelf_widget() { return shelf_widget_; } + + // Sets whether any windows overlap the shelf. If a window overlaps the shelf + // the shelf renders slightly differently. + void SetWindowOverlapsShelf(bool value); + bool window_overlaps_shelf() const { return window_overlaps_shelf_; } + + void AddObserver(ShelfLayoutManagerObserver* observer); + void RemoveObserver(ShelfLayoutManagerObserver* observer); + + // Processes a gesture event and updates the status of the shelf when + // appropriate. Returns true if the gesture has been handled and it should not + // be processed any further, false otherwise. + bool ProcessGestureEvent(const ui::GestureEvent& event); + + // Set an animation duration override for the show / hide animation of the + // shelf. Specifying 0 leads to use the default. + void SetAnimationDurationOverride(int duration_override_in_ms); + + // Overridden from wm::WmSnapToPixelLayoutManager: + void OnWindowResized() override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + // Overridden from ShellObserver: + void OnShelfAutoHideBehaviorChanged(WmWindow* root_window) override; + void OnPinnedStateChanged(WmWindow* pinned_window) override; + + // Overridden from WmActivationObserver: + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override; + + // Overridden from keyboard::KeyboardControllerObserver: + void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; + void OnKeyboardClosed() override; + + // Overridden from LockStateObserver: + void OnLockStateEvent(LockStateObserver::EventType event) override; + + // Overridden from SessionStateObserver: + void SessionStateChanged(session_manager::SessionState state) override; + + // TODO(harrym|oshima): These templates will be moved to a new Shelf class. + // A helper function for choosing values specific to a shelf alignment. + template <typename T> + T SelectValueForShelfAlignment(T bottom, T left, T right) const { + switch (wm_shelf_->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + return bottom; + case SHELF_ALIGNMENT_LEFT: + return left; + case SHELF_ALIGNMENT_RIGHT: + return right; + } + NOTREACHED(); + return right; + } + + template <typename T> + T PrimaryAxisValue(T horizontal, T vertical) const { + return wm_shelf_->IsHorizontalAlignment() ? horizontal : vertical; + } + + // Returns how the shelf background should be painted. + ShelfBackgroundType GetShelfBackgroundType() const; + + // Set the height of the ChromeVox panel, which takes away space from the + // available work area from the top of the screen. + void SetChromeVoxPanelHeight(int height); + + private: + class UpdateShelfObserver; + friend class PanelLayoutManagerTest; + friend class ShelfLayoutManagerTest; + friend class WebNotificationTrayTest; + + struct TargetBounds { + TargetBounds(); + ~TargetBounds(); + + float opacity; + float status_opacity; + gfx::Rect shelf_bounds_in_root; + gfx::Rect shelf_bounds_in_shelf; + gfx::Rect status_bounds_in_shelf; + gfx::Insets work_area_insets; + }; + + struct State { + State(); + + // Returns true when a secondary user is being added to an existing session. + bool IsAddingSecondaryUser() const; + + bool IsScreenLocked() const; + + // Returns true if the two states are considered equal. As + // |auto_hide_state| only matters if |visibility_state| is + // |SHELF_AUTO_HIDE|, Equals() ignores the |auto_hide_state| as + // appropriate. + bool Equals(const State& other) const; + + ShelfVisibilityState visibility_state; + ShelfAutoHideState auto_hide_state; + wm::WorkspaceWindowState window_state; + // True when the system is in the cancelable, pre-lock screen animation. + bool pre_lock_screen_animation_active; + session_manager::SessionState session_state; + }; + + // Sets the visibility of the shelf to |state|. + void SetState(ShelfVisibilityState visibility_state); + + // Updates the bounds and opacity of the shelf and status widgets. + // If |observer| is specified, it will be called back when the animations, if + // any, are complete. |change_work_area| specifies whether or not to update + // the work area of the screen. + void UpdateBoundsAndOpacity(const TargetBounds& target_bounds, + bool animate, + bool change_work_area, + ui::ImplicitAnimationObserver* observer); + + // Stops any animations and progresses them to the end. + void StopAnimating(); + + // Calculates the target bounds assuming visibility of |visible|. + void CalculateTargetBounds(const State& state, TargetBounds* target_bounds); + + // Updates the target bounds if a gesture-drag is in progress. This is only + // used by |CalculateTargetBounds()|. + void UpdateTargetBoundsForGesture(TargetBounds* target_bounds) const; + + // Updates the background of the shelf if it has changed. + void MaybeUpdateShelfBackground(AnimationChangeType change_type); + + // Updates the auto hide state immediately. + void UpdateAutoHideStateNow(); + + // Stops the auto hide timer and clears + // |mouse_over_shelf_when_auto_hide_timer_started_|. + void StopAutoHideTimer(); + + // Returns the bounds of an additional region which can trigger showing the + // shelf. This region exists to make it easier to trigger showing the shelf + // when the shelf is auto hidden and the shelf is on the boundary between + // two displays. + gfx::Rect GetAutoHideShowShelfRegionInScreen() const; + + // Returns the AutoHideState. This value is determined from the shelf and + // tray. + ShelfAutoHideState CalculateAutoHideState( + ShelfVisibilityState visibility_state) const; + + // Returns true if |window| is a descendant of the shelf. + bool IsShelfWindow(WmWindow* window); + + int GetWorkAreaInsets(const State& state, int size) const; + + // Overridden from DockedWindowLayoutManagerObserver: + void OnDockBoundsChanging( + const gfx::Rect& dock_bounds, + DockedWindowLayoutManagerObserver::Reason reason) override; + + // Called when the LoginUI changes from visible to invisible. + void UpdateShelfVisibilityAfterLoginUIChange(); + + // Compute |target_bounds| opacity based on gesture and shelf visibility. + float ComputeTargetOpacity(const State& state); + + // Returns true if there is a fullscreen window open that causes the shelf + // to be hidden. + bool IsShelfHiddenForFullscreen() const; + + // Gesture related functions: + void StartGestureDrag(const ui::GestureEvent& gesture); + void UpdateGestureDrag(const ui::GestureEvent& gesture); + void CompleteGestureDrag(const ui::GestureEvent& gesture); + void CancelGestureDrag(); + + // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling + // UpdateBoundsAndOpacity() again from SetChildBounds(). + bool updating_bounds_; + + bool in_shutdown_ = false; + + // True if the last mouse event was a mouse drag. + bool in_mouse_drag_ = false; + + // Current state. + State state_; + + ShelfWidget* shelf_widget_; + WmShelf* wm_shelf_; + + // Do any windows overlap the shelf? This is maintained by WorkspaceManager. + bool window_overlaps_shelf_; + + base::OneShotTimer auto_hide_timer_; + + // Whether the mouse was over the shelf when the auto hide timer started. + // False when neither the auto hide timer nor the timer task are running. + bool mouse_over_shelf_when_auto_hide_timer_started_; + + base::ObserverList<ShelfLayoutManagerObserver> observers_; + + // The shelf reacts to gesture-drags, and can be set to auto-hide for certain + // gestures. Some shelf behaviour (e.g. visibility state, background color + // etc.) are affected by various stages of the drag. The enum keeps track of + // the present status of the gesture drag. + enum GestureDragStatus { + GESTURE_DRAG_NONE, + GESTURE_DRAG_IN_PROGRESS, + GESTURE_DRAG_CANCEL_IN_PROGRESS, + GESTURE_DRAG_COMPLETE_IN_PROGRESS + }; + GestureDragStatus gesture_drag_status_; + + // Tracks the amount of the drag. The value is only valid when + // |gesture_drag_status_| is set to GESTURE_DRAG_IN_PROGRESS. + float gesture_drag_amount_; + + // Manage the auto-hide state during the gesture. + ShelfAutoHideState gesture_drag_auto_hide_state_; + + // Used to delay updating shelf background. + UpdateShelfObserver* update_shelf_observer_; + + // The bounds of the keyboard. + gfx::Rect keyboard_bounds_; + + // The bounds of the dock. + gfx::Rect dock_bounds_; + + // The bounds within the root window not occupied by the shelf nor the virtual + // keyboard. + gfx::Rect user_work_area_bounds_; + + // The height of the ChromeVox panel at the top of the screen, which + // needs to be removed from the available work area. + int chromevox_panel_height_; + + // The show hide animation duration override or 0 for default. + int duration_override_in_ms_; + + // The current shelf background. Should not be assigned to directly, use + // MaybeUpdateShelfBackground() instead. + ShelfBackgroundType shelf_background_type_; + + DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_LAYOUT_MANAGER_H_
diff --git a/ash/common/shelf/shelf_layout_manager_observer.h b/ash/common/shelf/shelf_layout_manager_observer.h new file mode 100644 index 0000000..00d03b13 --- /dev/null +++ b/ash/common/shelf/shelf_layout_manager_observer.h
@@ -0,0 +1,36 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_LAYOUT_MANAGER_OBSERVER_H_ +#define ASH_COMMON_SHELF_SHELF_LAYOUT_MANAGER_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_background_animator.h" +#include "ash/public/cpp/shelf_types.h" + +namespace ash { + +enum class AnimationChangeType; + +class ASH_EXPORT ShelfLayoutManagerObserver { + public: + virtual ~ShelfLayoutManagerObserver() {} + + // Called when the target ShelfLayoutManager will be deleted. + virtual void WillDeleteShelfLayoutManager() {} + + // Called when the visibility change is scheduled. + virtual void WillChangeVisibilityState(ShelfVisibilityState new_state) {} + + // Called when the auto hide state is changed. + virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) {} + + // Called when shelf background animation is started. + virtual void OnBackgroundUpdated(ShelfBackgroundType background_type, + AnimationChangeType change_type) {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_LAYOUT_MANAGER_OBSERVER_H_
diff --git a/ash/common/shelf/shelf_locking_manager.cc b/ash/common/shelf/shelf_locking_manager.cc new file mode 100644 index 0000000..aabc145 --- /dev/null +++ b/ash/common/shelf/shelf_locking_manager.cc
@@ -0,0 +1,56 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_locking_manager.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_shell.h" + +namespace ash { + +ShelfLockingManager::ShelfLockingManager(WmShelf* shelf) : shelf_(shelf) { + WmShell::Get()->AddLockStateObserver(this); + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + session_locked_ = + delegate->GetSessionState() != session_manager::SessionState::ACTIVE; + screen_locked_ = delegate->IsScreenLocked(); + delegate->AddSessionStateObserver(this); + WmShell::Get()->AddShellObserver(this); +} + +ShelfLockingManager::~ShelfLockingManager() { + WmShell::Get()->RemoveLockStateObserver(this); + WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); + WmShell::Get()->RemoveShellObserver(this); +} + +void ShelfLockingManager::OnLockStateChanged(bool locked) { + screen_locked_ = locked; + UpdateLockedState(); +} + +void ShelfLockingManager::SessionStateChanged( + session_manager::SessionState state) { + session_locked_ = state != session_manager::SessionState::ACTIVE; + UpdateLockedState(); +} + +void ShelfLockingManager::OnLockStateEvent(EventType event) { + // Lock when the animation starts, ignoring pre-lock. There's no unlock event. + screen_locked_ |= event == EVENT_LOCK_ANIMATION_STARTED; + UpdateLockedState(); +} + +void ShelfLockingManager::UpdateLockedState() { + const ShelfAlignment alignment = shelf_->GetAlignment(); + if (is_locked() && alignment != SHELF_ALIGNMENT_BOTTOM_LOCKED) { + stored_alignment_ = alignment; + shelf_->SetAlignment(SHELF_ALIGNMENT_BOTTOM_LOCKED); + } else if (!is_locked() && alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { + shelf_->SetAlignment(stored_alignment_); + } +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_locking_manager.h b/ash/common/shelf/shelf_locking_manager.h new file mode 100644 index 0000000..2bf015e --- /dev/null +++ b/ash/common/shelf/shelf_locking_manager.h
@@ -0,0 +1,52 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_LOCKING_MANAGER_H_ +#define ASH_COMMON_SHELF_SHELF_LOCKING_MANAGER_H_ + +#include "ash/ash_export.h" +#include "ash/common/session/session_state_observer.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/lock_state_observer.h" +#include "ash/public/cpp/shelf_types.h" + +namespace ash { + +class WmShelf; + +// ShelfLockingManager observes screen and session events to [un]lock the shelf. +class ASH_EXPORT ShelfLockingManager : public ShellObserver, + public SessionStateObserver, + public LockStateObserver { + public: + explicit ShelfLockingManager(WmShelf* shelf); + ~ShelfLockingManager() override; + + bool is_locked() const { return session_locked_ || screen_locked_; } + void set_stored_alignment(ShelfAlignment value) { stored_alignment_ = value; } + + // ShellObserver: + void OnLockStateChanged(bool locked) override; + + // SessionStateObserver: + void SessionStateChanged(session_manager::SessionState state) override; + + // LockStateObserver: + void OnLockStateEvent(EventType event) override; + + private: + // Update the shelf state for session and screen lock changes. + void UpdateLockedState(); + + WmShelf* shelf_; + bool session_locked_ = false; + bool screen_locked_ = false; + ShelfAlignment stored_alignment_ = SHELF_ALIGNMENT_BOTTOM; + + DISALLOW_COPY_AND_ASSIGN(ShelfLockingManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_LOCKING_MANAGER_H_
diff --git a/ash/common/shelf/shelf_locking_manager_unittest.cc b/ash/common/shelf/shelf_locking_manager_unittest.cc new file mode 100644 index 0000000..d225a937 --- /dev/null +++ b/ash/common/shelf/shelf_locking_manager_unittest.cc
@@ -0,0 +1,82 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_locking_manager.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/test/ash_test_base.h" + +namespace ash { +namespace test { + +// Tests the shelf behavior when the screen or session is locked. +class ShelfLockingManagerTest : public ash::test::AshTestBase { + public: + ShelfLockingManagerTest() {} + + ShelfLockingManager* GetShelfLockingManager() { + return GetPrimaryShelf()->GetShelfLockingManagerForTesting(); + } + + void SetScreenLocked(bool locked) { + GetShelfLockingManager()->OnLockStateChanged(locked); + } + + void SetSessionState(session_manager::SessionState state) { + GetShelfLockingManager()->SessionStateChanged(state); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShelfLockingManagerTest); +}; + +// Makes sure shelf alignment is correct for lock screen. +TEST_F(ShelfLockingManagerTest, AlignmentLockedWhileScreenLocked) { + WmShelf* shelf = GetPrimaryShelf(); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->GetAlignment()); + + shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); + EXPECT_EQ(SHELF_ALIGNMENT_LEFT, shelf->GetAlignment()); + + SetScreenLocked(true); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); + SetScreenLocked(false); + EXPECT_EQ(SHELF_ALIGNMENT_LEFT, shelf->GetAlignment()); +} + +// Makes sure shelf alignment is correct for login and add user screens. +TEST_F(ShelfLockingManagerTest, AlignmentLockedWhileSessionLocked) { + WmShelf* shelf = GetPrimaryShelf(); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->GetAlignment()); + + shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); + EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); + + SetSessionState(session_manager::SessionState::LOGIN_PRIMARY); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); + SetSessionState(session_manager::SessionState::ACTIVE); + EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); + + SetSessionState(session_manager::SessionState::LOGIN_SECONDARY); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); + SetSessionState(session_manager::SessionState::ACTIVE); + EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); +} + +// Makes sure shelf alignment changes are stored, not set, while locked. +TEST_F(ShelfLockingManagerTest, AlignmentChangesDeferredWhileLocked) { + WmShelf* shelf = GetPrimaryShelf(); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->GetAlignment()); + + SetScreenLocked(true); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); + shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); + EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); + SetScreenLocked(false); + EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/shelf/shelf_model.cc b/ash/common/shelf/shelf_model.cc new file mode 100644 index 0000000..a6844758 --- /dev/null +++ b/ash/common/shelf/shelf_model.cc
@@ -0,0 +1,211 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_model.h" + +#include <algorithm> + +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_model_observer.h" + +namespace ash { + +namespace { + +int ShelfItemTypeToWeight(ShelfItemType type) { + switch (type) { + case TYPE_APP_LIST: + // TODO(skuhne): If the app list item becomes movable again, this need + // to be a fallthrough. + return 0; + case TYPE_BROWSER_SHORTCUT: + case TYPE_APP_SHORTCUT: + return 1; + case TYPE_APP: + return 2; + case TYPE_DIALOG: + return 3; + case TYPE_APP_PANEL: + return 4; + case TYPE_UNDEFINED: + NOTREACHED() << "ShelfItemType must be set"; + return -1; + } + + NOTREACHED() << "Invalid type " << type; + return 1; +} + +bool CompareByWeight(const ShelfItem& a, const ShelfItem& b) { + return ShelfItemTypeToWeight(a.type) < ShelfItemTypeToWeight(b.type); +} + +} // namespace + +ShelfModel::ShelfModel() : next_id_(1) {} + +ShelfModel::~ShelfModel() {} + +void ShelfModel::DestroyItemDelegates() { + // Some ShelfItemDelegates access this model in their destructors and hence + // need early cleanup. + id_to_item_delegate_map_.clear(); +} + +int ShelfModel::Add(const ShelfItem& item) { + return AddAt(items_.size(), item); +} + +int ShelfModel::AddAt(int index, const ShelfItem& item) { + index = ValidateInsertionIndex(item.type, index); + items_.insert(items_.begin() + index, item); + items_[index].id = next_id_++; + for (auto& observer : observers_) + observer.ShelfItemAdded(index); + return index; +} + +void ShelfModel::RemoveItemAt(int index) { + DCHECK(index >= 0 && index < item_count()); + ShelfID id = items_[index].id; + items_.erase(items_.begin() + index); + RemoveShelfItemDelegate(id); + // TODO(jamescook): Fold this into ShelfItemRemoved in existing observers. + for (auto& observer : observers_) + observer.OnSetShelfItemDelegate(id, nullptr); + for (auto& observer : observers_) + observer.ShelfItemRemoved(index, id); +} + +void ShelfModel::Move(int index, int target_index) { + if (index == target_index) + return; + // TODO: this needs to enforce valid ranges. + ShelfItem item(items_[index]); + items_.erase(items_.begin() + index); + items_.insert(items_.begin() + target_index, item); + for (auto& observer : observers_) + observer.ShelfItemMoved(index, target_index); +} + +void ShelfModel::Set(int index, const ShelfItem& item) { + if (index < 0 || index >= item_count()) { + NOTREACHED(); + return; + } + + int new_index = item.type == items_[index].type + ? index + : ValidateInsertionIndex(item.type, index); + + ShelfItem old_item(items_[index]); + items_[index] = item; + items_[index].id = old_item.id; + for (auto& observer : observers_) + observer.ShelfItemChanged(index, old_item); + + // If the type changes confirm that the item is still in the right order. + if (new_index != index) { + // The move function works by removing one item and then inserting it at the + // new location. However - by removing the item first the order will change + // so that our target index needs to be corrected. + // TODO(skuhne): Moving this into the Move function breaks lots of unit + // tests. So several functions were already using this incorrectly. + // That needs to be cleaned up. + if (index < new_index) + new_index--; + + Move(index, new_index); + } +} + +int ShelfModel::ItemIndexByID(ShelfID id) const { + ShelfItems::const_iterator i = ItemByID(id); + return i == items_.end() ? -1 : static_cast<int>(i - items_.begin()); +} + +int ShelfModel::GetItemIndexForType(ShelfItemType type) { + for (size_t i = 0; i < items_.size(); ++i) { + if (items_[i].type == type) + return i; + } + return -1; +} + +ShelfItems::const_iterator ShelfModel::ItemByID(int id) const { + for (ShelfItems::const_iterator i = items_.begin(); i != items_.end(); ++i) { + if (i->id == id) + return i; + } + return items_.end(); +} + +int ShelfModel::FirstRunningAppIndex() const { + ShelfItem weight_dummy; + weight_dummy.type = TYPE_APP; + return std::lower_bound(items_.begin(), items_.end(), weight_dummy, + CompareByWeight) - + items_.begin(); +} + +int ShelfModel::FirstPanelIndex() const { + ShelfItem weight_dummy; + weight_dummy.type = TYPE_APP_PANEL; + return std::lower_bound(items_.begin(), items_.end(), weight_dummy, + CompareByWeight) - + items_.begin(); +} + +void ShelfModel::SetShelfItemDelegate( + ShelfID id, + std::unique_ptr<ShelfItemDelegate> item_delegate) { + // If another ShelfItemDelegate is already registered for |id|, we assume + // that this request is replacing ShelfItemDelegate for |id| with + // |item_delegate|. + RemoveShelfItemDelegate(id); + + for (auto& observer : observers_) + observer.OnSetShelfItemDelegate(id, item_delegate.get()); + + id_to_item_delegate_map_[id] = std::move(item_delegate); +} + +ShelfItemDelegate* ShelfModel::GetShelfItemDelegate(ShelfID id) { + if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) + return id_to_item_delegate_map_[id].get(); + return nullptr; +} + +void ShelfModel::AddObserver(ShelfModelObserver* observer) { + observers_.AddObserver(observer); +} + +void ShelfModel::RemoveObserver(ShelfModelObserver* observer) { + observers_.RemoveObserver(observer); +} + +int ShelfModel::ValidateInsertionIndex(ShelfItemType type, int index) const { + DCHECK(index >= 0 && index <= item_count() + 1); + + // Clamp |index| to the allowed range for the type as determined by |weight|. + ShelfItem weight_dummy; + weight_dummy.type = type; + index = std::max(std::lower_bound(items_.begin(), items_.end(), weight_dummy, + CompareByWeight) - + items_.begin(), + static_cast<ShelfItems::difference_type>(index)); + index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy, + CompareByWeight) - + items_.begin(), + static_cast<ShelfItems::difference_type>(index)); + + return index; +} + +void ShelfModel::RemoveShelfItemDelegate(ShelfID id) { + if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) + id_to_item_delegate_map_.erase(id); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_model.h b/ash/common/shelf/shelf_model.h new file mode 100644 index 0000000..a5f61e80 --- /dev/null +++ b/ash/common/shelf/shelf_model.h
@@ -0,0 +1,111 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_MODEL_H_ +#define ASH_COMMON_SHELF_SHELF_MODEL_H_ + +#include <map> +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_item_types.h" +#include "base/macros.h" +#include "base/observer_list.h" + +namespace ash { + +class ShelfItemDelegate; +class ShelfModelObserver; + +// Model used for shelf items. Owns ShelfItemDelegates but does not create them. +class ASH_EXPORT ShelfModel { + public: + ShelfModel(); + ~ShelfModel(); + + // Cleans up the ShelfItemDelegates. + void DestroyItemDelegates(); + + // Adds a new item to the model. Returns the resulting index. + int Add(const ShelfItem& item); + + // Adds the item. |index| is the requested insertion index, which may be + // modified to meet type-based ordering. Returns the actual insertion index. + int AddAt(int index, const ShelfItem& item); + + // Removes the item at |index|. + void RemoveItemAt(int index); + + // Moves the item at |index| to |target_index|. |target_index| is in terms + // of the model *after* the item at |index| is removed. + void Move(int index, int target_index); + + // Resets the item at the specified index. The item maintains its existing + // id and type. + void Set(int index, const ShelfItem& item); + + // Returns the index of the item by id. + int ItemIndexByID(ShelfID id) const; + + // Returns the |index| of the item matching |type| in |items_|. + // Returns -1 if the matching item is not found. + // Note: Requires a linear search. + int GetItemIndexForType(ShelfItemType type); + + // Returns the index of the first running application or the index where the + // first running application would go if there are no running (non pinned) + // applications yet. + int FirstRunningAppIndex() const; + + // Returns the index of the first panel or the index where the first panel + // would go if there are no panels. + int FirstPanelIndex() const; + + // Returns the id assigned to the next item added. + ShelfID next_id() const { return next_id_; } + + // Returns a reserved id which will not be used by the |ShelfModel|. + ShelfID reserve_external_id() { return next_id_++; } + + // Returns an iterator into items() for the item with the specified id, or + // items().end() if there is no item with the specified id. + ShelfItems::const_iterator ItemByID(ShelfID id) const; + + const ShelfItems& items() const { return items_; } + int item_count() const { return static_cast<int>(items_.size()); } + + // Set |item_delegate| for |id| and takes ownership. + void SetShelfItemDelegate(ShelfID id, + std::unique_ptr<ShelfItemDelegate> item_delegate); + + // Returns ShelfItemDelegate for |id|, or null if none exists. + ShelfItemDelegate* GetShelfItemDelegate(ShelfID id); + + void AddObserver(ShelfModelObserver* observer); + void RemoveObserver(ShelfModelObserver* observer); + + private: + // Makes sure |index| is in line with the type-based order of items. If that + // is not the case, adjusts index by shifting it to the valid range and + // returns the new value. + int ValidateInsertionIndex(ShelfItemType type, int index) const; + + // Remove and destroy ShelfItemDelegate for |id|. + void RemoveShelfItemDelegate(ShelfID id); + + // ID assigned to the next item. + ShelfID next_id_; + + ShelfItems items_; + base::ObserverList<ShelfModelObserver> observers_; + + std::map<ShelfID, std::unique_ptr<ShelfItemDelegate>> + id_to_item_delegate_map_; + + DISALLOW_COPY_AND_ASSIGN(ShelfModel); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_MODEL_H_
diff --git a/ash/common/shelf/shelf_model_observer.h b/ash/common/shelf/shelf_model_observer.h new file mode 100644 index 0000000..794300d --- /dev/null +++ b/ash/common/shelf/shelf_model_observer.h
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_MODEL_OBSERVER_H_ +#define ASH_COMMON_SHELF_SHELF_MODEL_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_item_types.h" + +namespace ash { + +struct ShelfItem; +class ShelfItemDelegate; + +class ASH_EXPORT ShelfModelObserver { + public: + // Invoked after an item has been added to the model. + virtual void ShelfItemAdded(int index) = 0; + + // Invoked after an item has been removed. |index| is the index the item was + // at. + virtual void ShelfItemRemoved(int index, ShelfID id) = 0; + + // Invoked after an item has been moved. See ShelfModel::Move() for details + // of the arguments. + virtual void ShelfItemMoved(int start_index, int target_index) = 0; + + // Invoked when the state of an item changes. |old_item| is the item + // before the change. + virtual void ShelfItemChanged(int index, const ShelfItem& old_item) = 0; + + // Gets called when a ShelfItemDelegate gets changed. Note that + // |item_delegate| can be null. + // NOTE: This is added a temporary fix for M39 to fix crbug.com/429870. + // TODO(skuhne): Find the real reason for this problem and remove this fix. + virtual void OnSetShelfItemDelegate(ShelfID id, + ShelfItemDelegate* item_delegate) = 0; + + protected: + virtual ~ShelfModelObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_MODEL_OBSERVER_H_
diff --git a/ash/common/shelf/shelf_model_unittest.cc b/ash/common/shelf/shelf_model_unittest.cc new file mode 100644 index 0000000..9589da1 --- /dev/null +++ b/ash/common/shelf/shelf_model_unittest.cc
@@ -0,0 +1,312 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_model.h" + +#include <set> +#include <string> + +#include "ash/common/shelf/shelf_model_observer.h" +#include "base/strings/stringprintf.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +namespace { + +// ShelfModelObserver implementation that tracks what message are invoked. +class TestShelfModelObserver : public ShelfModelObserver { + public: + TestShelfModelObserver() + : added_count_(0), + removed_count_(0), + changed_count_(0), + moved_count_(0) {} + + // Returns a string description of the changes that have occurred since this + // was last invoked. Resets state to initial state. + std::string StateStringAndClear() { + std::string result; + AddToResult("added=%d", added_count_, &result); + AddToResult("removed=%d", removed_count_, &result); + AddToResult("changed=%d", changed_count_, &result); + AddToResult("moved=%d", moved_count_, &result); + added_count_ = removed_count_ = changed_count_ = moved_count_ = 0; + return result; + } + + // ShelfModelObserver overrides: + void ShelfItemAdded(int index) override { added_count_++; } + void ShelfItemRemoved(int index, ShelfID id) override { removed_count_++; } + void ShelfItemChanged(int index, const ShelfItem& old_item) override { + changed_count_++; + } + void ShelfItemMoved(int start_index, int target_index) override { + moved_count_++; + } + void OnSetShelfItemDelegate(ShelfID id, + ShelfItemDelegate* item_delegate) override {} + + private: + void AddToResult(const std::string& format, int count, std::string* result) { + if (!count) + return; + if (!result->empty()) + *result += " "; + *result += base::StringPrintf(format.c_str(), count); + } + + int added_count_; + int removed_count_; + int changed_count_; + int moved_count_; + + DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver); +}; + +} // namespace + +class ShelfModelTest : public testing::Test { + public: + ShelfModelTest() {} + ~ShelfModelTest() override {} + + void SetUp() override { + model_.reset(new ShelfModel); + observer_.reset(new TestShelfModelObserver); + EXPECT_EQ(0, model_->item_count()); + + ShelfItem item; + item.type = TYPE_APP_LIST; + model_->Add(item); + EXPECT_EQ(1, model_->item_count()); + + model_->AddObserver(observer_.get()); + } + + void TearDown() override { + observer_.reset(); + model_.reset(); + } + + std::unique_ptr<ShelfModel> model_; + std::unique_ptr<TestShelfModelObserver> observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(ShelfModelTest); +}; + +TEST_F(ShelfModelTest, BasicAssertions) { + // Add an item. + ShelfItem item; + item.type = TYPE_APP_SHORTCUT; + int index = model_->Add(item); + EXPECT_EQ(2, model_->item_count()); + EXPECT_EQ("added=1", observer_->StateStringAndClear()); + + // Change to a platform app item. + ShelfID original_id = model_->items()[index].id; + item.type = TYPE_APP; + model_->Set(index, item); + EXPECT_EQ(original_id, model_->items()[index].id); + EXPECT_EQ("changed=1", observer_->StateStringAndClear()); + EXPECT_EQ(TYPE_APP, model_->items()[index].type); + + // Remove the item. + model_->RemoveItemAt(index); + EXPECT_EQ(1, model_->item_count()); + EXPECT_EQ("removed=1", observer_->StateStringAndClear()); + + // Add an app item. + item.type = TYPE_APP_SHORTCUT; + index = model_->Add(item); + observer_->StateStringAndClear(); + + // Change everything. + model_->Set(index, item); + EXPECT_EQ("changed=1", observer_->StateStringAndClear()); + EXPECT_EQ(TYPE_APP_SHORTCUT, model_->items()[index].type); + + // Add another item. + item.type = TYPE_APP_SHORTCUT; + model_->Add(item); + observer_->StateStringAndClear(); + + // Move the second to the first. + model_->Move(1, 0); + EXPECT_EQ("moved=1", observer_->StateStringAndClear()); + + // And back. + model_->Move(0, 1); + EXPECT_EQ("moved=1", observer_->StateStringAndClear()); + + // Verifies all the items get unique ids. + std::set<ShelfID> ids; + for (int i = 0; i < model_->item_count(); ++i) + ids.insert(model_->items()[i].id); + EXPECT_EQ(model_->item_count(), static_cast<int>(ids.size())); +} + +// Assertions around where items are added. +TEST_F(ShelfModelTest, AddIndices) { + // Insert browser short cut at index 1. + ShelfItem browser_shortcut; + browser_shortcut.type = TYPE_BROWSER_SHORTCUT; + int browser_shortcut_index = model_->Add(browser_shortcut); + EXPECT_EQ(1, browser_shortcut_index); + + // App items should be after the browser shortcut. + ShelfItem item; + item.type = TYPE_APP; + int platform_app_index1 = model_->Add(item); + EXPECT_EQ(2, platform_app_index1); + + // Add another platform app item, it should follow first. + int platform_app_index2 = model_->Add(item); + EXPECT_EQ(3, platform_app_index2); + + // APP_SHORTCUT priority is higher than PLATFORM_APP but same as + // BROWSER_SHORTCUT. So APP_SHORTCUT is located after BROWSER_SHORCUT. + item.type = TYPE_APP_SHORTCUT; + int app_shortcut_index1 = model_->Add(item); + EXPECT_EQ(2, app_shortcut_index1); + + item.type = TYPE_APP_SHORTCUT; + int app_shortcut_index2 = model_->Add(item); + EXPECT_EQ(3, app_shortcut_index2); + + // Check that AddAt() figures out the correct indexes for app shortcuts. + // APP_SHORTCUT and BROWSER_SHORTCUT has the same weight. + // So APP_SHORTCUT is located at index 0. And, BROWSER_SHORTCUT is located at + // index 1. + item.type = TYPE_APP_SHORTCUT; + int app_shortcut_index3 = model_->AddAt(1, item); + EXPECT_EQ(1, app_shortcut_index3); + + item.type = TYPE_APP_SHORTCUT; + int app_shortcut_index4 = model_->AddAt(6, item); + EXPECT_EQ(5, app_shortcut_index4); + + item.type = TYPE_APP_SHORTCUT; + int app_shortcut_index5 = model_->AddAt(3, item); + EXPECT_EQ(3, app_shortcut_index5); + + // Before there are any panels, no icons should be right aligned. + EXPECT_EQ(model_->item_count(), model_->FirstPanelIndex()); + + // Check that AddAt() figures out the correct indexes for apps and panels. + item.type = TYPE_APP; + int platform_app_index3 = model_->AddAt(3, item); + EXPECT_EQ(7, platform_app_index3); + + item.type = TYPE_APP_PANEL; + int app_panel_index1 = model_->AddAt(2, item); + EXPECT_EQ(10, app_panel_index1); + + item.type = TYPE_APP; + int platform_app_index4 = model_->AddAt(11, item); + EXPECT_EQ(10, platform_app_index4); + + item.type = TYPE_APP_PANEL; + int app_panel_index2 = model_->AddAt(12, item); + EXPECT_EQ(12, app_panel_index2); + + item.type = TYPE_APP; + int platform_app_index5 = model_->AddAt(7, item); + EXPECT_EQ(7, platform_app_index5); + + item.type = TYPE_APP_PANEL; + int app_panel_index3 = model_->AddAt(13, item); + EXPECT_EQ(13, app_panel_index3); + + // Right aligned index should be the first app panel index. + EXPECT_EQ(12, model_->FirstPanelIndex()); + + EXPECT_EQ(TYPE_BROWSER_SHORTCUT, model_->items()[2].type); + EXPECT_EQ(TYPE_APP_LIST, model_->items()[0].type); +} + +// Test that the indexes for the running applications are properly determined. +TEST_F(ShelfModelTest, FirstRunningAppIndex) { + // Insert the browser shortcut at index 1 and check that the running + // application index would be behind it. + ShelfItem item; + item.type = TYPE_BROWSER_SHORTCUT; + EXPECT_EQ(1, model_->Add(item)); + EXPECT_EQ(2, model_->FirstRunningAppIndex()); + + // Insert a panel application at the end and check that the running + // application index would be at / before the application panel. + item.type = TYPE_APP_PANEL; + EXPECT_EQ(2, model_->Add(item)); + EXPECT_EQ(2, model_->FirstRunningAppIndex()); + + // Insert an application shortcut and make sure that the running application + // index would be behind it. + item.type = TYPE_APP_SHORTCUT; + EXPECT_EQ(2, model_->Add(item)); + EXPECT_EQ(3, model_->FirstRunningAppIndex()); + + // Insert a two app items and check the first running app index. + item.type = TYPE_APP; + EXPECT_EQ(3, model_->Add(item)); + EXPECT_EQ(3, model_->FirstRunningAppIndex()); + EXPECT_EQ(4, model_->Add(item)); + EXPECT_EQ(3, model_->FirstRunningAppIndex()); +} + +// Assertions around id generation and usage. +TEST_F(ShelfModelTest, ShelfIDTests) { + // Get the next to use ID counter. + ShelfID id = model_->next_id(); + + // Calling this function multiple times does not change the returned ID. + EXPECT_EQ(model_->next_id(), id); + + // Check that when we reserve a value it will be the previously retrieved ID, + // but it will not change the item count and retrieving the next ID should + // produce something new. + EXPECT_EQ(model_->reserve_external_id(), id); + EXPECT_EQ(1, model_->item_count()); + ShelfID id2 = model_->next_id(); + EXPECT_NE(id2, id); + + // Adding another item to the list should also produce a new ID. + ShelfItem item; + item.type = TYPE_APP; + model_->Add(item); + EXPECT_NE(model_->next_id(), id2); +} + +// This verifies that converting an existing item into a lower weight category +// (e.g. shortcut to running but not pinned app) will move it to the proper +// location. See crbug.com/248769. +TEST_F(ShelfModelTest, CorrectMoveItemsWhenStateChange) { + // The first item is the app list and last item is the browser. + ShelfItem browser_shortcut; + browser_shortcut.type = TYPE_BROWSER_SHORTCUT; + int browser_shortcut_index = model_->Add(browser_shortcut); + EXPECT_EQ(TYPE_APP_LIST, model_->items()[0].type); + EXPECT_EQ(1, browser_shortcut_index); + + // Add three shortcuts. They should all be moved between the two. + ShelfItem item; + item.type = TYPE_APP_SHORTCUT; + int app1_index = model_->Add(item); + EXPECT_EQ(2, app1_index); + int app2_index = model_->Add(item); + EXPECT_EQ(3, app2_index); + int app3_index = model_->Add(item); + EXPECT_EQ(4, app3_index); + + // Now change the type of the second item and make sure that it is moving + // behind the shortcuts. + item.type = TYPE_APP; + model_->Set(app2_index, item); + + // The item should have moved in front of the app launcher. + EXPECT_EQ(TYPE_APP, model_->items()[4].type); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_tooltip_manager.cc b/ash/common/shelf/shelf_tooltip_manager.cc new file mode 100644 index 0000000..5741bc2a --- /dev/null +++ b/ash/common/shelf/shelf_tooltip_manager.cc
@@ -0,0 +1,263 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_tooltip_manager.h" + +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/bind.h" +#include "base/strings/string16.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "ui/base/material_design/material_design_controller.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +const int kTooltipAppearanceDelay = 1000; // msec + +// Tooltip layout constants. + +// Shelf item tooltip height. +const int kTooltipHeight = 24; + +// The maximum width of the tooltip bubble. Borrowed the value from +// ash/tooltip/tooltip_controller.cc +const int kTooltipMaxWidth = 250; + +// Shelf item tooltip internal text margins. +const int kTooltipTopBottomMargin = 4; +const int kTooltipLeftRightMargin = 8; + +// The offset for the tooltip bubble - making sure that the bubble is spaced +// with a fixed gap. The gap is accounted for by the transparent arrow in the +// bubble and an additional 1px padding for the shelf item views. +const int kArrowTopBottomOffset = 1; +const int kArrowLeftRightOffset = 1; + +// Tooltip's border interior thickness that defines its minimum height. +const int kBorderInteriorThickness = kTooltipHeight / 2; + +} // namespace + +// The implementation of tooltip of the launcher. +class ShelfTooltipManager::ShelfTooltipBubble + : public views::BubbleDialogDelegateView { + public: + ShelfTooltipBubble(views::View* anchor, + views::BubbleBorder::Arrow arrow, + const base::string16& text) + : views::BubbleDialogDelegateView(anchor, arrow) { + set_close_on_deactivate(false); + set_can_activate(false); + set_accept_events(false); + set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin)); + set_shadow(views::BubbleBorder::NO_ASSETS); + SetLayoutManager(new views::FillLayout()); + views::Label* label = new views::Label(text); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + ui::NativeTheme* theme = anchor->GetWidget()->GetNativeTheme(); + label->SetEnabledColor( + theme->GetSystemColor(ui::NativeTheme::kColorId_TooltipText)); + SkColor background_color = + theme->GetSystemColor(ui::NativeTheme::kColorId_TooltipBackground); + set_color(background_color); + label->SetBackgroundColor(background_color); + // The background is not opaque, so we can't do subpixel rendering. + label->SetSubpixelRenderingEnabled(false); + AddChildView(label); + + gfx::Insets insets(kArrowTopBottomOffset, kArrowLeftRightOffset); + // Adjust the anchor location for asymmetrical borders of shelf item. + if (anchor->border()) + insets += anchor->border()->GetInsets(); + if (ui::MaterialDesignController::IsSecondaryUiMaterial()) + insets += gfx::Insets(-kBubblePaddingHorizontalBottom); + set_anchor_view_insets(insets); + + views::BubbleDialogDelegateView::CreateBubble(this); + if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) { + // These must both be called after CreateBubble. + SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT); + SetBorderInteriorThickness(kBorderInteriorThickness); + } + } + + private: + // BubbleDialogDelegateView overrides: + gfx::Size GetPreferredSize() const override { + const gfx::Size size = BubbleDialogDelegateView::GetPreferredSize(); + const int kTooltipMinHeight = kTooltipHeight - 2 * kTooltipTopBottomMargin; + return gfx::Size(std::min(size.width(), kTooltipMaxWidth), + std::max(size.height(), kTooltipMinHeight)); + } + + void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, + views::Widget* bubble_widget) const override { + // Place the bubble in the same display as the anchor. + WmWindow::Get(anchor_widget()->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + bubble_widget, kShellWindowId_SettingBubbleContainer, params); + } + + int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; } + + DISALLOW_COPY_AND_ASSIGN(ShelfTooltipBubble); +}; + +ShelfTooltipManager::ShelfTooltipManager(ShelfView* shelf_view) + : timer_delay_(kTooltipAppearanceDelay), + shelf_view_(shelf_view), + bubble_(nullptr), + weak_factory_(this) { + shelf_view_->wm_shelf()->AddObserver(this); + WmShell::Get()->AddPointerWatcher(this, + views::PointerWatcherEventTypes::BASIC); +} + +ShelfTooltipManager::~ShelfTooltipManager() { + WmShell::Get()->RemovePointerWatcher(this); + shelf_view_->wm_shelf()->RemoveObserver(this); + WmWindow* window = nullptr; + if (shelf_view_->GetWidget()) + window = WmWindow::Get(shelf_view_->GetWidget()->GetNativeWindow()); + if (window) + window->RemoveLimitedPreTargetHandler(this); +} + +void ShelfTooltipManager::Init() { + WmWindow* window = WmWindow::Get(shelf_view_->GetWidget()->GetNativeWindow()); + window->AddLimitedPreTargetHandler(this); +} + +void ShelfTooltipManager::Close() { + timer_.Stop(); + if (bubble_) + bubble_->GetWidget()->Close(); + bubble_ = nullptr; +} + +bool ShelfTooltipManager::IsVisible() const { + return bubble_ && bubble_->GetWidget()->IsVisible(); +} + +views::View* ShelfTooltipManager::GetCurrentAnchorView() const { + return bubble_ ? bubble_->GetAnchorView() : nullptr; +} + +void ShelfTooltipManager::ShowTooltip(views::View* view) { + timer_.Stop(); + if (bubble_) { + // Cancel the hiding animation to hide the old bubble immediately. + WmWindow::Get(bubble_->GetWidget()->GetNativeWindow()) + ->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); + Close(); + } + + if (!ShouldShowTooltipForView(view)) + return; + + views::BubbleBorder::Arrow arrow = views::BubbleBorder::Arrow::NONE; + switch (shelf_view_->wm_shelf()->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + arrow = views::BubbleBorder::BOTTOM_CENTER; + break; + case SHELF_ALIGNMENT_LEFT: + arrow = views::BubbleBorder::LEFT_CENTER; + break; + case SHELF_ALIGNMENT_RIGHT: + arrow = views::BubbleBorder::RIGHT_CENTER; + break; + } + + base::string16 text = shelf_view_->GetTitleForView(view); + bubble_ = new ShelfTooltipBubble(view, arrow, text); + WmWindow* window = WmWindow::Get(bubble_->GetWidget()->GetNativeWindow()); + window->SetVisibilityAnimationType( + ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); + window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE); + bubble_->GetWidget()->Show(); +} + +void ShelfTooltipManager::ShowTooltipWithDelay(views::View* view) { + if (ShouldShowTooltipForView(view)) { + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timer_delay_), + base::Bind(&ShelfTooltipManager::ShowTooltip, + weak_factory_.GetWeakPtr(), view)); + } +} + +void ShelfTooltipManager::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + // Close on any press events inside or outside the tooltip. + if (event.type() == ui::ET_POINTER_DOWN) + Close(); +} + +void ShelfTooltipManager::OnMouseEvent(ui::MouseEvent* event) { + if (event->type() == ui::ET_MOUSE_EXITED) { + Close(); + return; + } + + if (event->type() != ui::ET_MOUSE_MOVED) + return; + + gfx::Point point = event->location(); + views::View::ConvertPointFromWidget(shelf_view_, &point); + views::View* view = shelf_view_->GetTooltipHandlerForPoint(point); + const bool should_show = ShouldShowTooltipForView(view); + + timer_.Stop(); + if (IsVisible() && should_show && bubble_->GetAnchorView() != view) + ShowTooltip(view); + else if (!IsVisible() && should_show) + ShowTooltipWithDelay(view); + else if (IsVisible() && shelf_view_->ShouldHideTooltip(point)) + Close(); +} + +void ShelfTooltipManager::WillChangeVisibilityState( + ShelfVisibilityState new_state) { + if (new_state == SHELF_HIDDEN) + Close(); +} + +void ShelfTooltipManager::OnAutoHideStateChanged(ShelfAutoHideState new_state) { + if (new_state == SHELF_AUTO_HIDE_HIDDEN) { + timer_.Stop(); + // AutoHide state change happens during an event filter, so immediate close + // may cause a crash in the HandleMouseEvent() after the filter. So we just + // schedule the Close here. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr())); + } +} + +bool ShelfTooltipManager::ShouldShowTooltipForView(views::View* view) { + WmShelf* shelf = shelf_view_ ? shelf_view_->wm_shelf() : nullptr; + return shelf && shelf_view_->ShouldShowTooltipForView(view) && + (shelf->GetVisibilityState() == SHELF_VISIBLE || + (shelf->GetVisibilityState() == SHELF_AUTO_HIDE && + shelf->GetAutoHideState() == SHELF_AUTO_HIDE_SHOWN)); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_tooltip_manager.h b/ash/common/shelf/shelf_tooltip_manager.h new file mode 100644 index 0000000..c68a1b0 --- /dev/null +++ b/ash/common/shelf/shelf_tooltip_manager.h
@@ -0,0 +1,90 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_TOOLTIP_MANAGER_H_ +#define ASH_COMMON_SHELF_SHELF_TOOLTIP_MANAGER_H_ + +#include "ash/ash_export.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" +#include "ui/events/event_handler.h" +#include "ui/views/pointer_watcher.h" + +namespace views { +class BubbleDialogDelegateView; +class View; +} + +namespace ash { +class ShelfView; + +namespace test { +class ShelfTooltipManagerTest; +class ShelfViewTest; +} + +// ShelfTooltipManager manages the tooltip bubble that appears for shelf items. +class ASH_EXPORT ShelfTooltipManager : public ui::EventHandler, + public views::PointerWatcher, + public WmShelfObserver { + public: + explicit ShelfTooltipManager(ShelfView* shelf_view); + ~ShelfTooltipManager() override; + + // Initializes the tooltip manager once the shelf is shown. + void Init(); + + // Closes the tooltip. + void Close(); + + // Returns true if the tooltip is currently visible. + bool IsVisible() const; + + // Returns the view to which the tooltip bubble is anchored. May be null. + views::View* GetCurrentAnchorView() const; + + // Show the tooltip bubble for the specified view. + void ShowTooltip(views::View* view); + void ShowTooltipWithDelay(views::View* view); + + // Set the timer delay in ms for testing. + void set_timer_delay_for_test(int timer_delay) { timer_delay_ = timer_delay; } + + protected: + // ui::EventHandler overrides: + void OnMouseEvent(ui::MouseEvent* event) override; + + // views::PointerWatcher overrides: + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; + + // WmShelfObserver overrides: + void WillChangeVisibilityState(ShelfVisibilityState new_state) override; + void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; + + private: + class ShelfTooltipBubble; + friend class test::ShelfViewTest; + friend class test::ShelfTooltipManagerTest; + + // A helper function to check for shelf visibility and view validity. + bool ShouldShowTooltipForView(views::View* view); + + int timer_delay_; + base::OneShotTimer timer_; + + ShelfView* shelf_view_; + views::BubbleDialogDelegateView* bubble_; + + base::WeakPtrFactory<ShelfTooltipManager> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_TOOLTIP_MANAGER_H_
diff --git a/ash/common/shelf/shelf_tooltip_manager_unittest.cc b/ash/common/shelf/shelf_tooltip_manager_unittest.cc new file mode 100644 index 0000000..955301fd --- /dev/null +++ b/ash/common/shelf/shelf_tooltip_manager_unittest.cc
@@ -0,0 +1,246 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_tooltip_manager.h" + +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/test/test_shelf_item_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/shelf_view_test_api.h" +#include "base/memory/ptr_util.h" +#include "ui/events/event_constants.h" +#include "ui/events/test/event_generator.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace test { + +class ShelfTooltipManagerTest : public AshTestBase { + public: + ShelfTooltipManagerTest() {} + ~ShelfTooltipManagerTest() override {} + + void SetUp() override { + AshTestBase::SetUp(); + shelf_view_ = GetPrimaryShelf()->GetShelfViewForTesting(); + tooltip_manager_ = test::ShelfViewTestAPI(shelf_view_).tooltip_manager(); + tooltip_manager_->set_timer_delay_for_test(0); + } + + bool IsTimerRunning() { return tooltip_manager_->timer_.IsRunning(); } + views::Widget* GetTooltip() { return tooltip_manager_->bubble_->GetWidget(); } + + std::unique_ptr<views::Widget> CreateTestWidget() { + std::unique_ptr<views::Widget> widget = base::MakeUnique<views::Widget>(); + views::Widget::InitParams params; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.context = CurrentContext(); + widget->Init(params); + widget->Show(); + return widget; + } + + protected: + ShelfView* shelf_view_; + ShelfTooltipManager* tooltip_manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManagerTest); +}; + +TEST_F(ShelfTooltipManagerTest, ShowTooltip) { + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + EXPECT_TRUE(tooltip_manager_->IsVisible()); + EXPECT_FALSE(IsTimerRunning()); +} + +TEST_F(ShelfTooltipManagerTest, ShowTooltipWithDelay) { + // ShowTooltipWithDelay should start the timer instead of showing immediately. + tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + EXPECT_TRUE(IsTimerRunning()); + // TODO: Test that the delayed tooltip is shown, without flaky failures. +} + +TEST_F(ShelfTooltipManagerTest, DoNotShowForInvalidView) { + // The manager should not show or start the timer for a null view. + tooltip_manager_->ShowTooltip(nullptr); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + tooltip_manager_->ShowTooltipWithDelay(nullptr); + EXPECT_FALSE(IsTimerRunning()); + + // The manager should not show or start the timer for a non-shelf view. + views::View view; + tooltip_manager_->ShowTooltip(&view); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + tooltip_manager_->ShowTooltipWithDelay(&view); + EXPECT_FALSE(IsTimerRunning()); + + // The manager should start the timer for a view on the shelf. + ShelfModel* model = shelf_view_->model(); + ShelfItem item; + item.type = TYPE_APP_SHORTCUT; + const int index = model->Add(item); + const ShelfID id = model->items()[index].id; + model->SetShelfItemDelegate(id, + base::MakeUnique<TestShelfItemDelegate>(nullptr)); + // Note: There's no easy way to correlate shelf a model index/id to its view. + tooltip_manager_->ShowTooltipWithDelay( + shelf_view_->child_at(shelf_view_->child_count() - 1)); + EXPECT_TRUE(IsTimerRunning()); + + // Removing the view won't stop the timer, but the tooltip shouldn't be shown. + model->RemoveItemAt(index); + EXPECT_TRUE(IsTimerRunning()); + RunAllPendingInMessageLoop(); + EXPECT_FALSE(IsTimerRunning()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); +} + +TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsHidden) { + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + + // Create a full-screen window to hide the shelf. + std::unique_ptr<views::Widget> widget = CreateTestWidget(); + widget->SetFullscreen(true); + + // Once the shelf is hidden, the tooltip should be invisible. + ASSERT_EQ(SHELF_HIDDEN, GetPrimaryShelf()->GetVisibilityState()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // Do not show the view if the shelf is hidden. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // ShowTooltipWithDelay doesn't even start the timer for the hidden shelf. + tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); + EXPECT_FALSE(IsTimerRunning()); +} + +TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHideHidden) { + // Create a visible window so auto-hide behavior can actually hide the shelf. + std::unique_ptr<views::Widget> widget = CreateTestWidget(); + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + + GetPrimaryShelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + GetPrimaryShelf()->UpdateAutoHideState(); + ASSERT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, + GetPrimaryShelf()->auto_hide_behavior()); + ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); + + // Tooltip visibility change for auto hide may take time. + EXPECT_TRUE(tooltip_manager_->IsVisible()); + RunAllPendingInMessageLoop(); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // Do not show the view if the shelf is hidden. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // ShowTooltipWithDelay doesn't even run the timer for the hidden shelf. + tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); + EXPECT_FALSE(IsTimerRunning()); + + // Close the window to show the auto-hide shelf; tooltips should now show. + widget.reset(); + GetPrimaryShelf()->UpdateAutoHideState(); + ASSERT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, + GetPrimaryShelf()->auto_hide_behavior()); + ASSERT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); + + // The tooltip should show for an auto-hide-shown shelf. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + EXPECT_TRUE(tooltip_manager_->IsVisible()); + + // ShowTooltipWithDelay should run the timer for an auto-hide-shown shelf. + tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); + EXPECT_TRUE(IsTimerRunning()); +} + +TEST_F(ShelfTooltipManagerTest, HideForEvents) { + // TODO: investigate failure in mash. http://crbug.com/695563. + if (WmShell::Get()->IsRunningInMash()) + return; + + ui::test::EventGenerator& generator = GetEventGenerator(); + gfx::Rect shelf_bounds = shelf_view_->GetBoundsInScreen(); + + // Should hide if the mouse exits the shelf area. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.MoveMouseTo(shelf_bounds.CenterPoint()); + generator.SendMouseExit(); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // Should hide if the mouse is pressed in the shelf area. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.MoveMouseTo(shelf_bounds.CenterPoint()); + generator.PressLeftButton(); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // Should hide for touch events in the shelf. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.set_current_location(shelf_bounds.CenterPoint()); + generator.PressTouch(); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + + // Should hide for gesture events in the shelf. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.GestureTapDownAndUp(shelf_bounds.CenterPoint()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); +} + +TEST_F(ShelfTooltipManagerTest, HideForExternalEvents) { + // TODO: investigate failure in mash. http://crbug.com/695563. + if (WmShell::Get()->IsRunningInMash()) + return; + + ui::test::EventGenerator& generator = GetEventGenerator(); + + // Should hide for touches outside the shelf. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.set_current_location(gfx::Point()); + generator.PressTouch(); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + generator.ReleaseTouch(); + + // Should hide for touch events on the tooltip. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.set_current_location( + GetTooltip()->GetWindowBoundsInScreen().CenterPoint()); + generator.PressTouch(); + EXPECT_FALSE(tooltip_manager_->IsVisible()); + generator.ReleaseTouch(); + + // Should hide for gestures outside the shelf. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.GestureTapDownAndUp(gfx::Point()); + EXPECT_FALSE(tooltip_manager_->IsVisible()); +} + +TEST_F(ShelfTooltipManagerTest, DoNotHideForKeyEvents) { + ui::test::EventGenerator& generator = GetEventGenerator(); + + // Should not hide for key events. + tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); + ASSERT_TRUE(tooltip_manager_->IsVisible()); + generator.PressKey(ui::VKEY_A, ui::EF_NONE); + EXPECT_TRUE(tooltip_manager_->IsVisible()); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/shelf/shelf_view.cc b/ash/common/shelf/shelf_view.cc new file mode 100644 index 0000000..c46b168b --- /dev/null +++ b/ash/common/shelf/shelf_view.cc
@@ -0,0 +1,1779 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_view.h" + +#include <algorithm> +#include <memory> + +#include "ash/common/ash_constants.h" +#include "ash/common/drag_drop/drag_image_view.h" +#include "ash/common/scoped_root_window_for_new_windows.h" +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/overflow_bubble.h" +#include "ash/common/shelf/overflow_bubble_view.h" +#include "ash/common/shelf/overflow_button.h" +#include "ash/common/shelf/shelf_application_menu_model.h" +#include "ash/common/shelf/shelf_button.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shell_delegate.h" +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/auto_reset.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animator.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/events/event_utils.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/point.h" +#include "ui/views/animation/bounds_animator.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/menu/menu_model_adapter.h" +#include "ui/views/controls/menu/menu_runner.h" +#include "ui/views/focus/focus_search.h" +#include "ui/views/view_model.h" +#include "ui/views/view_model_utils.h" +#include "ui/views/widget/widget.h" +#include "ui/wm/core/coordinate_conversion.h" + +using gfx::Animation; +using views::View; + +namespace ash { + +const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM = 0; +const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT = 1; +const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT = 2; +const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT = 3; + +// Default amount content is inset on the left edge. +const int kDefaultLeadingInset = 8; + +// The proportion of the shelf space reserved for non-panel icons. Panels +// may flow into this space but will be put into the overflow bubble if there +// is contention for the space. +const float kReservedNonPanelIconProportion = 0.67f; + +// The distance of the cursor from the outer rim of the shelf before it +// separates. +const int kRipOffDistance = 48; + +// The rip off drag and drop proxy image should get scaled by this factor. +const float kDragAndDropProxyScale = 1.5f; + +// The opacity represents that this partially disappeared item will get removed. +const float kDraggedImageOpacity = 0.5f; + +namespace { + +// A class to temporarily disable a given bounds animator. +class BoundsAnimatorDisabler { + public: + explicit BoundsAnimatorDisabler(views::BoundsAnimator* bounds_animator) + : old_duration_(bounds_animator->GetAnimationDuration()), + bounds_animator_(bounds_animator) { + bounds_animator_->SetAnimationDuration(1); + } + + ~BoundsAnimatorDisabler() { + bounds_animator_->SetAnimationDuration(old_duration_); + } + + private: + // The previous animation duration. + int old_duration_; + // The bounds animator which gets used. + views::BoundsAnimator* bounds_animator_; + + DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorDisabler); +}; + +// Custom FocusSearch used to navigate the shelf in the order items are in +// the ViewModel. +class ShelfFocusSearch : public views::FocusSearch { + public: + explicit ShelfFocusSearch(views::ViewModel* view_model) + : FocusSearch(nullptr, true, true), view_model_(view_model) {} + ~ShelfFocusSearch() override {} + + // views::FocusSearch overrides: + View* FindNextFocusableView(View* starting_view, + bool reverse, + Direction direction, + bool check_starting_view, + views::FocusTraversable** focus_traversable, + View** focus_traversable_view) override { + int index = view_model_->GetIndexOfView(starting_view); + if (index == -1) + return view_model_->view_at(0); + + if (reverse) { + --index; + if (index < 0) + index = view_model_->view_size() - 1; + } else { + ++index; + if (index >= view_model_->view_size()) + index = 0; + } + return view_model_->view_at(index); + } + + private: + views::ViewModel* view_model_; + + DISALLOW_COPY_AND_ASSIGN(ShelfFocusSearch); +}; + +// AnimationDelegate used when inserting a new item. This steadily increases the +// opacity of the layer as the animation progress. +class FadeInAnimationDelegate : public gfx::AnimationDelegate { + public: + explicit FadeInAnimationDelegate(views::View* view) : view_(view) {} + ~FadeInAnimationDelegate() override {} + + // AnimationDelegate overrides: + void AnimationProgressed(const Animation* animation) override { + view_->layer()->SetOpacity(animation->GetCurrentValue()); + view_->layer()->ScheduleDraw(); + } + void AnimationEnded(const Animation* animation) override { + view_->layer()->SetOpacity(1.0f); + view_->layer()->ScheduleDraw(); + } + void AnimationCanceled(const Animation* animation) override { + view_->layer()->SetOpacity(1.0f); + view_->layer()->ScheduleDraw(); + } + + private: + views::View* view_; + + DISALLOW_COPY_AND_ASSIGN(FadeInAnimationDelegate); +}; + +void ReflectItemStatus(const ShelfItem& item, ShelfButton* button) { + switch (item.status) { + case STATUS_CLOSED: + button->ClearState(ShelfButton::STATE_ACTIVE); + button->ClearState(ShelfButton::STATE_RUNNING); + button->ClearState(ShelfButton::STATE_ATTENTION); + break; + case STATUS_RUNNING: + button->ClearState(ShelfButton::STATE_ACTIVE); + button->AddState(ShelfButton::STATE_RUNNING); + button->ClearState(ShelfButton::STATE_ATTENTION); + break; + case STATUS_ACTIVE: + button->AddState(ShelfButton::STATE_ACTIVE); + button->ClearState(ShelfButton::STATE_RUNNING); + button->ClearState(ShelfButton::STATE_ATTENTION); + break; + case STATUS_ATTENTION: + button->ClearState(ShelfButton::STATE_ACTIVE); + button->ClearState(ShelfButton::STATE_RUNNING); + button->AddState(ShelfButton::STATE_ATTENTION); + break; + } +} + +} // namespace + +// AnimationDelegate used when deleting an item. This steadily decreased the +// opacity of the layer as the animation progress. +class ShelfView::FadeOutAnimationDelegate : public gfx::AnimationDelegate { + public: + FadeOutAnimationDelegate(ShelfView* host, views::View* view) + : shelf_view_(host), view_(view) {} + ~FadeOutAnimationDelegate() override {} + + // AnimationDelegate overrides: + void AnimationProgressed(const Animation* animation) override { + view_->layer()->SetOpacity(1 - animation->GetCurrentValue()); + view_->layer()->ScheduleDraw(); + } + void AnimationEnded(const Animation* animation) override { + shelf_view_->OnFadeOutAnimationEnded(); + } + void AnimationCanceled(const Animation* animation) override {} + + private: + ShelfView* shelf_view_; + std::unique_ptr<views::View> view_; + + DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate); +}; + +// AnimationDelegate used to trigger fading an element in. When an item is +// inserted this delegate is attached to the animation that expands the size of +// the item. When done it kicks off another animation to fade the item in. +class ShelfView::StartFadeAnimationDelegate : public gfx::AnimationDelegate { + public: + StartFadeAnimationDelegate(ShelfView* host, views::View* view) + : shelf_view_(host), view_(view) {} + ~StartFadeAnimationDelegate() override {} + + // AnimationDelegate overrides: + void AnimationEnded(const Animation* animation) override { + shelf_view_->FadeIn(view_); + } + void AnimationCanceled(const Animation* animation) override { + view_->layer()->SetOpacity(1.0f); + } + + private: + ShelfView* shelf_view_; + views::View* view_; + + DISALLOW_COPY_AND_ASSIGN(StartFadeAnimationDelegate); +}; + +// static +const int ShelfView::kMinimumDragDistance = 8; + +ShelfView::ShelfView(ShelfModel* model, + ShelfDelegate* delegate, + WmShelf* wm_shelf, + ShelfWidget* shelf_widget) + : model_(model), + delegate_(delegate), + wm_shelf_(wm_shelf), + shelf_widget_(shelf_widget), + view_model_(new views::ViewModel), + first_visible_index_(0), + last_visible_index_(-1), + overflow_button_(nullptr), + owner_overflow_bubble_(nullptr), + tooltip_(this), + drag_pointer_(NONE), + drag_view_(nullptr), + start_drag_index_(-1), + context_menu_id_(0), + leading_inset_(kDefaultLeadingInset), + cancelling_drag_model_changed_(false), + last_hidden_index_(0), + closing_event_time_(base::TimeTicks()), + drag_and_drop_item_pinned_(false), + drag_and_drop_shelf_id_(0), + drag_replaced_view_(nullptr), + dragged_off_shelf_(false), + snap_back_from_rip_off_view_(nullptr), + overflow_mode_(false), + main_shelf_(nullptr), + dragged_off_from_overflow_to_shelf_(false), + is_repost_event_on_same_item_(false), + last_pressed_index_(-1) { + DCHECK(model_); + DCHECK(delegate_); + DCHECK(wm_shelf_); + DCHECK(shelf_widget_); + bounds_animator_.reset(new views::BoundsAnimator(this)); + bounds_animator_->AddObserver(this); + set_context_menu_controller(this); + focus_search_.reset(new ShelfFocusSearch(view_model_.get())); +} + +ShelfView::~ShelfView() { + bounds_animator_->RemoveObserver(this); + model_->RemoveObserver(this); +} + +void ShelfView::Init() { + model_->AddObserver(this); + + const ShelfItems& items(model_->items()); + for (ShelfItems::const_iterator i = items.begin(); i != items.end(); ++i) { + views::View* child = CreateViewForItem(*i); + child->SetPaintToLayer(); + view_model_->Add(child, static_cast<int>(i - items.begin())); + AddChildView(child); + } + overflow_button_ = new OverflowButton(this, wm_shelf_); + overflow_button_->set_context_menu_controller(this); + ConfigureChildView(overflow_button_); + AddChildView(overflow_button_); + + // We'll layout when our bounds change. +} + +void ShelfView::OnShelfAlignmentChanged() { + overflow_button_->OnShelfAlignmentChanged(); + LayoutToIdealBounds(); + for (int i = 0; i < view_model_->view_size(); ++i) { + if (i >= first_visible_index_ && i <= last_visible_index_) + view_model_->view_at(i)->Layout(); + } + tooltip_.Close(); + if (overflow_bubble_) + overflow_bubble_->Hide(); + // For crbug.com/587931, because AppListButton layout logic is in OnPaint. + AppListButton* app_list_button = GetAppListButton(); + if (app_list_button) + app_list_button->SchedulePaint(); +} + +gfx::Rect ShelfView::GetIdealBoundsOfItemIcon(ShelfID id) { + int index = model_->ItemIndexByID(id); + if (index == -1) + return gfx::Rect(); + // Map all items from overflow area to the overflow button. Note that the + // section between last_index_hidden_ and model_->FirstPanelIndex() is the + // list of invisible panel items. However, these items are currently nowhere + // represented and get dropped instead - see (crbug.com/378907). As such there + // is no way to address them or place them. We therefore move them over the + // overflow button. + if (index > last_visible_index_ && index < model_->FirstPanelIndex()) + index = last_visible_index_ + 1; + const gfx::Rect& ideal_bounds(view_model_->ideal_bounds(index)); + DCHECK_NE(TYPE_APP_LIST, model_->items()[index].type); + views::View* view = view_model_->view_at(index); + CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); + ShelfButton* button = static_cast<ShelfButton*>(view); + gfx::Rect icon_bounds = button->GetIconBounds(); + return gfx::Rect(GetMirroredXWithWidthInView( + ideal_bounds.x() + icon_bounds.x(), icon_bounds.width()), + ideal_bounds.y() + icon_bounds.y(), icon_bounds.width(), + icon_bounds.height()); +} + +void ShelfView::UpdatePanelIconPosition(ShelfID id, + const gfx::Point& midpoint) { + int current_index = model_->ItemIndexByID(id); + int first_panel_index = model_->FirstPanelIndex(); + if (current_index < first_panel_index) + return; + + gfx::Point midpoint_in_view(GetMirroredXInView(midpoint.x()), midpoint.y()); + int target_index = current_index; + while ( + target_index > first_panel_index && + wm_shelf_->PrimaryAxisValue(view_model_->ideal_bounds(target_index).x(), + view_model_->ideal_bounds(target_index).y()) > + wm_shelf_->PrimaryAxisValue(midpoint_in_view.x(), + midpoint_in_view.y())) { + --target_index; + } + while (target_index < view_model_->view_size() - 1 && + wm_shelf_->PrimaryAxisValue( + view_model_->ideal_bounds(target_index).right(), + view_model_->ideal_bounds(target_index).bottom()) < + wm_shelf_->PrimaryAxisValue(midpoint_in_view.x(), + midpoint_in_view.y())) { + ++target_index; + } + if (current_index != target_index) + model_->Move(current_index, target_index); +} + +bool ShelfView::IsShowingMenu() const { + return launcher_menu_runner_.get() && launcher_menu_runner_->IsRunning(); +} + +bool ShelfView::IsShowingOverflowBubble() const { + return overflow_bubble_.get() && overflow_bubble_->IsShowing(); +} + +AppListButton* ShelfView::GetAppListButton() const { + for (int i = 0; i < model_->item_count(); ++i) { + if (model_->items()[i].type == TYPE_APP_LIST) { + views::View* view = view_model_->view_at(i); + CHECK_EQ(AppListButton::kViewClassName, view->GetClassName()); + return static_cast<AppListButton*>(view); + } + } + + NOTREACHED() << "Applist button not found"; + return nullptr; +} + +bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) const { + gfx::Rect tooltip_bounds; + for (int i = 0; i < child_count(); ++i) { + const views::View* child = child_at(i); + if (child != overflow_button_ && ShouldShowTooltipForView(child)) + tooltip_bounds.Union(child->GetMirroredBounds()); + } + return !tooltip_bounds.Contains(cursor_location); +} + +bool ShelfView::ShouldShowTooltipForView(const views::View* view) const { + // TODO(msw): Push this app list state into ShelfItem::shows_tooltip. + if (view == GetAppListButton() && GetAppListButton()->is_showing_app_list()) + return false; + const ShelfItem* item = ShelfItemForView(view); + return item && item->shows_tooltip; +} + +base::string16 ShelfView::GetTitleForView(const views::View* view) const { + const ShelfItem* item = ShelfItemForView(view); + return item ? item->title : base::string16(); +} + +gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() { + gfx::Size preferred_size = GetPreferredSize(); + gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0); + ConvertPointToScreen(this, &origin); + return gfx::Rect(origin, preferred_size); +} + +void ShelfView::ButtonPressed(views::Button* sender, + const ui::Event& event, + views::InkDrop* ink_drop) { + if (sender == overflow_button_) { + ToggleOverflowBubble(); + shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender, + SHELF_ACTION_NONE); + return; + } + + // None of the checks in ShouldEventActivateButton() affects overflow button. + // So, it is safe to be checked after handling overflow button. + if (!ShouldEventActivateButton(sender, event)) + return; + + // Record the index for the last pressed shelf item. + last_pressed_index_ = view_model_->GetIndexOfView(sender); + DCHECK_LT(-1, last_pressed_index_); + + // Place new windows on the same display as the button. + WmWindow* window = WmWindow::Get(sender->GetWidget()->GetNativeWindow()); + scoped_root_window_for_new_windows_.reset( + new ScopedRootWindowForNewWindows(window->GetRootWindow())); + + // Slow down activation animations if shift key is pressed. + std::unique_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations; + if (event.IsShiftDown()) { + slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); + } + + // Collect usage statistics before we decide what to do with the click. + switch (model_->items()[last_pressed_index_].type) { + case TYPE_APP_SHORTCUT: + case TYPE_BROWSER_SHORTCUT: + case TYPE_APP: + WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_CLICK_ON_APP); + break; + + case TYPE_APP_LIST: + WmShell::Get()->RecordUserMetricsAction( + UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON); + break; + + case TYPE_APP_PANEL: + case TYPE_DIALOG: + break; + + case TYPE_UNDEFINED: + NOTREACHED() << "ShelfItemType must be set."; + break; + } + + const int64_t display_id = window->GetDisplayNearestWindow().id(); + ShelfAction performed_action = + model_->GetShelfItemDelegate(model_->items()[last_pressed_index_].id) + ->ItemSelected(event.type(), event.flags(), display_id, + LAUNCH_FROM_UNKNOWN); + + shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender, + performed_action); + + // For the app list menu no TRIGGERED ink drop effect is needed and it + // handles its own ACTIVATED/DEACTIVATED states. + if (performed_action == SHELF_ACTION_NEW_WINDOW_CREATED || + (performed_action != SHELF_ACTION_APP_LIST_SHOWN && + !ShowListMenuForView(model_->items()[last_pressed_index_], sender, event, + ink_drop))) { + ink_drop->AnimateToState(views::InkDropState::ACTION_TRIGGERED); + } + // Allow the menu to clear |scoped_root_window_for_new_windows_| during + // OnMenuClosed. + if (!IsShowingMenu()) + scoped_root_window_for_new_windows_.reset(); +} + +//////////////////////////////////////////////////////////////////////////////// +// ShelfView, FocusTraversable implementation: + +views::FocusSearch* ShelfView::GetFocusSearch() { + return focus_search_.get(); +} + +views::FocusTraversable* ShelfView::GetFocusTraversableParent() { + return parent()->GetFocusTraversable(); +} + +View* ShelfView::GetFocusTraversableParentView() { + return this; +} + +void ShelfView::CreateDragIconProxy( + const gfx::Point& location_in_screen_coordinates, + const gfx::ImageSkia& icon, + views::View* replaced_view, + const gfx::Vector2d& cursor_offset_from_center, + float scale_factor) { + drag_replaced_view_ = replaced_view; + WmWindow* root_window = + WmWindow::Get(drag_replaced_view_->GetWidget()->GetNativeWindow()) + ->GetRootWindow(); + drag_image_.reset(new DragImageView( + root_window, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE)); + drag_image_->SetImage(icon); + gfx::Size size = drag_image_->GetPreferredSize(); + size.set_width(size.width() * scale_factor); + size.set_height(size.height() * scale_factor); + drag_image_offset_ = gfx::Vector2d(size.width() / 2, size.height() / 2) + + cursor_offset_from_center; + gfx::Rect drag_image_bounds( + location_in_screen_coordinates - drag_image_offset_, size); + drag_image_->SetBoundsInScreen(drag_image_bounds); + drag_image_->SetWidgetVisible(true); +} + +void ShelfView::UpdateDragIconProxy( + const gfx::Point& location_in_screen_coordinates) { + // TODO(jennyz): Investigate why drag_image_ becomes null at this point per + // crbug.com/34722, while the app list item is still being dragged around. + if (drag_image_) { + drag_image_->SetScreenPosition(location_in_screen_coordinates - + drag_image_offset_); + } +} + +void ShelfView::DestroyDragIconProxy() { + drag_image_.reset(); + drag_image_offset_ = gfx::Vector2d(0, 0); +} + +bool ShelfView::StartDrag(const std::string& app_id, + const gfx::Point& location_in_screen_coordinates) { + // Bail if an operation is already going on - or the cursor is not inside. + // This could happen if mouse / touch operations overlap. + if (drag_and_drop_shelf_id_ || + !GetBoundsInScreen().Contains(location_in_screen_coordinates)) + return false; + + // If the AppsGridView (which was dispatching this event) was opened by our + // button, ShelfView dragging operations are locked and we have to unlock. + CancelDrag(-1); + drag_and_drop_item_pinned_ = false; + drag_and_drop_app_id_ = app_id; + drag_and_drop_shelf_id_ = + delegate_->GetShelfIDForAppID(drag_and_drop_app_id_); + // Check if the application is known and pinned - if not, we have to pin it so + // that we can re-arrange the shelf order accordingly. Note that items have + // to be pinned to give them the same (order) possibilities as a shortcut. + // When an item is dragged from overflow to shelf, IsShowingOverflowBubble() + // returns true. At this time, we don't need to pin the item. + if (!IsShowingOverflowBubble() && + (!drag_and_drop_shelf_id_ || !delegate_->IsAppPinned(app_id))) { + delegate_->PinAppWithID(app_id); + drag_and_drop_shelf_id_ = + delegate_->GetShelfIDForAppID(drag_and_drop_app_id_); + if (!drag_and_drop_shelf_id_) + return false; + drag_and_drop_item_pinned_ = true; + } + views::View* drag_and_drop_view = + view_model_->view_at(model_->ItemIndexByID(drag_and_drop_shelf_id_)); + DCHECK(drag_and_drop_view); + + // Since there is already an icon presented by the caller, we hide this item + // for now. That has to be done by reducing the size since the visibility will + // change once a regrouping animation is performed. + pre_drag_and_drop_size_ = drag_and_drop_view->size(); + drag_and_drop_view->SetSize(gfx::Size()); + + // First we have to center the mouse cursor over the item. + gfx::Point pt = drag_and_drop_view->GetBoundsInScreen().CenterPoint(); + views::View::ConvertPointFromScreen(drag_and_drop_view, &pt); + gfx::Point point_in_root = + wm::GetRootWindowAt(location_in_screen_coordinates) + ->ConvertPointFromScreen(location_in_screen_coordinates); + ui::MouseEvent event(ui::ET_MOUSE_PRESSED, pt, point_in_root, + ui::EventTimeForNow(), 0, 0); + PointerPressedOnButton(drag_and_drop_view, DRAG_AND_DROP, event); + + // Drag the item where it really belongs. + Drag(location_in_screen_coordinates); + return true; +} + +bool ShelfView::Drag(const gfx::Point& location_in_screen_coordinates) { + if (!drag_and_drop_shelf_id_ || + !GetBoundsInScreen().Contains(location_in_screen_coordinates)) + return false; + + gfx::Point pt = location_in_screen_coordinates; + views::View* drag_and_drop_view = + view_model_->view_at(model_->ItemIndexByID(drag_and_drop_shelf_id_)); + ConvertPointFromScreen(drag_and_drop_view, &pt); + gfx::Point point_in_root = + wm::GetRootWindowAt(location_in_screen_coordinates) + ->ConvertPointFromScreen(location_in_screen_coordinates); + ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, point_in_root, + ui::EventTimeForNow(), 0, 0); + PointerDraggedOnButton(drag_and_drop_view, DRAG_AND_DROP, event); + return true; +} + +void ShelfView::EndDrag(bool cancel) { + if (!drag_and_drop_shelf_id_) + return; + + views::View* drag_and_drop_view = + view_model_->view_at(model_->ItemIndexByID(drag_and_drop_shelf_id_)); + PointerReleasedOnButton(drag_and_drop_view, DRAG_AND_DROP, cancel); + + // Either destroy the temporarily created item - or - make the item visible. + if (drag_and_drop_item_pinned_ && cancel) { + delegate_->UnpinAppWithID(drag_and_drop_app_id_); + } else if (drag_and_drop_view) { + if (cancel) { + // When a hosted drag gets canceled, the item can remain in the same slot + // and it might have moved within the bounds. In that case the item need + // to animate back to its correct location. + AnimateToIdealBounds(); + } else { + drag_and_drop_view->SetSize(pre_drag_and_drop_size_); + } + } + + drag_and_drop_shelf_id_ = 0; +} + +bool ShelfView::ShouldEventActivateButton(View* view, const ui::Event& event) { + if (dragging()) + return false; + + // Ignore if we are already in a pointer event sequence started with a repost + // event on the same shelf item. See crbug.com/343005 for more detail. + if (is_repost_event_on_same_item_) + return false; + + // Don't activate the item twice on double-click. Otherwise the window starts + // animating open due to the first click, then immediately minimizes due to + // the second click. The user most likely intended to open or minimize the + // item once, not do both. + if (event.flags() & ui::EF_IS_DOUBLE_CLICK) + return false; + + // Ignore if this is a repost event on the last pressed shelf item. + int index = view_model_->GetIndexOfView(view); + if (index == -1) + return false; + return !IsRepostEvent(event) || last_pressed_index_ != index; +} + +void ShelfView::PointerPressedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event) { + if (drag_view_) + return; + + int index = view_model_->GetIndexOfView(view); + if (index == -1 || view_model_->view_size() <= 1) + return; // View is being deleted, ignore request. + + if (view == GetAppListButton()) + return; // View is not draggable, ignore request. + + // Only when the repost event occurs on the same shelf item, we should ignore + // the call in ShelfView::ButtonPressed(...). + is_repost_event_on_same_item_ = + IsRepostEvent(event) && (last_pressed_index_ == index); + + CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); + drag_view_ = static_cast<ShelfButton*>(view); + drag_origin_ = gfx::Point(event.x(), event.y()); + UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage", + wm_shelf_->SelectValueForShelfAlignment( + SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM, + SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT, + SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT), + SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT); +} + +void ShelfView::PointerDraggedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event) { + // To prepare all drag types (moving an item in the shelf and dragging off), + // we should check the x-axis and y-axis offset. + if (!dragging() && drag_view_ && + ((std::abs(event.x() - drag_origin_.x()) >= kMinimumDragDistance) || + (std::abs(event.y() - drag_origin_.y()) >= kMinimumDragDistance))) { + PrepareForDrag(pointer, event); + } + if (drag_pointer_ == pointer) + ContinueDrag(event); +} + +void ShelfView::PointerReleasedOnButton(views::View* view, + Pointer pointer, + bool canceled) { + is_repost_event_on_same_item_ = false; + + if (canceled) { + CancelDrag(-1); + } else if (drag_pointer_ == pointer) { + FinalizeRipOffDrag(false); + drag_pointer_ = NONE; + AnimateToIdealBounds(); + } + // If the drag pointer is NONE, no drag operation is going on and the + // drag_view can be released. + if (drag_pointer_ == NONE) + drag_view_ = nullptr; +} + +void ShelfView::LayoutToIdealBounds() { + if (bounds_animator_->IsAnimating()) { + AnimateToIdealBounds(); + return; + } + + IdealBounds ideal_bounds; + CalculateIdealBounds(&ideal_bounds); + views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); + overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds); +} + +void ShelfView::UpdateShelfItemBackground(SkColor color) { + GetAppListButton()->UpdateShelfItemBackground(color); + overflow_button_->UpdateShelfItemBackground(color); +} + +void ShelfView::UpdateAllButtonsVisibilityInOverflowMode() { + // The overflow button is not shown in overflow mode. + overflow_button_->SetVisible(false); + DCHECK_LT(last_visible_index_, view_model_->view_size()); + for (int i = 0; i < view_model_->view_size(); ++i) { + bool visible = i >= first_visible_index_ && i <= last_visible_index_; + // To track the dragging of |drag_view_| continuously, its visibility + // should be always true regardless of its position. + if (dragged_off_from_overflow_to_shelf_ && + view_model_->view_at(i) == drag_view_) + view_model_->view_at(i)->SetVisible(true); + else + view_model_->view_at(i)->SetVisible(visible); + } +} + +void ShelfView::CalculateIdealBounds(IdealBounds* bounds) const { + int available_size = wm_shelf_->PrimaryAxisValue(width(), height()); + DCHECK(model_->item_count() == view_model_->view_size()); + if (!available_size) + return; + + int first_panel_index = model_->FirstPanelIndex(); + int last_button_index = first_panel_index - 1; + + int x = 0; + int y = 0; + + int w = wm_shelf_->PrimaryAxisValue(kShelfButtonSize, width()); + int h = wm_shelf_->PrimaryAxisValue(height(), kShelfButtonSize); + for (int i = 0; i < view_model_->view_size(); ++i) { + if (i < first_visible_index_) { + view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0)); + continue; + } + + view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); + x = wm_shelf_->PrimaryAxisValue(x + w + kShelfButtonSpacing, x); + y = wm_shelf_->PrimaryAxisValue(y, y + h + kShelfButtonSpacing); + } + + if (is_overflow_mode()) { + const_cast<ShelfView*>(this)->UpdateAllButtonsVisibilityInOverflowMode(); + return; + } + + // Right aligned icons. + int end_position = available_size; + x = wm_shelf_->PrimaryAxisValue(end_position, 0); + y = wm_shelf_->PrimaryAxisValue(0, end_position); + for (int i = view_model_->view_size() - 1; i >= first_panel_index; --i) { + x = wm_shelf_->PrimaryAxisValue(x - w - kShelfButtonSpacing, x); + y = wm_shelf_->PrimaryAxisValue(y, y - h - kShelfButtonSpacing); + view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); + end_position = wm_shelf_->PrimaryAxisValue(x, y); + } + + // Icons on the left / top are guaranteed up to kLeftIconProportion of + // the available space. + int last_icon_position = + wm_shelf_->PrimaryAxisValue( + view_model_->ideal_bounds(last_button_index).right(), + view_model_->ideal_bounds(last_button_index).bottom()) + + kShelfButtonSpacing; + int reserved_icon_space = available_size * kReservedNonPanelIconProportion; + if (last_icon_position < reserved_icon_space) + end_position = last_icon_position; + else + end_position = std::max(end_position, reserved_icon_space); + + bounds->overflow_bounds.set_size( + gfx::Size(wm_shelf_->PrimaryAxisValue(w, width()), + wm_shelf_->PrimaryAxisValue(height(), h))); + + last_visible_index_ = + DetermineLastVisibleIndex(end_position - kShelfButtonSpacing); + last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1; + bool show_overflow = last_visible_index_ < last_button_index || + last_hidden_index_ >= first_panel_index; + + // Create Space for the overflow button + if (show_overflow) { + // The following code makes sure that platform apps icons (aligned to left / + // top) are favored over panel apps icons (aligned to right / bottom). + if (last_visible_index_ > 0 && last_visible_index_ < last_button_index) { + // This condition means that we will take one platform app and replace it + // with the overflow button and put the app in the overflow bubble. + // This happens when the space needed for platform apps exceeds the + // reserved area for non-panel icons, + // (i.e. |last_icon_position| > |reserved_icon_space|). + --last_visible_index_; + } else if (last_hidden_index_ >= first_panel_index && + last_hidden_index_ < view_model_->view_size() - 1) { + // This condition means that we will take a panel app icon and replace it + // with the overflow button. + // This happens when there is still room for platform apps in the reserved + // area for non-panel icons, + // (i.e. |last_icon_position| < |reserved_icon_space|). + ++last_hidden_index_; + } + } + + for (int i = 0; i < view_model_->view_size(); ++i) { + bool visible = i <= last_visible_index_ || i > last_hidden_index_; + // To receive drag event continuously from |drag_view_| during the dragging + // off from the shelf, don't make |drag_view_| invisible. It will be + // eventually invisible and removed from the |view_model_| by + // FinalizeRipOffDrag(). + if (dragged_off_shelf_ && view_model_->view_at(i) == drag_view_) + continue; + view_model_->view_at(i)->SetVisible(visible); + } + + overflow_button_->SetVisible(show_overflow); + if (show_overflow) { + DCHECK_NE(0, view_model_->view_size()); + if (last_visible_index_ == -1) { + x = 0; + y = 0; + } else { + x = wm_shelf_->PrimaryAxisValue( + view_model_->ideal_bounds(last_visible_index_).right(), + view_model_->ideal_bounds(last_visible_index_).x()); + y = wm_shelf_->PrimaryAxisValue( + view_model_->ideal_bounds(last_visible_index_).y(), + view_model_->ideal_bounds(last_visible_index_).bottom()); + } + + if (last_visible_index_ >= 0) { + // Add more space between last visible item and overflow button. + // Without this, two buttons look too close compared with other items. + x = wm_shelf_->PrimaryAxisValue(x + kShelfButtonSpacing, x); + y = wm_shelf_->PrimaryAxisValue(y, y + kShelfButtonSpacing); + } + + // Set all hidden panel icon positions to be on the overflow button. + for (int i = first_panel_index; i <= last_hidden_index_; ++i) + view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); + + bounds->overflow_bounds.set_x(x); + bounds->overflow_bounds.set_y(y); + if (overflow_bubble_.get() && overflow_bubble_->IsShowing()) + UpdateOverflowRange(overflow_bubble_->shelf_view()); + } else { + if (overflow_bubble_) + overflow_bubble_->Hide(); + } +} + +int ShelfView::DetermineLastVisibleIndex(int max_value) const { + int index = model_->FirstPanelIndex() - 1; + while (index >= 0 && + wm_shelf_->PrimaryAxisValue( + view_model_->ideal_bounds(index).right(), + view_model_->ideal_bounds(index).bottom()) > max_value) { + index--; + } + return index; +} + +int ShelfView::DetermineFirstVisiblePanelIndex(int min_value) const { + int index = model_->FirstPanelIndex(); + while (index < view_model_->view_size() && + wm_shelf_->PrimaryAxisValue(view_model_->ideal_bounds(index).x(), + view_model_->ideal_bounds(index).y()) < + min_value) { + ++index; + } + return index; +} + +void ShelfView::AnimateToIdealBounds() { + IdealBounds ideal_bounds; + CalculateIdealBounds(&ideal_bounds); + for (int i = 0; i < view_model_->view_size(); ++i) { + View* view = view_model_->view_at(i); + bounds_animator_->AnimateViewTo(view, view_model_->ideal_bounds(i)); + // Now that the item animation starts, we have to make sure that the + // padding of the first gets properly transferred to the new first item. + if (i && view->border()) + view->SetBorder(views::NullBorder()); + } + overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds); +} + +views::View* ShelfView::CreateViewForItem(const ShelfItem& item) { + views::View* view = nullptr; + switch (item.type) { + case TYPE_APP_PANEL: + case TYPE_APP_SHORTCUT: + case TYPE_BROWSER_SHORTCUT: + case TYPE_APP: + case TYPE_DIALOG: { + ShelfButton* button = new ShelfButton(this, this); + button->SetImage(item.image); + ReflectItemStatus(item, button); + view = button; + break; + } + + case TYPE_APP_LIST: { + view = new AppListButton(this, this, wm_shelf_); + break; + } + + case TYPE_UNDEFINED: + return nullptr; + } + + view->set_context_menu_controller(this); + ConfigureChildView(view); + return view; +} + +void ShelfView::FadeIn(views::View* view) { + view->SetVisible(true); + view->layer()->SetOpacity(0); + AnimateToIdealBounds(); + bounds_animator_->SetAnimationDelegate( + view, std::unique_ptr<gfx::AnimationDelegate>( + new FadeInAnimationDelegate(view))); +} + +void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) { + DCHECK(!dragging()); + DCHECK(drag_view_); + drag_pointer_ = pointer; + start_drag_index_ = view_model_->GetIndexOfView(drag_view_); + + if (start_drag_index_ == -1) { + CancelDrag(-1); + return; + } + + // Move the view to the front so that it appears on top of other views. + ReorderChildView(drag_view_, -1); + bounds_animator_->StopAnimatingView(drag_view_); + + drag_view_->OnDragStarted(&event); +} + +void ShelfView::ContinueDrag(const ui::LocatedEvent& event) { + DCHECK(dragging()); + DCHECK(drag_view_); + // Due to a syncing operation the application might have been removed. + // Bail if it is gone. + int current_index = view_model_->GetIndexOfView(drag_view_); + DCHECK_NE(-1, current_index); + + // If this is not a drag and drop host operation and not the app list item, + // check if the item got ripped off the shelf - if it did we are done. + if (!drag_and_drop_shelf_id_ && + RemovableByRipOff(current_index) != NOT_REMOVABLE) { + if (HandleRipOffDrag(event)) + return; + // The rip off handler could have changed the location of the item. + current_index = view_model_->GetIndexOfView(drag_view_); + } + + // TODO: I don't think this works correctly with RTL. + gfx::Point drag_point(event.location()); + ConvertPointToTarget(drag_view_, this, &drag_point); + + // Constrain the location to the range of valid indices for the type. + std::pair<int, int> indices(GetDragRange(current_index)); + int first_drag_index = indices.first; + int last_drag_index = indices.second; + // If the last index isn't valid, we're overflowing. Constrain to the app list + // (which is the last visible item). + if (first_drag_index < model_->FirstPanelIndex() && + last_drag_index > last_visible_index_) + last_drag_index = last_visible_index_; + int x = 0, y = 0; + if (wm_shelf_->IsHorizontalAlignment()) { + x = std::max(view_model_->ideal_bounds(indices.first).x(), + drag_point.x() - drag_origin_.x()); + x = std::min(view_model_->ideal_bounds(last_drag_index).right() - + view_model_->ideal_bounds(current_index).width(), + x); + if (drag_view_->x() == x) + return; + drag_view_->SetX(x); + } else { + y = std::max(view_model_->ideal_bounds(indices.first).y(), + drag_point.y() - drag_origin_.y()); + y = std::min(view_model_->ideal_bounds(last_drag_index).bottom() - + view_model_->ideal_bounds(current_index).height(), + y); + if (drag_view_->y() == y) + return; + drag_view_->SetY(y); + } + + int target_index = views::ViewModelUtils::DetermineMoveIndex( + *view_model_, drag_view_, + wm_shelf_->IsHorizontalAlignment() ? views::ViewModelUtils::HORIZONTAL + : views::ViewModelUtils::VERTICAL, + x, y); + target_index = + std::min(indices.second, std::max(target_index, indices.first)); + + // The app list button is always first, and it is the only non-draggable item. + int first_draggable_item = model_->GetItemIndexForType(TYPE_APP_LIST) + 1; + DCHECK_EQ(1, first_draggable_item); + target_index = std::max(target_index, first_draggable_item); + DCHECK_LT(target_index, model_->item_count()); + + if (target_index == current_index) + return; + + // Change the model, the ShelfItemMoved() callback will handle the + // |view_model_| update. + model_->Move(current_index, target_index); + bounds_animator_->StopAnimatingView(drag_view_); +} + +bool ShelfView::HandleRipOffDrag(const ui::LocatedEvent& event) { + int current_index = view_model_->GetIndexOfView(drag_view_); + DCHECK_NE(-1, current_index); + std::string dragged_app_id = + delegate_->GetAppIDForShelfID(model_->items()[current_index].id); + + gfx::Point screen_location = + WmWindow::Get(GetWidget()->GetNativeWindow()) + ->GetRootWindow() + ->ConvertPointToScreen(event.root_location()); + + // To avoid ugly forwards and backwards flipping we use different constants + // for ripping off / re-inserting the items. + if (dragged_off_shelf_) { + // If the shelf/overflow bubble bounds contains |screen_location| we insert + // the item back into the shelf. + if (GetBoundsForDragInsertInScreen().Contains(screen_location)) { + if (dragged_off_from_overflow_to_shelf_) { + // During the dragging an item from Shelf to Overflow, it can enter here + // directly because both are located very closly. + main_shelf_->EndDrag(true); + // Stops the animation of |drag_view_| and sets its bounds explicitly + // becase ContinueDrag() stops its animation. Without this, unexpected + // bounds will be set. + bounds_animator_->StopAnimatingView(drag_view_); + int drag_view_index = view_model_->GetIndexOfView(drag_view_); + drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index)); + dragged_off_from_overflow_to_shelf_ = false; + } + // Destroy our proxy view item. + DestroyDragIconProxy(); + // Re-insert the item and return simply false since the caller will handle + // the move as in any normal case. + dragged_off_shelf_ = false; + drag_view_->layer()->SetOpacity(1.0f); + // The size of Overflow bubble should be updated immediately when an item + // is re-inserted. + if (is_overflow_mode()) + PreferredSizeChanged(); + return false; + } else if (is_overflow_mode() && + main_shelf_->GetBoundsForDragInsertInScreen().Contains( + screen_location)) { + if (!dragged_off_from_overflow_to_shelf_) { + dragged_off_from_overflow_to_shelf_ = true; + drag_image_->SetOpacity(1.0f); + main_shelf_->StartDrag(dragged_app_id, screen_location); + } else { + main_shelf_->Drag(screen_location); + } + } else if (dragged_off_from_overflow_to_shelf_) { + // Makes the |drag_image_| partially disappear again. + dragged_off_from_overflow_to_shelf_ = false; + drag_image_->SetOpacity(kDraggedImageOpacity); + main_shelf_->EndDrag(true); + bounds_animator_->StopAnimatingView(drag_view_); + int drag_view_index = view_model_->GetIndexOfView(drag_view_); + drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index)); + } + // Move our proxy view item. + UpdateDragIconProxy(screen_location); + return true; + } + // Check if we are too far away from the shelf to enter the ripped off state. + // Determine the distance to the shelf. + int delta = CalculateShelfDistance(screen_location); + if (delta > kRipOffDistance) { + // Create a proxy view item which can be moved anywhere. + CreateDragIconProxy(event.root_location(), drag_view_->GetImage(), + drag_view_, gfx::Vector2d(0, 0), + kDragAndDropProxyScale); + drag_view_->layer()->SetOpacity(0.0f); + dragged_off_shelf_ = true; + if (RemovableByRipOff(current_index) == REMOVABLE) { + // Move the item to the front of the first panel item and hide it. + // ShelfItemMoved() callback will handle the |view_model_| update and + // call AnimateToIdealBounds(). + if (current_index != model_->FirstPanelIndex() - 1) { + model_->Move(current_index, model_->FirstPanelIndex() - 1); + StartFadeInLastVisibleItem(); + } else if (is_overflow_mode()) { + // Overflow bubble should be shrunk when an item is ripped off. + PreferredSizeChanged(); + } + // Make the item partially disappear to show that it will get removed if + // dropped. + drag_image_->SetOpacity(kDraggedImageOpacity); + } + return true; + } + return false; +} + +void ShelfView::FinalizeRipOffDrag(bool cancel) { + if (!dragged_off_shelf_) + return; + // Make sure we do not come in here again. + dragged_off_shelf_ = false; + + // Coming here we should always have a |drag_view_|. + DCHECK(drag_view_); + int current_index = view_model_->GetIndexOfView(drag_view_); + // If the view isn't part of the model anymore (|current_index| == -1), a sync + // operation must have removed it. In that case we shouldn't change the model + // and only delete the proxy image. + if (current_index == -1) { + DestroyDragIconProxy(); + return; + } + + // Set to true when the animation should snap back to where it was before. + bool snap_back = false; + // Items which cannot be dragged off will be handled as a cancel. + if (!cancel) { + if (dragged_off_from_overflow_to_shelf_) { + dragged_off_from_overflow_to_shelf_ = false; + main_shelf_->EndDrag(false); + drag_view_->layer()->SetOpacity(1.0f); + } else if (RemovableByRipOff(current_index) != REMOVABLE) { + // Make sure we do not try to remove un-removable items like items which + // were not pinned or have to be always there. + cancel = true; + snap_back = true; + } else { + // Make sure the item stays invisible upon removal. + drag_view_->SetVisible(false); + std::string app_id = + delegate_->GetAppIDForShelfID(model_->items()[current_index].id); + delegate_->UnpinAppWithID(app_id); + } + } + if (cancel || snap_back) { + if (dragged_off_from_overflow_to_shelf_) { + dragged_off_from_overflow_to_shelf_ = false; + // Main shelf handles revert of dragged item. + main_shelf_->EndDrag(true); + drag_view_->layer()->SetOpacity(1.0f); + } else if (!cancelling_drag_model_changed_) { + // Only do something if the change did not come through a model change. + gfx::Rect drag_bounds = drag_image_->GetBoundsInScreen(); + gfx::Point relative_to = GetBoundsInScreen().origin(); + gfx::Rect target( + gfx::PointAtOffsetFromOrigin(drag_bounds.origin() - relative_to), + drag_bounds.size()); + drag_view_->SetBoundsRect(target); + // Hide the status from the active item since we snap it back now. Upon + // animation end the flag gets cleared if |snap_back_from_rip_off_view_| + // is set. + snap_back_from_rip_off_view_ = drag_view_; + drag_view_->AddState(ShelfButton::STATE_HIDDEN); + // When a canceling drag model is happening, the view model is diverged + // from the menu model and movements / animations should not be done. + model_->Move(current_index, start_drag_index_); + AnimateToIdealBounds(); + } + drag_view_->layer()->SetOpacity(1.0f); + } + DestroyDragIconProxy(); +} + +ShelfView::RemovableState ShelfView::RemovableByRipOff(int index) const { + DCHECK(index >= 0 && index < model_->item_count()); + ShelfItemType type = model_->items()[index].type; + if (type == TYPE_APP_LIST || type == TYPE_DIALOG) + return NOT_REMOVABLE; + + if (model_->items()[index].pinned_by_policy) + return NOT_REMOVABLE; + + // Note: Only pinned app shortcuts can be removed! + std::string app_id = delegate_->GetAppIDForShelfID(model_->items()[index].id); + return (type == TYPE_APP_SHORTCUT && delegate_->IsAppPinned(app_id)) + ? REMOVABLE + : DRAGGABLE; +} + +bool ShelfView::SameDragType(ShelfItemType typea, ShelfItemType typeb) const { + switch (typea) { + case TYPE_APP_SHORTCUT: + case TYPE_BROWSER_SHORTCUT: + return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT); + case TYPE_APP_PANEL: + case TYPE_APP_LIST: + case TYPE_APP: + case TYPE_DIALOG: + return typeb == typea; + case TYPE_UNDEFINED: + NOTREACHED() << "ShelfItemType must be set."; + return false; + } + NOTREACHED(); + return false; +} + +std::pair<int, int> ShelfView::GetDragRange(int index) { + int min_index = -1; + int max_index = -1; + ShelfItemType type = model_->items()[index].type; + for (int i = 0; i < model_->item_count(); ++i) { + if (SameDragType(model_->items()[i].type, type)) { + if (min_index == -1) + min_index = i; + max_index = i; + } + } + return std::pair<int, int>(min_index, max_index); +} + +void ShelfView::ConfigureChildView(views::View* view) { + view->SetPaintToLayer(); + view->layer()->SetFillsBoundsOpaquely(false); +} + +void ShelfView::ToggleOverflowBubble() { + if (IsShowingOverflowBubble()) { + overflow_bubble_->Hide(); + return; + } + + if (!overflow_bubble_) + overflow_bubble_.reset(new OverflowBubble(wm_shelf_)); + + ShelfView* overflow_view = + new ShelfView(model_, delegate_, wm_shelf_, shelf_widget_); + overflow_view->overflow_mode_ = true; + overflow_view->Init(); + overflow_view->set_owner_overflow_bubble(overflow_bubble_.get()); + overflow_view->OnShelfAlignmentChanged(); + overflow_view->main_shelf_ = this; + UpdateOverflowRange(overflow_view); + + overflow_bubble_->Show(overflow_button_, overflow_view); + + wm_shelf_->UpdateVisibilityState(); +} + +void ShelfView::OnFadeOutAnimationEnded() { + AnimateToIdealBounds(); + StartFadeInLastVisibleItem(); +} + +void ShelfView::StartFadeInLastVisibleItem() { + // If overflow button is visible and there is a valid new last item, fading + // the new last item in after sliding animation is finished. + if (overflow_button_->visible() && last_visible_index_ >= 0) { + views::View* last_visible_view = view_model_->view_at(last_visible_index_); + last_visible_view->layer()->SetOpacity(0); + bounds_animator_->SetAnimationDelegate( + last_visible_view, + std::unique_ptr<gfx::AnimationDelegate>( + new StartFadeAnimationDelegate(this, last_visible_view))); + } +} + +void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const { + const int first_overflow_index = last_visible_index_ + 1; + const int last_overflow_index = last_hidden_index_; + DCHECK_LE(first_overflow_index, last_overflow_index); + DCHECK_LT(last_overflow_index, view_model_->view_size()); + + overflow_view->first_visible_index_ = first_overflow_index; + overflow_view->last_visible_index_ = last_overflow_index; +} + +gfx::Rect ShelfView::GetBoundsForDragInsertInScreen() { + gfx::Size preferred_size; + if (is_overflow_mode()) { + DCHECK(owner_overflow_bubble_); + gfx::Rect bubble_bounds = + owner_overflow_bubble_->bubble_view()->GetBubbleBounds(); + preferred_size = bubble_bounds.size(); + } else { + const int last_button_index = view_model_->view_size() - 1; + gfx::Rect last_button_bounds = + view_model_->view_at(last_button_index)->bounds(); + if (overflow_button_->visible() && + model_->GetItemIndexForType(TYPE_APP_PANEL) == -1) { + // When overflow button is visible and shelf has no panel items, + // last_button_bounds should be overflow button's bounds. + last_button_bounds = overflow_button_->bounds(); + } + + if (wm_shelf_->IsHorizontalAlignment()) { + preferred_size = gfx::Size(last_button_bounds.right() + leading_inset_, + GetShelfConstant(SHELF_SIZE)); + } else { + preferred_size = gfx::Size(GetShelfConstant(SHELF_SIZE), + last_button_bounds.bottom() + leading_inset_); + } + } + gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0); + + // In overflow mode, we should use OverflowBubbleView as a source for + // converting |origin| to screen coordinates. When a scroll operation is + // occurred in OverflowBubble, the bounds of ShelfView in OverflowBubble can + // be changed. + if (is_overflow_mode()) + ConvertPointToScreen(owner_overflow_bubble_->bubble_view(), &origin); + else + ConvertPointToScreen(this, &origin); + + return gfx::Rect(origin, preferred_size); +} + +int ShelfView::CancelDrag(int modified_index) { + FinalizeRipOffDrag(true); + if (!drag_view_) + return modified_index; + bool was_dragging = dragging(); + int drag_view_index = view_model_->GetIndexOfView(drag_view_); + drag_pointer_ = NONE; + drag_view_ = nullptr; + if (drag_view_index == modified_index) { + // The view that was being dragged is being modified. Don't do anything. + return modified_index; + } + if (!was_dragging) + return modified_index; + + // Restore previous position, tracking the position of the modified view. + bool at_end = modified_index == view_model_->view_size(); + views::View* modified_view = (modified_index >= 0 && !at_end) + ? view_model_->view_at(modified_index) + : nullptr; + model_->Move(drag_view_index, start_drag_index_); + + // If the modified view will be at the end of the list, return the new end of + // the list. + if (at_end) + return view_model_->view_size(); + return modified_view ? view_model_->GetIndexOfView(modified_view) : -1; +} + +gfx::Size ShelfView::GetPreferredSize() const { + IdealBounds ideal_bounds; + CalculateIdealBounds(&ideal_bounds); + const int shelf_size = GetShelfConstant(SHELF_SIZE); + + int last_button_index = last_visible_index_; + if (!is_overflow_mode()) { + if (last_hidden_index_ < view_model_->view_size() - 1) + last_button_index = view_model_->view_size() - 1; + else if (overflow_button_ && overflow_button_->visible()) + last_button_index++; + } + + // When an item is dragged off from the overflow bubble, it is moved to last + // position and and changed to invisible. Overflow bubble size should be + // shrunk to fit only for visible items. + // If |dragged_off_from_overflow_to_shelf_| is set, there will be no invisible + // items in the shelf. + if (is_overflow_mode() && dragged_off_shelf_ && + !dragged_off_from_overflow_to_shelf_ && + RemovableByRipOff(view_model_->GetIndexOfView(drag_view_)) == REMOVABLE) + last_button_index--; + + const gfx::Rect last_button_bounds = + last_button_index >= first_visible_index_ + ? view_model_->ideal_bounds(last_button_index) + : gfx::Rect(gfx::Size(shelf_size, shelf_size)); + + if (wm_shelf_->IsHorizontalAlignment()) + return gfx::Size(last_button_bounds.right() + leading_inset_, shelf_size); + + return gfx::Size(shelf_size, last_button_bounds.bottom() + leading_inset_); +} + +void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) { + // This bounds change is produced by the shelf movement and all content has + // to follow. Using an animation at that time would produce a time lag since + // the animation of the BoundsAnimator has itself a delay before it arrives + // at the required location. As such we tell the animator to go there + // immediately. + BoundsAnimatorDisabler disabler(bounds_animator_.get()); + LayoutToIdealBounds(); + wm_shelf_->NotifyShelfIconPositionsChanged(); + + if (IsShowingOverflowBubble()) + overflow_bubble_->Hide(); +} + +views::FocusTraversable* ShelfView::GetPaneFocusTraversable() { + return this; +} + +void ShelfView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_TOOLBAR; + node_data->SetName(l10n_util::GetStringUTF8(IDS_ASH_SHELF_ACCESSIBLE_NAME)); +} + +void ShelfView::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + if (details.is_add && details.child == this) + tooltip_.Init(); +} + +void ShelfView::OnGestureEvent(ui::GestureEvent* event) { + if (wm_shelf_->ProcessGestureEvent(*event)) + event->StopPropagation(); +} + +void ShelfView::ShelfItemAdded(int model_index) { + { + base::AutoReset<bool> cancelling_drag(&cancelling_drag_model_changed_, + true); + model_index = CancelDrag(model_index); + } + views::View* view = CreateViewForItem(model_->items()[model_index]); + AddChildView(view); + // Hide the view, it'll be made visible when the animation is done. Using + // opacity 0 here to avoid messing with CalculateIdealBounds which touches + // the view's visibility. + view->layer()->SetOpacity(0); + view_model_->Add(view, model_index); + + // Give the button its ideal bounds. That way if we end up animating the + // button before this animation completes it doesn't appear at some random + // spot (because it was in the middle of animating from 0,0 0x0 to its + // target). + IdealBounds ideal_bounds; + CalculateIdealBounds(&ideal_bounds); + view->SetBoundsRect(view_model_->ideal_bounds(model_index)); + + // The first animation moves all the views to their target position. |view| + // is hidden, so it visually appears as though we are providing space for + // it. When done we'll fade the view in. + AnimateToIdealBounds(); + if (model_index <= last_visible_index_ || + model_index >= model_->FirstPanelIndex()) { + bounds_animator_->SetAnimationDelegate( + view, std::unique_ptr<gfx::AnimationDelegate>( + new StartFadeAnimationDelegate(this, view))); + } else { + // Undo the hiding if animation does not run. + view->layer()->SetOpacity(1.0f); + } +} + +void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) { + if (id == context_menu_id_) + launcher_menu_runner_->Cancel(); + { + base::AutoReset<bool> cancelling_drag(&cancelling_drag_model_changed_, + true); + model_index = CancelDrag(model_index); + } + views::View* view = view_model_->view_at(model_index); + view_model_->Remove(model_index); + + // When the overflow bubble is visible, the overflow range needs to be set + // before CalculateIdealBounds() gets called. Otherwise CalculateIdealBounds() + // could trigger a ShelfItemChanged() by hiding the overflow bubble and + // since the overflow bubble is not yet synced with the ShelfModel this + // could cause a crash. + if (overflow_bubble_ && overflow_bubble_->IsShowing()) { + last_hidden_index_ = + std::min(last_hidden_index_, view_model_->view_size() - 1); + UpdateOverflowRange(overflow_bubble_->shelf_view()); + } + + if (view->visible()) { + // The first animation fades out the view. When done we'll animate the rest + // of the views to their target location. + bounds_animator_->AnimateViewTo(view, view->bounds()); + bounds_animator_->SetAnimationDelegate( + view, std::unique_ptr<gfx::AnimationDelegate>( + new FadeOutAnimationDelegate(this, view))); + } else { + // We don't need to show a fade out animation for invisible |view|. When an + // item is ripped out from the shelf, its |view| is already invisible. + AnimateToIdealBounds(); + } + + if (view == tooltip_.GetCurrentAnchorView()) + tooltip_.Close(); +} + +void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) { + const ShelfItem& item(model_->items()[model_index]); + if (old_item.type != item.type) { + // Type changed, swap the views. + model_index = CancelDrag(model_index); + std::unique_ptr<views::View> old_view(view_model_->view_at(model_index)); + bounds_animator_->StopAnimatingView(old_view.get()); + // Removing and re-inserting a view in our view model will strip the ideal + // bounds from the item. To avoid recalculation of everything the bounds + // get remembered and restored after the insertion to the previous value. + gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index); + view_model_->Remove(model_index); + views::View* new_view = CreateViewForItem(item); + AddChildView(new_view); + view_model_->Add(new_view, model_index); + view_model_->set_ideal_bounds(model_index, old_ideal_bounds); + new_view->SetBoundsRect(old_view->bounds()); + if (overflow_button_ && overflow_button_->visible()) + AnimateToIdealBounds(); + else + bounds_animator_->AnimateViewTo(new_view, old_ideal_bounds); + return; + } + + views::View* view = view_model_->view_at(model_index); + switch (item.type) { + case TYPE_APP_PANEL: + case TYPE_APP_SHORTCUT: + case TYPE_BROWSER_SHORTCUT: + case TYPE_APP: + case TYPE_DIALOG: { + CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); + ShelfButton* button = static_cast<ShelfButton*>(view); + ReflectItemStatus(item, button); + button->SetImage(item.image); + button->SchedulePaint(); + break; + } + + default: + break; + } +} + +void ShelfView::ShelfItemMoved(int start_index, int target_index) { + view_model_->Move(start_index, target_index); + // When cancelling a drag due to a shelf item being added, the currently + // dragged item is moved back to its initial position. AnimateToIdealBounds + // will be called again when the new item is added to the |view_model_| but + // at this time the |view_model_| is inconsistent with the |model_|. + if (!cancelling_drag_model_changed_) + AnimateToIdealBounds(); +} + +void ShelfView::OnSetShelfItemDelegate(ShelfID id, + ShelfItemDelegate* item_delegate) {} + +bool ShelfView::ShowListMenuForView(const ShelfItem& item, + views::View* source, + const ui::Event& event, + views::InkDrop* ink_drop) { + ShelfItemDelegate* item_delegate = model_->GetShelfItemDelegate(item.id); + ShelfAppMenuItemList items = item_delegate->GetAppMenuItems(event.flags()); + + // The application list menu should only show for two or more items; return + // false here to ensure that other behavior is triggered (eg. activating or + // minimizing a single associated window, or launching a pinned shelf item). + if (items.size() < 2) + return false; + + ink_drop->AnimateToState(views::InkDropState::ACTIVATED); + context_menu_id_ = item.id; + ShowMenu(base::MakeUnique<ShelfApplicationMenuModel>( + item.title, std::move(items), item_delegate), + source, gfx::Point(), false, ui::GetMenuSourceTypeForEvent(event), + ink_drop); + return true; +} + +void ShelfView::ShowContextMenuForView(views::View* source, + const gfx::Point& point, + ui::MenuSourceType source_type) { + last_pressed_index_ = -1; + + const ShelfItem* item = ShelfItemForView(source); + if (!item) { + WmShell::Get()->ShowContextMenu(point, source_type); + return; + } + + std::unique_ptr<ui::MenuModel> context_menu_model( + WmShell::Get()->delegate()->CreateContextMenu(wm_shelf_, item)); + if (!context_menu_model) + return; + + context_menu_id_ = item ? item->id : 0; + ShowMenu(std::move(context_menu_model), source, point, true, source_type, + nullptr); +} + +void ShelfView::ShowMenu(std::unique_ptr<ui::MenuModel> menu_model, + views::View* source, + const gfx::Point& click_point, + bool context_menu, + ui::MenuSourceType source_type, + views::InkDrop* ink_drop) { + menu_model_ = std::move(menu_model); + menu_model_adapter_.reset(new views::MenuModelAdapter( + menu_model_.get(), + base::Bind(&ShelfView::OnMenuClosed, base::Unretained(this), ink_drop))); + + closing_event_time_ = base::TimeTicks(); + int run_types = views::MenuRunner::ASYNC; + if (context_menu) + run_types |= views::MenuRunner::CONTEXT_MENU; + launcher_menu_runner_.reset( + new views::MenuRunner(menu_model_adapter_->CreateMenu(), run_types)); + + // Place new windows on the same display as the button that spawned the menu. + WmWindow* window = WmWindow::Get(source->GetWidget()->GetNativeWindow()); + scoped_root_window_for_new_windows_.reset( + new ScopedRootWindowForNewWindows(window->GetRootWindow())); + + views::MenuAnchorPosition menu_alignment = views::MENU_ANCHOR_TOPLEFT; + gfx::Rect anchor = gfx::Rect(click_point, gfx::Size()); + + if (!context_menu) { + // Application lists use a bubble. + // It is possible to invoke the menu while it is sliding into view. To cover + // that case, the screen coordinates are offsetted by the animation delta. + anchor = source->GetBoundsInScreen() + (window->GetTargetBounds().origin() - + window->GetBounds().origin()); + + // Adjust the anchor location for shelf items with asymmetrical borders. + if (source->border()) + anchor.Inset(source->border()->GetInsets()); + + // Determine the menu alignment dependent on the shelf. + switch (wm_shelf_->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + menu_alignment = views::MENU_ANCHOR_BUBBLE_ABOVE; + break; + case SHELF_ALIGNMENT_LEFT: + menu_alignment = views::MENU_ANCHOR_BUBBLE_RIGHT; + break; + case SHELF_ALIGNMENT_RIGHT: + menu_alignment = views::MENU_ANCHOR_BUBBLE_LEFT; + break; + } + } + + // NOTE: if you convert to HAS_MNEMONICS be sure to update menu building code. + launcher_menu_runner_->RunMenuAt(source->GetWidget(), nullptr, anchor, + menu_alignment, source_type); +} + +void ShelfView::OnMenuClosed(views::InkDrop* ink_drop) { + context_menu_id_ = 0; + + // Hide the hide overflow bubble after showing a context menu for its items. + if (owner_overflow_bubble_) + owner_overflow_bubble_->Hide(); + + closing_event_time_ = launcher_menu_runner_->closing_event_time(); + + if (ink_drop) + ink_drop->AnimateToState(views::InkDropState::DEACTIVATED); + + launcher_menu_runner_.reset(); + menu_model_adapter_.reset(); + menu_model_.reset(); + scoped_root_window_for_new_windows_.reset(); + + // Auto-hide or alignment might have changed, but only for this shelf. + wm_shelf_->UpdateVisibilityState(); +} + +void ShelfView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) { + wm_shelf_->NotifyShelfIconPositionsChanged(); + PreferredSizeChanged(); +} + +void ShelfView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { + if (snap_back_from_rip_off_view_ && animator == bounds_animator_.get()) { + if (!animator->IsAnimating(snap_back_from_rip_off_view_)) { + // Coming here the animation of the ShelfButton is finished and the + // previously hidden status can be shown again. Since the button itself + // might have gone away or changed locations we check that the button + // is still in the shelf and show its status again. + for (int index = 0; index < view_model_->view_size(); index++) { + views::View* view = view_model_->view_at(index); + if (view == snap_back_from_rip_off_view_) { + CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); + ShelfButton* button = static_cast<ShelfButton*>(view); + button->ClearState(ShelfButton::STATE_HIDDEN); + break; + } + } + snap_back_from_rip_off_view_ = nullptr; + } + } +} + +bool ShelfView::IsRepostEvent(const ui::Event& event) { + if (closing_event_time_.is_null()) + return false; + + // If the current (press down) event is a repost event, the time stamp of + // these two events should be the same. + return closing_event_time_ == event.time_stamp(); +} + +const ShelfItem* ShelfView::ShelfItemForView(const views::View* view) const { + const int view_index = view_model_->GetIndexOfView(view); + return (view_index < 0) ? nullptr : &(model_->items()[view_index]); +} + +int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const { + const gfx::Rect bounds = GetBoundsInScreen(); + int distance = wm_shelf_->SelectValueForShelfAlignment( + bounds.y() - coordinate.y(), coordinate.x() - bounds.right(), + bounds.x() - coordinate.x()); + return distance > 0 ? distance : 0; +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_view.h b/ash/common/shelf/shelf_view.h new file mode 100644 index 0000000..3f1858b --- /dev/null +++ b/ash/common/shelf/shelf_view.h
@@ -0,0 +1,470 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_VIEW_H_ +#define ASH_COMMON_SHELF_SHELF_VIEW_H_ + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "ash/common/shelf/ink_drop_button_listener.h" +#include "ash/common/shelf/shelf_button_pressed_metric_tracker.h" +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_model_observer.h" +#include "ash/common/shelf/shelf_tooltip_manager.h" +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/app_list/views/app_list_drag_and_drop_host.h" +#include "ui/views/animation/bounds_animator_observer.h" +#include "ui/views/animation/ink_drop_state.h" +#include "ui/views/context_menu_controller.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/focus/focus_manager.h" +#include "ui/views/view.h" +#include "ui/views/view_model.h" + +namespace ui { +class MenuModel; +} + +namespace views { +class BoundsAnimator; +class MenuModelAdapter; +class MenuRunner; +} + +namespace ash { +class AppListButton; +class DragImageView; +class OverflowBubble; +class OverflowButton; +class ScopedRootWindowForNewWindows; +class ShelfButton; +class ShelfDelegate; +class ShelfModel; +struct ShelfItem; +class ShelfWidget; +class WmShelf; + +namespace test { +class ShelfViewTestAPI; +} + +extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM; +extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT; +extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT; +extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT; + +class ASH_EXPORT ShelfView : public views::View, + public ShelfModelObserver, + public InkDropButtonListener, + public views::ContextMenuController, + public views::FocusTraversable, + public views::BoundsAnimatorObserver, + public app_list::ApplicationDragAndDropHost { + public: + ShelfView(ShelfModel* model, + ShelfDelegate* delegate, + WmShelf* wm_shelf, + ShelfWidget* shelf_widget); + ~ShelfView() override; + + WmShelf* wm_shelf() const { return wm_shelf_; } + ShelfModel* model() const { return model_; } + + void Init(); + + void OnShelfAlignmentChanged(); + + // Returns the ideal bounds of the specified item, or an empty rect if id + // isn't know. If the item is in an overflow shelf, the overflow icon location + // will be returned. + gfx::Rect GetIdealBoundsOfItemIcon(ShelfID id); + + // Repositions the icon for the specified item by the midpoint of the window. + void UpdatePanelIconPosition(ShelfID id, const gfx::Point& midpoint); + + // Returns true if we're showing a menu. + bool IsShowingMenu() const; + + // Returns true if overflow bubble is shown. + bool IsShowingOverflowBubble() const; + + // Sets owner overflow bubble instance from which this shelf view pops + // out as overflow. + void set_owner_overflow_bubble(OverflowBubble* owner) { + owner_overflow_bubble_ = owner; + } + + AppListButton* GetAppListButton() const; + + // Returns true if the mouse cursor exits the area for launcher tooltip. + // There are thin gaps between launcher buttons but the tooltip shouldn't hide + // in the gaps, but the tooltip should hide if the mouse moved totally outside + // of the buttons area. + bool ShouldHideTooltip(const gfx::Point& cursor_location) const; + + // Returns true if a tooltip should be shown for the shelf item |view|. + bool ShouldShowTooltipForView(const views::View* view) const; + + // Returns the title of the shelf item |view|. + base::string16 GetTitleForView(const views::View* view) const; + + // Returns rectangle bounding all visible launcher items. Used screen + // coordinate system. + gfx::Rect GetVisibleItemsBoundsInScreen(); + + // InkDropButtonListener: + void ButtonPressed(views::Button* sender, + const ui::Event& event, + views::InkDrop* ink_drop) override; + + // Overridden from FocusTraversable: + views::FocusSearch* GetFocusSearch() override; + FocusTraversable* GetFocusTraversableParent() override; + View* GetFocusTraversableParentView() override; + + // Overridden from app_list::ApplicationDragAndDropHost: + void CreateDragIconProxy(const gfx::Point& location_in_screen_coordinates, + const gfx::ImageSkia& icon, + views::View* replaced_view, + const gfx::Vector2d& cursor_offset_from_center, + float scale_factor) override; + void UpdateDragIconProxy( + const gfx::Point& location_in_screen_coordinates) override; + void DestroyDragIconProxy() override; + bool StartDrag(const std::string& app_id, + const gfx::Point& location_in_screen_coordinates) override; + bool Drag(const gfx::Point& location_in_screen_coordinates) override; + void EndDrag(bool cancel) override; + + // Returns true if |event| on the shelf item is going to activate the item. + // Used to determine whether a pending ink drop should be shown or not. + bool ShouldEventActivateButton(views::View* view, const ui::Event& event); + + // The shelf buttons use the Pointer interface to enable item reordering. + enum Pointer { NONE, DRAG_AND_DROP, MOUSE, TOUCH }; + void PointerPressedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event); + void PointerDraggedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event); + void PointerReleasedOnButton(views::View* view, + Pointer pointer, + bool canceled); + + // Updates the background for the shelf items. + void UpdateShelfItemBackground(SkColor color); + + // Return the view model for test purposes. + const views::ViewModel* view_model_for_test() const { + return view_model_.get(); + } + + private: + friend class ash::test::ShelfViewTestAPI; + + class FadeOutAnimationDelegate; + class StartFadeAnimationDelegate; + + struct IdealBounds { + gfx::Rect overflow_bounds; + }; + + enum RemovableState { + REMOVABLE, // Item can be removed when dragged away. + DRAGGABLE, // Item can be dragged, but will snap always back to origin. + NOT_REMOVABLE, // Item is fixed and can never be removed. + }; + + // Minimum distance before drag starts. + static const int kMinimumDragDistance; + + // Returns true when this ShelfView is used for Overflow Bubble. + // In this mode, it does not show app list, panel and overflow button. + // Note: + // * When Shelf can contain only one item (overflow button) due to very + // small resolution screen, overflow bubble can show app list and panel + // button. + bool is_overflow_mode() const { return overflow_mode_; } + + bool dragging() const { return drag_pointer_ != NONE; } + + // Sets the bounds of each view to its ideal bounds. + void LayoutToIdealBounds(); + + // Update all button's visibility in overflow. + void UpdateAllButtonsVisibilityInOverflowMode(); + + // Calculates the ideal bounds. The bounds of each button corresponding to an + // item in the model is set in |view_model_|. + void CalculateIdealBounds(IdealBounds* bounds) const; + + // Returns the index of the last view whose max primary axis coordinate is + // less than |max_value|. Returns -1 if nothing fits, or there are no views. + int DetermineLastVisibleIndex(int max_value) const; + + // Returns the index of the first panel whose min primary axis coordinate is + // at least |min_value|. Returns the index past the last panel if none fit. + int DetermineFirstVisiblePanelIndex(int min_value) const; + + // Animates the bounds of each view to its ideal bounds. + void AnimateToIdealBounds(); + + // Creates the view used to represent |item|. + views::View* CreateViewForItem(const ShelfItem& item); + + // Fades |view| from an opacity of 0 to 1. This is when adding a new item. + void FadeIn(views::View* view); + + // Invoked when the pointer has moved enough to trigger a drag. Sets + // internal state in preparation for the drag. + void PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event); + + // Invoked when the mouse is dragged. Updates the models as appropriate. + void ContinueDrag(const ui::LocatedEvent& event); + + // Handles ripping off an item from the shelf. Returns true when the item got + // removed. + bool HandleRipOffDrag(const ui::LocatedEvent& event); + + // Finalize the rip off dragging by either |cancel| the action or validating. + void FinalizeRipOffDrag(bool cancel); + + // Check if an item can be ripped off or not. + RemovableState RemovableByRipOff(int index) const; + + // Returns true if |typea| and |typeb| should be in the same drag range. + bool SameDragType(ShelfItemType typea, ShelfItemType typeb) const; + + // Returns the range (in the model) the item at the specified index can be + // dragged to. + std::pair<int, int> GetDragRange(int index); + + // If there is a drag operation in progress it's canceled. If |modified_index| + // is valid, the new position of the corresponding item is returned. + int CancelDrag(int modified_index); + + // Returns rectangle bounds used for drag insertion. + // Note: + // * When overflow button is visible, returns bounds from first item + // to overflow button. + // * When overflow button is visible and one or more panel items exists, + // returns bounds from first item to last panel item. + // * In the overflow mode, returns only bubble's bounds. + gfx::Rect GetBoundsForDragInsertInScreen(); + + // Common setup done for all children. + void ConfigureChildView(views::View* view); + + // Toggles the overflow menu. + void ToggleOverflowBubble(); + + // Invoked after the fading out animation for item deletion is ended. + void OnFadeOutAnimationEnded(); + + // Fade in last visible item. + void StartFadeInLastVisibleItem(); + + // Updates the visible range of overflow items in |overflow_view|. + void UpdateOverflowRange(ShelfView* overflow_view) const; + + // Overridden from views::View: + gfx::Size GetPreferredSize() const override; + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; + FocusTraversable* GetPaneFocusTraversable() override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) override; + + // Overridden from ui::EventHandler: + void OnGestureEvent(ui::GestureEvent* event) override; + + // Overridden from ShelfModelObserver: + void ShelfItemAdded(int model_index) override; + void ShelfItemRemoved(int model_index, ShelfID id) override; + void ShelfItemChanged(int model_index, const ShelfItem& old_item) override; + void ShelfItemMoved(int start_index, int target_index) override; + void OnSetShelfItemDelegate(ShelfID id, + ShelfItemDelegate* item_delegate) override; + + // Show a list of all running items for this shelf |item|; it only shows a + // menu if there are multiple running items. |source| specifies the view + // responsible for showing the menu, and the bubble will point towards it. + // The |event_flags| are the flags of the event which triggered this menu. + // Returns |true| if a menu is shown. + bool ShowListMenuForView(const ShelfItem& item, + views::View* source, + const ui::Event& event, + views::InkDrop* ink_drop); + + // Overridden from views::ContextMenuController: + void ShowContextMenuForView(views::View* source, + const gfx::Point& point, + ui::MenuSourceType source_type) override; + + // Show either a context or normal click menu of given |menu_model|. + // If |context_menu| is set, the displayed menu is a context menu and not + // a menu listing one or more running applications. + // The |click_point| is only used for |context_menu|'s. + void ShowMenu(std::unique_ptr<ui::MenuModel> menu_model, + views::View* source, + const gfx::Point& click_point, + bool context_menu, + ui::MenuSourceType source_type, + views::InkDrop* ink_drop); + + // Callback for MenuModelAdapter. + void OnMenuClosed(views::InkDrop* ink_drop); + + // Overridden from views::BoundsAnimatorObserver: + void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override; + void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override; + + // Returns true if the (press down) |event| is a repost event from an event + // which just closed the menu of a shelf item. If it occurs on the same shelf + // item, we should ignore the call. + bool IsRepostEvent(const ui::Event& event); + + // Convenience accessor to model_->items(). + const ShelfItem* ShelfItemForView(const views::View* view) const; + + // Get the distance from the given |coordinate| to the closest point on this + // launcher/shelf. + int CalculateShelfDistance(const gfx::Point& coordinate) const; + + // The model; owned by Launcher. + ShelfModel* model_; + + // Delegate; owned by Launcher. + ShelfDelegate* delegate_; + + // The shelf controller; owned by RootWindowController. + WmShelf* wm_shelf_; + + // The shelf widget for this view. For overflow bubbles, this is the widget + // for the shelf, not for the bubble. + ShelfWidget* shelf_widget_; + + // Used to manage the set of active launcher buttons. There is a view per + // item in |model_|. + std::unique_ptr<views::ViewModel> view_model_; + + // Index of first visible launcher item. + int first_visible_index_; + + // Last index of a launcher button that is visible + // (does not go into overflow). + mutable int last_visible_index_; + + std::unique_ptr<views::BoundsAnimator> bounds_animator_; + + OverflowButton* overflow_button_; + + std::unique_ptr<OverflowBubble> overflow_bubble_; + + OverflowBubble* owner_overflow_bubble_; + + ShelfTooltipManager tooltip_; + + // Pointer device that initiated the current drag operation. If there is no + // current dragging operation, this is NONE. + Pointer drag_pointer_; + + // The view being dragged. This is set immediately when the mouse is pressed. + // |dragging_| is set only if the mouse is dragged far enough. + ShelfButton* drag_view_; + + // Position of the mouse down event in |drag_view_|'s coordinates. + gfx::Point drag_origin_; + + // Index |drag_view_| was initially at. + int start_drag_index_; + + // Used for the context menu of a particular item. + ShelfID context_menu_id_; + + std::unique_ptr<views::FocusSearch> focus_search_; + + // Manages the context menu, and the list menu. + std::unique_ptr<ui::MenuModel> menu_model_; + std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; + std::unique_ptr<views::MenuRunner> launcher_menu_runner_; + std::unique_ptr<ScopedRootWindowForNewWindows> + scoped_root_window_for_new_windows_; + + // Amount content is inset on the left edge (or top edge for vertical + // alignment). + int leading_inset_; + + // True when an item being inserted or removed in the model cancels a drag. + bool cancelling_drag_model_changed_; + + // Index of the last hidden launcher item. If there are no hidden items this + // will be equal to last_visible_index_ + 1. + mutable int last_hidden_index_; + + // The timestamp of the event which closed the last menu - or 0. + base::TimeTicks closing_event_time_; + + // True if a drag and drop operation created/pinned the item in the launcher + // and it needs to be deleted/unpinned again if the operation gets cancelled. + bool drag_and_drop_item_pinned_; + + // The ShelfItem which is currently used for a drag and a drop operation + // or 0 otherwise. + ShelfID drag_and_drop_shelf_id_; + + // The application ID of the application which we drag and drop. + std::string drag_and_drop_app_id_; + + // The original launcher item's size before the dragging operation. + gfx::Size pre_drag_and_drop_size_; + + // The image proxy for drag operations when a drag and drop host exists and + // the item can be dragged outside the app grid. + std::unique_ptr<ash::DragImageView> drag_image_; + + // The cursor offset to the middle of the dragged item. + gfx::Vector2d drag_image_offset_; + + // The view which gets replaced by our drag icon proxy. + views::View* drag_replaced_view_; + + // True when the icon was dragged off the shelf. + bool dragged_off_shelf_; + + // The rip off view when a snap back operation is underway. + views::View* snap_back_from_rip_off_view_; + + // True when this ShelfView is used for Overflow Bubble. + bool overflow_mode_; + + // Holds a pointer to main ShelfView when a ShelfView is in overflow mode. + ShelfView* main_shelf_; + + // True when ripped item from overflow bubble is entered into Shelf. + bool dragged_off_from_overflow_to_shelf_; + + // True if the event is a repost event from a event which has just closed the + // menu of the same shelf item. + bool is_repost_event_on_same_item_; + + // Record the index for the last pressed shelf item. This variable is used to + // check if a repost event occurs on the same shelf item as previous one. If + // so, the repost event should be ignored. + int last_pressed_index_; + + // Tracks UMA metrics based on shelf button press actions. + ShelfButtonPressedMetricTracker shelf_button_pressed_metric_tracker_; + + DISALLOW_COPY_AND_ASSIGN(ShelfView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_VIEW_H_
diff --git a/ash/common/shelf/shelf_widget.cc b/ash/common/shelf/shelf_widget.cc new file mode 100644 index 0000000..248b4d5 --- /dev/null +++ b/ash/common/shelf/shelf_widget.cc
@@ -0,0 +1,358 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_widget.h" + +#include "ash/animation/animation_change_type.h" +#include "ash/common/focus_cycler.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/status_area_layout_manager.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_properties.h" +#include "base/memory/ptr_util.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/skbitmap_operations.h" +#include "ui/views/accessible_pane_view.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +// The contents view of the Shelf. This view contains ShelfView and +// sizes it to the width of the shelf minus the size of the status area. +class ShelfWidget::DelegateView : public views::WidgetDelegate, + public views::AccessiblePaneView, + public ShelfBackgroundAnimatorObserver { + public: + explicit DelegateView(ShelfWidget* shelf); + ~DelegateView() override; + + void set_focus_cycler(FocusCycler* focus_cycler) { + focus_cycler_ = focus_cycler; + } + FocusCycler* focus_cycler() { return focus_cycler_; } + + ui::Layer* opaque_background() { return &opaque_background_; } + ui::Layer* opaque_foreground() { return &opaque_foreground_; } + + void SetParentLayer(ui::Layer* layer); + + // views::WidgetDelegateView overrides: + views::Widget* GetWidget() override { return View::GetWidget(); } + const views::Widget* GetWidget() const override { return View::GetWidget(); } + + bool CanActivate() const override; + void ReorderChildLayers(ui::Layer* parent_layer) override; + // This will be called when the parent local bounds change. + void OnBoundsChanged(const gfx::Rect& old_bounds) override; + + // ShelfBackgroundAnimatorObserver: + void UpdateShelfBackground(SkColor color) override; + + private: + ShelfWidget* shelf_widget_; + FocusCycler* focus_cycler_; + // A black background layer that may be visible depending on a + // ShelfBackgroundAnimator. + // TODO(bruthig): Remove opaque_background_ (see https://crbug.com/621551). + ui::Layer opaque_background_; + // A black foreground layer which is shown while transitioning between users. + // Note: Since the back- and foreground layers have different functions they + // can be used simultaneously - so no repurposing possible. + ui::Layer opaque_foreground_; + + DISALLOW_COPY_AND_ASSIGN(DelegateView); +}; + +ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf_widget) + : shelf_widget_(shelf_widget), + focus_cycler_(nullptr), + opaque_background_(ui::LAYER_SOLID_COLOR), + opaque_foreground_(ui::LAYER_SOLID_COLOR) { + DCHECK(shelf_widget_); + SetLayoutManager(new views::FillLayout()); + set_allow_deactivate_on_esc(true); + opaque_background_.SetColor(SK_ColorBLACK); + opaque_background_.SetBounds(GetLocalBounds()); + opaque_foreground_.SetColor(SK_ColorBLACK); + opaque_foreground_.SetBounds(GetLocalBounds()); + opaque_foreground_.SetOpacity(0.0f); +} + +ShelfWidget::DelegateView::~DelegateView() {} + +void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) { + layer->Add(&opaque_background_); + layer->Add(&opaque_foreground_); + ReorderLayers(); +} + +bool ShelfWidget::DelegateView::CanActivate() const { + // Allow to activate as fallback. + if (shelf_widget_->activating_as_fallback_) + return true; + // Allow to activate from the focus cycler. + if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget()) + return true; + // Disallow activating in other cases, especially when using mouse. + return false; +} + +void ShelfWidget::DelegateView::ReorderChildLayers(ui::Layer* parent_layer) { + views::View::ReorderChildLayers(parent_layer); + parent_layer->StackAtBottom(&opaque_background_); + parent_layer->StackAtTop(&opaque_foreground_); +} + +void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect& old_bounds) { + opaque_background_.SetBounds(GetLocalBounds()); + opaque_foreground_.SetBounds(GetLocalBounds()); +} + +void ShelfWidget::DelegateView::UpdateShelfBackground(SkColor color) { + opaque_background_.SetColor(color); +} + +ShelfWidget::ShelfWidget(WmWindow* shelf_container, WmShelf* wm_shelf) + : wm_shelf_(wm_shelf), + status_area_widget_(nullptr), + delegate_view_(new DelegateView(this)), + shelf_view_(nullptr), + background_animator_(SHELF_BACKGROUND_DEFAULT, + wm_shelf_, + WmShell::Get()->wallpaper_controller()), + activating_as_fallback_(false) { + DCHECK(wm_shelf_); + background_animator_.AddObserver(this); + background_animator_.AddObserver(delegate_view_); + + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.name = "ShelfWidget"; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.delegate = delegate_view_; + shelf_container->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + this, shelf_container->GetShellWindowId(), ¶ms); + Init(params); + + // The shelf should not take focus when initially shown. + set_focus_on_creation(false); + SetContentsView(delegate_view_); + delegate_view_->SetParentLayer(GetLayer()); + + shelf_layout_manager_ = new ShelfLayoutManager(this, wm_shelf_); + shelf_layout_manager_->AddObserver(this); + shelf_container->SetLayoutManager(base::WrapUnique(shelf_layout_manager_)); + background_animator_.PaintBackground( + shelf_layout_manager_->GetShelfBackgroundType(), + AnimationChangeType::IMMEDIATE); + + views::Widget::AddObserver(this); +} + +ShelfWidget::~ShelfWidget() { + // Must call Shutdown() before destruction. + DCHECK(!status_area_widget_); + WmShell::Get()->focus_cycler()->RemoveWidget(this); + SetFocusCycler(nullptr); + RemoveObserver(this); + background_animator_.RemoveObserver(delegate_view_); + background_animator_.RemoveObserver(this); +} + +void ShelfWidget::CreateStatusAreaWidget(WmWindow* status_container) { + DCHECK(status_container); + DCHECK(!status_area_widget_); + // TODO(jamescook): Move ownership to RootWindowController. + status_area_widget_ = new StatusAreaWidget(status_container, wm_shelf_); + status_area_widget_->CreateTrayViews(); + if (WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()) + status_area_widget_->Show(); + WmShell::Get()->focus_cycler()->AddWidget(status_area_widget_); + background_animator_.AddObserver(status_area_widget_); + status_container->SetLayoutManager( + base::MakeUnique<StatusAreaLayoutManager>(this)); +} + +void ShelfWidget::SetPaintsBackground(ShelfBackgroundType background_type, + AnimationChangeType change_type) { + background_animator_.PaintBackground(background_type, change_type); +} + +ShelfBackgroundType ShelfWidget::GetBackgroundType() const { + return background_animator_.target_background_type(); +} + +void ShelfWidget::HideShelfBehindBlackBar(bool hide, int animation_time_ms) { + if (IsShelfHiddenBehindBlackBar() == hide) + return; + + ui::Layer* opaque_foreground = delegate_view_->opaque_foreground(); + float target_opacity = hide ? 1.0f : 0.0f; + std::unique_ptr<ui::ScopedLayerAnimationSettings> opaque_foreground_animation; + opaque_foreground_animation.reset( + new ui::ScopedLayerAnimationSettings(opaque_foreground->GetAnimator())); + opaque_foreground_animation->SetTransitionDuration( + base::TimeDelta::FromMilliseconds(animation_time_ms)); + opaque_foreground_animation->SetPreemptionStrategy( + ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); + + opaque_foreground->SetOpacity(target_opacity); +} + +bool ShelfWidget::IsShelfHiddenBehindBlackBar() const { + return delegate_view_->opaque_foreground()->GetTargetOpacity() != 0.0f; +} + +void ShelfWidget::OnShelfAlignmentChanged() { + shelf_view_->OnShelfAlignmentChanged(); + // TODO(jamescook): Status area should not cache alignment. + status_area_widget_->SetShelfAlignment(wm_shelf_->GetAlignment()); + delegate_view_->SchedulePaint(); +} + +ShelfView* ShelfWidget::CreateShelfView() { + DCHECK(!shelf_view_); + + shelf_view_ = + new ShelfView(WmShell::Get()->shelf_model(), + WmShell::Get()->shelf_delegate(), wm_shelf_, this); + shelf_view_->Init(); + GetContentsView()->AddChildView(shelf_view_); + return shelf_view_; +} + +void ShelfWidget::PostCreateShelf() { + SetFocusCycler(WmShell::Get()->focus_cycler()); + + // Ensure the newly created |shelf_| gets current values. + background_animator_.NotifyObserver(this); + + // TODO(jamescook): The IsActiveUserSessionStarted() check may not be needed + // because the shelf is only created after the first user session is active. + // The ShelfView seems to always be visible after login. At the lock screen + // the shelf is hidden because its container is hidden. During auto-hide it is + // hidden because ShelfWidget is transparent. Some of the ShelfView visibility + // code could be simplified. http://crbug.com/674773 + shelf_view_->SetVisible( + WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()); + shelf_layout_manager_->LayoutShelf(); + shelf_layout_manager_->UpdateAutoHideState(); + Show(); +} + +bool ShelfWidget::IsShelfVisible() const { + return shelf_view_ && shelf_view_->visible(); +} + +bool ShelfWidget::IsShowingAppList() const { + return GetAppListButton() && GetAppListButton()->is_showing_app_list(); +} + +bool ShelfWidget::IsShowingContextMenu() const { + return shelf_view_ && shelf_view_->IsShowingMenu(); +} + +bool ShelfWidget::IsShowingOverflowBubble() const { + return shelf_view_ && shelf_view_->IsShowingOverflowBubble(); +} + +void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) { + delegate_view_->set_focus_cycler(focus_cycler); + if (focus_cycler) + focus_cycler->AddWidget(this); +} + +FocusCycler* ShelfWidget::GetFocusCycler() { + return delegate_view_->focus_cycler(); +} + +void ShelfWidget::Shutdown() { + // Shutting down the status area widget may cause some widgets (e.g. bubbles) + // to close, so uninstall the ShelfLayoutManager event filters first. Don't + // reset the pointer until later because other widgets (e.g. app list) may + // access it later in shutdown. + if (shelf_layout_manager_) + shelf_layout_manager_->PrepareForShutdown(); + + if (status_area_widget_) { + background_animator_.RemoveObserver(status_area_widget_); + WmShell::Get()->focus_cycler()->RemoveWidget(status_area_widget_); + status_area_widget_->Shutdown(); + status_area_widget_ = nullptr; + } + + CloseNow(); +} + +void ShelfWidget::UpdateIconPositionForPanel(WmWindow* panel) { + if (!shelf_view_) + return; + + WmWindow* shelf_window = WmWindow::Get(this->GetNativeWindow()); + shelf_view_->UpdatePanelIconPosition( + panel->aura_window()->GetProperty(kShelfIDKey), + shelf_window->ConvertRectFromScreen(panel->GetBoundsInScreen()) + .CenterPoint()); +} + +gfx::Rect ShelfWidget::GetScreenBoundsOfItemIconForWindow(WmWindow* window) { + // Window animations can be triggered during session restore before the shelf + // view is created. In that case, return default empty bounds. + if (!shelf_view_) + return gfx::Rect(); + + ShelfID id = window->aura_window()->GetProperty(kShelfIDKey); + gfx::Rect bounds(shelf_view_->GetIdealBoundsOfItemIcon(id)); + gfx::Point screen_origin; + views::View::ConvertPointToScreen(shelf_view_, &screen_origin); + return gfx::Rect(screen_origin.x() + bounds.x(), + screen_origin.y() + bounds.y(), bounds.width(), + bounds.height()); +} + +AppListButton* ShelfWidget::GetAppListButton() const { + return shelf_view_ ? shelf_view_->GetAppListButton() : nullptr; +} + +app_list::ApplicationDragAndDropHost* +ShelfWidget::GetDragAndDropHostForAppList() { + return shelf_view_; +} + +void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget, + bool active) { + activating_as_fallback_ = false; + if (active) + delegate_view_->SetPaneFocusAndFocusDefault(); + else + delegate_view_->GetFocusManager()->ClearFocus(); +} + +void ShelfWidget::UpdateShelfItemBackground(SkColor color) { + if (shelf_view_) + shelf_view_->UpdateShelfItemBackground(color); +} + +void ShelfWidget::WillDeleteShelfLayoutManager() { + shelf_layout_manager_->RemoveObserver(this); + shelf_layout_manager_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_widget.h b/ash/common/shelf/shelf_widget.h new file mode 100644 index 0000000..e77b9d8 --- /dev/null +++ b/ash/common/shelf/shelf_widget.h
@@ -0,0 +1,130 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_WIDGET_H_ +#define ASH_COMMON_SHELF_SHELF_WIDGET_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_background_animator.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/common/shelf/shelf_layout_manager_observer.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" + +namespace app_list { +class ApplicationDragAndDropHost; +} + +namespace ash { +enum class AnimationChangeType; +class AppListButton; +class FocusCycler; +class ShelfLayoutManager; +class ShelfView; +class StatusAreaWidget; +class WmShelf; +class WmWindow; + +// The ShelfWidget manages the shelf view (which contains the shelf icons) and +// the status area widget. There is one ShelfWidget per display. It is created +// early during RootWindowController initialization. +class ASH_EXPORT ShelfWidget : public views::Widget, + public views::WidgetObserver, + public ShelfBackgroundAnimatorObserver, + public ShelfLayoutManagerObserver { + public: + ShelfWidget(WmWindow* shelf_container, WmShelf* wm_shelf); + ~ShelfWidget() override; + + void CreateStatusAreaWidget(WmWindow* status_container); + + void OnShelfAlignmentChanged(); + + // Sets the shelf's background type. + void SetPaintsBackground(ShelfBackgroundType background_type, + AnimationChangeType change_type); + ShelfBackgroundType GetBackgroundType() const; + + // Hide the shelf behind a black bar during e.g. a user transition when |hide| + // is true. The |animation_time_ms| will be used as animation duration. + void HideShelfBehindBlackBar(bool hide, int animation_time_ms); + bool IsShelfHiddenBehindBlackBar() const; + + ShelfLayoutManager* shelf_layout_manager() { return shelf_layout_manager_; } + StatusAreaWidget* status_area_widget() const { return status_area_widget_; } + + // Creates the shelf view and populates it with icons. Called after the user + // session is active (and hence the user profile is available). + ShelfView* CreateShelfView(); + void PostCreateShelf(); + + bool IsShelfVisible() const; + + bool IsShowingAppList() const; + bool IsShowingContextMenu() const; + bool IsShowingOverflowBubble() const; + + // Sets the focus cycler. Also adds the shelf to the cycle. + void SetFocusCycler(FocusCycler* focus_cycler); + FocusCycler* GetFocusCycler(); + + // Called by the activation delegate, before the shelf is activated + // when no other windows are visible. + void WillActivateAsFallback() { activating_as_fallback_ = true; } + + // Clean up prior to deletion. + void Shutdown(); + + // See WmShelf::UpdateIconPositionForPanel(). + void UpdateIconPositionForPanel(WmWindow* panel); + + // See WmShelf::GetScreenBoundsOfItemIconForWindow(). + gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window); + + // Returns the button that opens the app launcher. + AppListButton* GetAppListButton() const; + + // Returns the ApplicationDragAndDropHost for this shelf. + app_list::ApplicationDragAndDropHost* GetDragAndDropHostForAppList(); + + // Overridden from views::WidgetObserver: + void OnWidgetActivationChanged(views::Widget* widget, bool active) override; + + // ShelfBackgroundAnimatorObserver overrides: + void UpdateShelfItemBackground(SkColor color) override; + + // ShelfLayoutManagerObserver overrides: + void WillDeleteShelfLayoutManager() override; + + private: + class DelegateView; + friend class DelegateView; + + WmShelf* wm_shelf_; + + // Owned by the shelf container's window. + ShelfLayoutManager* shelf_layout_manager_; + + // Owned by the native widget. + StatusAreaWidget* status_area_widget_; + + // |delegate_view_| is the contents view of this widget and is cleaned up + // during CloseChildWindows of the associated RootWindowController. + DelegateView* delegate_view_; + // View containing the shelf items. Owned by the views hierarchy. Null when + // at the login screen. + ShelfView* shelf_view_; + ShelfBackgroundAnimator background_animator_; + bool activating_as_fallback_; + + DISALLOW_COPY_AND_ASSIGN(ShelfWidget); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_WIDGET_H_
diff --git a/ash/common/shelf/shelf_window_watcher.cc b/ash/common/shelf/shelf_window_watcher.cc new file mode 100644 index 0000000..7a00df9d --- /dev/null +++ b/ash/common/shelf/shelf_window_watcher.cc
@@ -0,0 +1,262 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_window_watcher.h" + +#include <memory> +#include <utility> + +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_window_watcher_item_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/shell.h" +#include "ash/wm/window_properties.h" +#include "ash/wm/window_state_aura.h" +#include "ash/wm/window_util.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/env.h" +#include "ui/aura/window.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/wm/public/activation_client.h" + +namespace ash { +namespace { + +// Returns the shelf item type, with special temporary behavior for Mash: +// Mash provides a default shelf item type (TYPE_APP) for non-ignored windows. +ShelfItemType GetShelfItemType(aura::Window* window) { + if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL || + window->GetProperty(kShelfItemTypeKey) != TYPE_UNDEFINED) { + return static_cast<ShelfItemType>(window->GetProperty(kShelfItemTypeKey)); + } + return wm::GetWindowState(window)->ignored_by_shelf() ? TYPE_UNDEFINED + : TYPE_APP; +} + +// Update the ShelfItem from relevant window properties. +void UpdateShelfItemForWindow(ShelfItem* item, aura::Window* window) { + item->type = GetShelfItemType(window); + + item->status = STATUS_RUNNING; + if (wm::IsActiveWindow(window)) + item->status = STATUS_ACTIVE; + else if (window->GetProperty(aura::client::kDrawAttentionKey)) + item->status = STATUS_ATTENTION; + + const std::string* app_id = window->GetProperty(aura::client::kAppIdKey); + item->app_id = app_id ? *app_id : std::string(); + + // Prefer app icons over window icons, they're typically larger. + gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconKey); + if (!image || image->isNull()) + image = window->GetProperty(aura::client::kWindowIconKey); + item->image = image ? *image : gfx::ImageSkia(); + + item->title = window->GetTitle(); + + // Do not show tooltips for visible attached app panel windows. + item->shows_tooltip = item->type != TYPE_APP_PANEL || !window->IsVisible() || + !window->GetProperty(kPanelAttachedKey); +} + +} // namespace + +ShelfWindowWatcher::ContainerWindowObserver::ContainerWindowObserver( + ShelfWindowWatcher* window_watcher) + : window_watcher_(window_watcher) {} + +ShelfWindowWatcher::ContainerWindowObserver::~ContainerWindowObserver() {} + +void ShelfWindowWatcher::ContainerWindowObserver::OnWindowHierarchyChanged( + const HierarchyChangeParams& params) { + if (!params.old_parent && params.new_parent && + (params.new_parent->id() == kShellWindowId_DefaultContainer || + params.new_parent->id() == kShellWindowId_PanelContainer)) { + // A new window was created in the default container or the panel container. + window_watcher_->OnUserWindowAdded(params.target); + } +} + +void ShelfWindowWatcher::ContainerWindowObserver::OnWindowDestroying( + aura::Window* window) { + window_watcher_->OnContainerWindowDestroying(window); +} + +//////////////////////////////////////////////////////////////////////////////// + +ShelfWindowWatcher::UserWindowObserver::UserWindowObserver( + ShelfWindowWatcher* window_watcher) + : window_watcher_(window_watcher) {} + +ShelfWindowWatcher::UserWindowObserver::~UserWindowObserver() {} + +void ShelfWindowWatcher::UserWindowObserver::OnWindowPropertyChanged( + aura::Window* window, + const void* key, + intptr_t old) { + if (key == aura::client::kAppIconKey || key == aura::client::kAppIdKey || + key == aura::client::kDrawAttentionKey || + key == aura::client::kWindowIconKey || key == kPanelAttachedKey || + key == kShelfItemTypeKey) { + window_watcher_->OnUserWindowPropertyChanged(window); + } +} + +void ShelfWindowWatcher::UserWindowObserver::OnWindowDestroying( + aura::Window* window) { + window_watcher_->OnUserWindowDestroying(window); +} + +void ShelfWindowWatcher::UserWindowObserver::OnWindowVisibilityChanged( + aura::Window* window, + bool visible) { + // OnWindowVisibilityChanged() is called for descendants too. We only care + // about changes to the visibility of windows we know about. + if (!window_watcher_->observed_user_windows_.IsObserving(window)) + return; + + // The tooltip behavior for panel windows depends on the panel visibility. + window_watcher_->OnUserWindowPropertyChanged(window); +} + +void ShelfWindowWatcher::UserWindowObserver::OnWindowTitleChanged( + aura::Window* window) { + window_watcher_->OnUserWindowPropertyChanged(window); +} + +//////////////////////////////////////////////////////////////////////////////// + +ShelfWindowWatcher::ShelfWindowWatcher(ShelfModel* model) + : model_(model), + container_window_observer_(this), + user_window_observer_(this), + observed_container_windows_(&container_window_observer_), + observed_user_windows_(&user_window_observer_) { + Shell::GetInstance()->activation_client()->AddObserver(this); + for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) + OnDisplayAdded(display); + display::Screen::GetScreen()->AddObserver(this); +} + +ShelfWindowWatcher::~ShelfWindowWatcher() { + display::Screen::GetScreen()->RemoveObserver(this); + Shell::GetInstance()->activation_client()->RemoveObserver(this); +} + +void ShelfWindowWatcher::AddShelfItem(aura::Window* window) { + user_windows_with_items_.insert(window); + ShelfItem item; + ShelfID id = model_->next_id(); + UpdateShelfItemForWindow(&item, window); + window->SetProperty(kShelfIDKey, id); + std::unique_ptr<ShelfItemDelegate> item_delegate( + new ShelfWindowWatcherItemDelegate(id, WmWindow::Get(window))); + model_->SetShelfItemDelegate(id, std::move(item_delegate)); + // Panels are inserted on the left so as not to push all existing panels over. + model_->AddAt(item.type == TYPE_APP_PANEL ? 0 : model_->item_count(), item); +} + +void ShelfWindowWatcher::RemoveShelfItem(aura::Window* window) { + user_windows_with_items_.erase(window); + int shelf_id = window->GetProperty(kShelfIDKey); + DCHECK_NE(shelf_id, kInvalidShelfID); + int index = model_->ItemIndexByID(shelf_id); + DCHECK_GE(index, 0); + model_->RemoveItemAt(index); + window->SetProperty(kShelfIDKey, kInvalidShelfID); +} + +void ShelfWindowWatcher::OnContainerWindowDestroying(aura::Window* container) { + observed_container_windows_.Remove(container); +} + +int ShelfWindowWatcher::GetShelfItemIndexForWindow(aura::Window* window) const { + return model_->ItemIndexByID(window->GetProperty(kShelfIDKey)); +} + +void ShelfWindowWatcher::OnUserWindowAdded(aura::Window* window) { + // The window may already be tracked from a prior display or parent container. + if (observed_user_windows_.IsObserving(window)) + return; + + observed_user_windows_.Add(window); + + // Add, update, or remove a ShelfItem for |window|, as needed. + OnUserWindowPropertyChanged(window); +} + +void ShelfWindowWatcher::OnUserWindowDestroying(aura::Window* window) { + if (observed_user_windows_.IsObserving(window)) + observed_user_windows_.Remove(window); + + if (user_windows_with_items_.count(window) > 0) + RemoveShelfItem(window); + DCHECK_EQ(0u, user_windows_with_items_.count(window)); +} + +void ShelfWindowWatcher::OnUserWindowPropertyChanged(aura::Window* window) { + if (GetShelfItemType(window) == TYPE_UNDEFINED) { + // Remove |window|'s ShelfItem if it was added by this ShelfWindowWatcher. + if (user_windows_with_items_.count(window) > 0) + RemoveShelfItem(window); + return; + } + + // Update an existing ShelfItem for |window| when a property has changed. + int index = GetShelfItemIndexForWindow(window); + if (index > 0) { + ShelfItem item = model_->items()[index]; + UpdateShelfItemForWindow(&item, window); + model_->Set(index, item); + return; + } + + // Creates a new ShelfItem for |window|. + AddShelfItem(window); +} + +void ShelfWindowWatcher::OnWindowActivated(ActivationReason reason, + aura::Window* gained_active, + aura::Window* lost_active) { + if (gained_active && user_windows_with_items_.count(gained_active) > 0) + OnUserWindowPropertyChanged(gained_active); + if (lost_active && user_windows_with_items_.count(lost_active) > 0) + OnUserWindowPropertyChanged(lost_active); +} + +void ShelfWindowWatcher::OnDisplayAdded(const display::Display& new_display) { + WmWindow* root = WmShell::Get()->GetRootWindowForDisplayId(new_display.id()); + aura::Window* aura_root = WmWindow::GetAuraWindow(root); + + // When the primary root window's display is removed, the existing root window + // is taken over by the new display, and the observer is already set. + aura::Window* default_container = + aura_root->GetChildById(kShellWindowId_DefaultContainer); + if (!observed_container_windows_.IsObserving(default_container)) { + for (aura::Window* window : default_container->children()) + OnUserWindowAdded(window); + observed_container_windows_.Add(default_container); + } + aura::Window* panel_container = + aura_root->GetChildById(kShellWindowId_PanelContainer); + if (!observed_container_windows_.IsObserving(panel_container)) { + for (aura::Window* window : panel_container->children()) + OnUserWindowAdded(window); + observed_container_windows_.Add(panel_container); + } +} + +void ShelfWindowWatcher::OnDisplayRemoved(const display::Display& old_display) { +} + +void ShelfWindowWatcher::OnDisplayMetricsChanged(const display::Display&, + uint32_t) {} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_window_watcher.h b/ash/common/shelf/shelf_window_watcher.h new file mode 100644 index 0000000..c683f39 --- /dev/null +++ b/ash/common/shelf/shelf_window_watcher.h
@@ -0,0 +1,120 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_WINDOW_WATCHER_H_ +#define ASH_COMMON_SHELF_SHELF_WINDOW_WATCHER_H_ + +#include <set> + +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "ui/aura/window_observer.h" +#include "ui/display/display_observer.h" +#include "ui/wm/public/activation_change_observer.h" + +namespace ash { + +class ShelfModel; + +// ShelfWindowWatcher creates and handles a ShelfItem for windows in the default +// container and panels in the panel container that have a valid ShelfItemType +// property (e.g. the task manager dialog or the OS settings window). It adds +// the ShelfItem when the window is added to the default container and maintains +// it until the window is closed, even if the window is transiently reparented +// (e.g. during a drag). +class ShelfWindowWatcher : public aura::client::ActivationChangeObserver, + public display::DisplayObserver { + public: + explicit ShelfWindowWatcher(ShelfModel* model); + ~ShelfWindowWatcher() override; + + private: + // Observes for windows being added to a root window's default container. + class ContainerWindowObserver : public aura::WindowObserver { + public: + explicit ContainerWindowObserver(ShelfWindowWatcher* window_watcher); + ~ContainerWindowObserver() override; + + private: + // aura::WindowObserver: + void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; + void OnWindowDestroying(aura::Window* window) override; + + ShelfWindowWatcher* window_watcher_; + + DISALLOW_COPY_AND_ASSIGN(ContainerWindowObserver); + }; + + // Observes individual user windows to detect when they are closed or when + // their shelf item properties have changed. + class UserWindowObserver : public aura::WindowObserver { + public: + explicit UserWindowObserver(ShelfWindowWatcher* window_watcher); + ~UserWindowObserver() override; + + private: + // aura::WindowObserver: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + void OnWindowDestroying(aura::Window* window) override; + void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; + void OnWindowTitleChanged(aura::Window* window) override; + + ShelfWindowWatcher* window_watcher_; + + DISALLOW_COPY_AND_ASSIGN(UserWindowObserver); + }; + + // Creates a ShelfItem for |window|. + void AddShelfItem(aura::Window* window); + + // Removes a ShelfItem for |window|. + void RemoveShelfItem(aura::Window* window); + + // Returns the index of ShelfItem associated with |window|, or -1 if none. + int GetShelfItemIndexForWindow(aura::Window* window) const; + + // Cleans up observers on |container|. + void OnContainerWindowDestroying(aura::Window* container); + + // Adds a shelf item for new windows added to the default container that have + // a valid ShelfItemType property value. + void OnUserWindowAdded(aura::Window* window); + + // Adds, updates or removes the shelf item based on a property change. + void OnUserWindowPropertyChanged(aura::Window* window); + + // Removes the shelf item when a window closes. + void OnUserWindowDestroying(aura::Window* window); + + // aura::client::ActivationChangeObserver: + void OnWindowActivated(ActivationReason reason, + aura::Window* gained_active, + aura::Window* lost_active) override; + + // display::DisplayObserver overrides: + void OnDisplayAdded(const display::Display& display) override; + void OnDisplayRemoved(const display::Display& old_display) override; + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t metrics) override; + + ShelfModel* model_; + + ContainerWindowObserver container_window_observer_; + UserWindowObserver user_window_observer_; + + ScopedObserver<aura::Window, ContainerWindowObserver> + observed_container_windows_; + ScopedObserver<aura::Window, UserWindowObserver> observed_user_windows_; + + // The set of windows with shelf items managed by this ShelfWindowWatcher. + std::set<aura::Window*> user_windows_with_items_; + + DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcher); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_WINDOW_WATCHER_H_
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.cc b/ash/common/shelf/shelf_window_watcher_item_delegate.cc new file mode 100644 index 0000000..01f4bd4 --- /dev/null +++ b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
@@ -0,0 +1,79 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_window_watcher_item_delegate.h" + +#include "ash/common/shelf/shelf_controller.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/wm/window_util.h" +#include "ui/aura/window.h" +#include "ui/events/event_constants.h" + +namespace ash { + +namespace { + +ShelfItemType GetShelfItemType(ShelfID id) { + ShelfModel* model = WmShell::Get()->shelf_controller()->model(); + ShelfItems::const_iterator item = model->ItemByID(id); + return item == model->items().end() ? TYPE_UNDEFINED : item->type; +} + +} // namespace + +ShelfWindowWatcherItemDelegate::ShelfWindowWatcherItemDelegate(ShelfID id, + WmWindow* window) + : id_(id), window_(window) { + DCHECK_NE(kInvalidShelfID, id_); + DCHECK(window_); +} + +ShelfWindowWatcherItemDelegate::~ShelfWindowWatcherItemDelegate() {} + +ShelfAction ShelfWindowWatcherItemDelegate::ItemSelected( + ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) { + // Move panels attached on another display to the current display. + if (GetShelfItemType(id_) == TYPE_APP_PANEL && + window_->aura_window()->GetProperty(kPanelAttachedKey) && + wm::MoveWindowToDisplay(window_->aura_window(), display_id)) { + window_->Activate(); + return SHELF_ACTION_WINDOW_ACTIVATED; + } + + if (window_->IsActive()) { + if (event_type == ui::ET_KEY_RELEASED) { + window_->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); + return SHELF_ACTION_NONE; + } + window_->Minimize(); + return SHELF_ACTION_WINDOW_MINIMIZED; + } + window_->Activate(); + return SHELF_ACTION_WINDOW_ACTIVATED; +} + +ShelfAppMenuItemList ShelfWindowWatcherItemDelegate::GetAppMenuItems( + int event_flags) { + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); +} + +void ShelfWindowWatcherItemDelegate::ExecuteCommand(uint32_t command_id, + int event_flags) { + // This delegate does not support showing an application menu. + NOTIMPLEMENTED(); +} + +void ShelfWindowWatcherItemDelegate::Close() { + window_->CloseWidget(); +} + +} // namespace ash
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.h b/ash/common/shelf/shelf_window_watcher_item_delegate.h new file mode 100644 index 0000000..fd61f439 --- /dev/null +++ b/ash/common/shelf/shelf_window_watcher_item_delegate.h
@@ -0,0 +1,41 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_SHELF_WINDOW_WATCHER_ITEM_DELEGATE_H_ +#define ASH_COMMON_SHELF_SHELF_WINDOW_WATCHER_ITEM_DELEGATE_H_ + +#include "ash/common/shelf/shelf_item_delegate.h" +#include "base/macros.h" + +namespace ash { + +class WmWindow; + +// ShelfItemDelegate for the items created by ShelfWindowWatcher, for example: +// The Chrome OS settings window, task manager window, and panel windows. +class ShelfWindowWatcherItemDelegate : public ShelfItemDelegate { + public: + ShelfWindowWatcherItemDelegate(ShelfID id, WmWindow* window); + ~ShelfWindowWatcherItemDelegate() override; + + private: + // ShelfItemDelegate overrides: + ShelfAction ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; + void ExecuteCommand(uint32_t command_id, int event_flags) override; + void Close() override; + + ShelfID id_; + // The window associated with this item. Not owned. + WmWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcherItemDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_SHELF_WINDOW_WATCHER_ITEM_DELEGATE_H_
diff --git a/ash/common/shelf/shelf_window_watcher_unittest.cc b/ash/common/shelf/shelf_window_watcher_unittest.cc new file mode 100644 index 0000000..f88eaa1 --- /dev/null +++ b/ash/common/shelf/shelf_window_watcher_unittest.cc
@@ -0,0 +1,395 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/shelf_window_watcher.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/root_window_controller.h" +#include "ash/test/ash_test_base.h" +#include "ui/base/hit_test.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +class ShelfWindowWatcherTest : public test::AshTestBase { + public: + ShelfWindowWatcherTest() : model_(nullptr) {} + ~ShelfWindowWatcherTest() override {} + + void SetUp() override { + test::AshTestBase::SetUp(); + model_ = WmShell::Get()->shelf_model(); + } + + void TearDown() override { + model_ = nullptr; + test::AshTestBase::TearDown(); + } + + static ShelfID CreateShelfItem(WmWindow* window) { + ShelfID id = WmShell::Get()->shelf_model()->next_id(); + window->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_DIALOG)); + return id; + } + + protected: + ShelfModel* model_; + + private: + DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcherTest); +}; + +// Ensure shelf items are added and removed as windows are opened and closed. +TEST_F(ShelfWindowWatcherTest, OpenAndClose) { + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + // Adding windows with valid ShelfItemType properties adds shelf items. + std::unique_ptr<views::Widget> widget1 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + CreateShelfItem(WmWindow::Get(widget1->GetNativeWindow())); + EXPECT_EQ(2, model_->item_count()); + std::unique_ptr<views::Widget> widget2 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + CreateShelfItem(WmWindow::Get(widget2->GetNativeWindow())); + EXPECT_EQ(3, model_->item_count()); + + // Each ShelfItem is removed when the associated window is destroyed. + widget1.reset(); + EXPECT_EQ(2, model_->item_count()); + widget2.reset(); + EXPECT_EQ(1, model_->item_count()); +} + +TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItemProperties) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + // Creating windows without a valid ShelfItemType does not add items. + std::unique_ptr<views::Widget> widget1 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); + std::unique_ptr<views::Widget> widget2 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); + EXPECT_EQ(1, model_->item_count()); + + // Create a ShelfItem for the first window. + ShelfID id_w1 = CreateShelfItem(window1); + EXPECT_EQ(2, model_->item_count()); + + int index_w1 = model_->ItemIndexByID(id_w1); + EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); + + // Create a ShelfItem for the second window. + ShelfID id_w2 = CreateShelfItem(window2); + EXPECT_EQ(3, model_->item_count()); + + int index_w2 = model_->ItemIndexByID(id_w2); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); + + // ShelfItem is removed when the item type window property is cleared. + window1->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_UNDEFINED)); + EXPECT_EQ(2, model_->item_count()); + window2->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_UNDEFINED)); + EXPECT_EQ(1, model_->item_count()); + // Clearing twice doesn't do anything. + window2->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_UNDEFINED)); + EXPECT_EQ(1, model_->item_count()); +} + +TEST_F(ShelfWindowWatcherTest, ActivateWindow) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only have APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + std::unique_ptr<views::Widget> widget1 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); + std::unique_ptr<views::Widget> widget2 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); + + // Create a ShelfItem for the first window. + ShelfID id_w1 = CreateShelfItem(window1); + EXPECT_EQ(2, model_->item_count()); + int index_w1 = model_->ItemIndexByID(id_w1); + EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); + + // Create a ShelfItem for the second window. + ShelfID id_w2 = CreateShelfItem(window2); + EXPECT_EQ(3, model_->item_count()); + int index_w2 = model_->ItemIndexByID(id_w2); + EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); + + // The ShelfItem for the first window is active when the window is activated. + widget1->Activate(); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w1].status); + EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status); + + // The ShelfItem for the second window is active when the window is activated. + widget2->Activate(); + EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); +} + +TEST_F(ShelfWindowWatcherTest, UpdateWindowProperty) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + std::unique_ptr<views::Widget> widget = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + + // Create a ShelfItem for |window|. + ShelfID id = CreateShelfItem(window); + EXPECT_EQ(2, model_->item_count()); + + int index = model_->ItemIndexByID(id); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); + + // Update the ShelfItemType for |window|. + window->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_APP)); + // No new item is created after updating a launcher item. + EXPECT_EQ(2, model_->item_count()); + // index and id are not changed after updating a launcher item. + EXPECT_EQ(index, model_->ItemIndexByID(id)); + EXPECT_EQ(id, model_->items()[index].id); +} + +TEST_F(ShelfWindowWatcherTest, MaximizeAndRestoreWindow) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + std::unique_ptr<views::Widget> widget = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + wm::WindowState* window_state = window->GetWindowState(); + + // Create a ShelfItem for |window|. + ShelfID id = CreateShelfItem(window); + EXPECT_EQ(2, model_->item_count()); + + int index = model_->ItemIndexByID(id); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); + + // Maximize window |window|. + EXPECT_FALSE(window_state->IsMaximized()); + window_state->Maximize(); + EXPECT_TRUE(window_state->IsMaximized()); + // No new item is created after maximizing a window |window|. + EXPECT_EQ(2, model_->item_count()); + // index and id are not changed after maximizing a window |window|. + EXPECT_EQ(index, model_->ItemIndexByID(id)); + EXPECT_EQ(id, model_->items()[index].id); + + // Restore window |window|. + window_state->Restore(); + EXPECT_FALSE(window_state->IsMaximized()); + // No new item is created after restoring a window |window|. + EXPECT_EQ(2, model_->item_count()); + // Index and id are not changed after maximizing a window |window|. + EXPECT_EQ(index, model_->ItemIndexByID(id)); + EXPECT_EQ(id, model_->items()[index].id); +} + +// Check that an item is maintained when its associated Window is docked. +TEST_F(ShelfWindowWatcherTest, DockWindow) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + std::unique_ptr<views::Widget> widget = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + + // Create a ShelfItem for |window|. + ShelfID id = CreateShelfItem(window); + EXPECT_EQ(2, model_->item_count()); + + int index = model_->ItemIndexByID(id); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); + + WmWindow* root_window = window->GetRootWindow(); + WmWindow* default_container = + root_window->GetChildByShellWindowId(kShellWindowId_DefaultContainer); + EXPECT_EQ(default_container, window->GetParent()); + + WmWindow* docked_container = + root_window->GetChildByShellWindowId(kShellWindowId_DockedContainer); + + // Check |window|'s item is not removed when it is re-parented to the dock. + docked_container->AddChild(window); + EXPECT_EQ(docked_container, window->GetParent()); + EXPECT_EQ(2, model_->item_count()); + + // The shelf item is removed when the window is closed, even if it is in the + // docked container at the time. + widget.reset(); + EXPECT_EQ(1, model_->item_count()); +} + +// Check |window|'s item is not changed during the dragging. +// TODO(simonhong): Add a test for removing a Window during the dragging. +TEST_F(ShelfWindowWatcherTest, DragWindow) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + std::unique_ptr<views::Widget> widget = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + + // Create a ShelfItem for |window|. + ShelfID id = CreateShelfItem(window); + EXPECT_EQ(2, model_->item_count()); + + int index = model_->ItemIndexByID(id); + EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); + + // Simulate dragging of |window| and check its item is not changed. + std::unique_ptr<WindowResizer> resizer(CreateWindowResizer( + window, gfx::Point(), HTCAPTION, aura::client::WINDOW_MOVE_SOURCE_MOUSE)); + ASSERT_TRUE(resizer.get()); + resizer->Drag(gfx::Point(50, 50), 0); + resizer->CompleteDrag(); + + // Index and id are not changed after dragging a |window|. + EXPECT_EQ(index, model_->ItemIndexByID(id)); + EXPECT_EQ(id, model_->items()[index].id); +} + +// Ensure shelf items are added and removed as panels are opened and closed. +TEST_F(ShelfWindowWatcherTest, PanelWindow) { + // TODO: investigate failure in mash. http://crbug.com/695562. + if (WmShell::Get()->IsRunningInMash()) + return; + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model_->item_count()); + + // Adding windows with valid ShelfItemType properties adds shelf items. + std::unique_ptr<views::Widget> widget1 = + CreateTestWidget(nullptr, kShellWindowId_PanelContainer, gfx::Rect()); + WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); + window1->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_APP_PANEL)); + EXPECT_EQ(2, model_->item_count()); + std::unique_ptr<views::Widget> widget2 = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); + window2->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_APP_PANEL)); + EXPECT_EQ(3, model_->item_count()); + + // Create a panel-type widget to mimic Chrome's app panel windows. + views::Widget panel_widget; + views::Widget::InitParams panel_params(views::Widget::InitParams::TYPE_PANEL); + panel_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + WmShell::Get() + ->GetPrimaryRootWindow() + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + &panel_widget, kShellWindowId_PanelContainer, &panel_params); + panel_widget.Init(panel_params); + panel_widget.Show(); + WmWindow* panel_window = WmWindow::Get(panel_widget.GetNativeWindow()); + panel_window->aura_window()->SetProperty( + kShelfItemTypeKey, static_cast<int32_t>(TYPE_APP_PANEL)); + EXPECT_EQ(4, model_->item_count()); + + // Each ShelfItem is removed when the associated window is destroyed. + panel_widget.CloseNow(); + EXPECT_EQ(3, model_->item_count()); + widget2.reset(); + EXPECT_EQ(2, model_->item_count()); + widget1.reset(); + EXPECT_EQ(1, model_->item_count()); +} + +TEST_F(ShelfWindowWatcherTest, DontCreateShelfEntriesForChildWindows) { + const int initial_item_count = model_->item_count(); + + WmWindow* window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_NOT_DRAWN); + window->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_APP)); + WmShell::Get() + ->GetPrimaryRootWindow() + ->GetChildByShellWindowId(kShellWindowId_DefaultContainer) + ->AddChild(window); + window->Show(); + EXPECT_EQ(initial_item_count + 1, model_->item_count()); + + WmWindow* child_window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_NOT_DRAWN); + child_window->aura_window()->SetProperty(kShelfItemTypeKey, + static_cast<int32_t>(TYPE_APP)); + window->AddChild(child_window); + child_window->Show(); + // |child_window| should not result in adding a new entry. + EXPECT_EQ(initial_item_count + 1, model_->item_count()); + + child_window->Destroy(); + window->Destroy(); + EXPECT_EQ(initial_item_count, model_->item_count()); +} + +// Ensures ShelfWindowWatcher supports windows opened prior to session start. +using ShelfWindowWatcherSessionStartTest = test::NoSessionAshTestBase; +TEST_F(ShelfWindowWatcherSessionStartTest, PreExistingWindow) { + ShelfModel* model = WmShell::Get()->shelf_model(); + ASSERT_FALSE( + WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()); + + // ShelfModel only has an APP_LIST item. + EXPECT_EQ(1, model->item_count()); + + // Construct a window that should get a shelf item once the session starts. + std::unique_ptr<views::Widget> widget = + CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + ShelfWindowWatcherTest::CreateShelfItem(window); + EXPECT_EQ(1, model->item_count()); + + // Start the test user session; ShelfWindowWatcher will find the open window. + SetSessionStarted(true); + EXPECT_EQ(2, model->item_count()); +} + +} // namespace ash
diff --git a/ash/common/shelf/wm_shelf.cc b/ash/common/shelf/wm_shelf.cc new file mode 100644 index 0000000..2a06cc2 --- /dev/null +++ b/ash/common/shelf/wm_shelf.cc
@@ -0,0 +1,375 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/wm_shelf.h" + +#include "ash/common/shelf/shelf_controller.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_locking_manager.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/shelf/shelf_bezel_event_handler.h" +#include "ash/shell.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "ui/aura/env.h" +#include "ui/display/types/display_constants.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { + +// WmShelf::AutoHideEventHandler ----------------------------------------------- + +// Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. +// TODO(mash): Add similar event handling support for mash. +class WmShelf::AutoHideEventHandler : public ui::EventHandler { + public: + explicit AutoHideEventHandler(ShelfLayoutManager* shelf_layout_manager) + : shelf_layout_manager_(shelf_layout_manager) { + Shell::GetInstance()->AddPreTargetHandler(this); + } + ~AutoHideEventHandler() override { + Shell::GetInstance()->RemovePreTargetHandler(this); + } + + // Overridden from ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + shelf_layout_manager_->UpdateAutoHideForMouseEvent( + event, WmWindow::Get(static_cast<aura::Window*>(event->target()))); + } + void OnGestureEvent(ui::GestureEvent* event) override { + shelf_layout_manager_->UpdateAutoHideForGestureEvent( + event, WmWindow::Get(static_cast<aura::Window*>(event->target()))); + } + + private: + ShelfLayoutManager* shelf_layout_manager_; + DISALLOW_COPY_AND_ASSIGN(AutoHideEventHandler); +}; + +// WmShelf --------------------------------------------------------------------- + +WmShelf::WmShelf() {} + +WmShelf::~WmShelf() {} + +// static +WmShelf* WmShelf::ForWindow(WmWindow* window) { + return window->GetRootWindowController()->GetShelf(); +} + +// static +bool WmShelf::CanChangeShelfAlignment() { + if (WmShell::Get()->system_tray_delegate()->IsUserSupervised()) + return false; + + LoginStatus login_status = + WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); + + switch (login_status) { + case LoginStatus::LOCKED: + // Shelf alignment changes can be requested while being locked, but will + // be applied upon unlock. + case LoginStatus::USER: + case LoginStatus::OWNER: + return true; + case LoginStatus::PUBLIC: + case LoginStatus::SUPERVISED: + case LoginStatus::GUEST: + case LoginStatus::KIOSK_APP: + case LoginStatus::ARC_KIOSK_APP: + case LoginStatus::NOT_LOGGED_IN: + return false; + } + + NOTREACHED(); + return false; +} + +void WmShelf::CreateShelfWidget(WmWindow* root) { + DCHECK(!shelf_widget_); + WmWindow* shelf_container = + root->GetChildByShellWindowId(kShellWindowId_ShelfContainer); + shelf_widget_.reset(new ShelfWidget(shelf_container, this)); + + DCHECK(!shelf_layout_manager_); + shelf_layout_manager_ = shelf_widget_->shelf_layout_manager(); + shelf_layout_manager_->AddObserver(this); + + // Must occur after |shelf_widget_| is constructed because the system tray + // constructors call back into WmShelf::shelf_widget(). + DCHECK(!shelf_widget_->status_area_widget()); + WmWindow* status_container = + root->GetChildByShellWindowId(kShellWindowId_StatusContainer); + shelf_widget_->CreateStatusAreaWidget(status_container); + + // TODO: ShelfBezelEventHandler needs to work with mus too. + // http://crbug.com/636647 + if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL) + bezel_event_handler_ = base::MakeUnique<ShelfBezelEventHandler>(this); +} + +void WmShelf::ShutdownShelfWidget() { + if (shelf_widget_) + shelf_widget_->Shutdown(); +} + +void WmShelf::DestroyShelfWidget() { + shelf_widget_.reset(); +} + +void WmShelf::CreateShelfView() { + DCHECK(shelf_layout_manager_); + DCHECK(shelf_widget_); + DCHECK(!shelf_view_); + shelf_view_ = shelf_widget_->CreateShelfView(); + shelf_locking_manager_.reset(new ShelfLockingManager(this)); + WmShell::Get()->shelf_controller()->NotifyShelfCreated(this); +} + +void WmShelf::ShutdownShelf() { + DCHECK(shelf_view_); + shelf_locking_manager_.reset(); + shelf_view_ = nullptr; +} + +bool WmShelf::IsShelfInitialized() const { + return !!shelf_view_; +} + +WmWindow* WmShelf::GetWindow() { + return WmWindow::Get(shelf_widget_->GetNativeWindow()); +} + +void WmShelf::SetAlignment(ShelfAlignment alignment) { + DCHECK(shelf_layout_manager_); + DCHECK(shelf_locking_manager_); + + if (alignment_ == alignment) + return; + + if (shelf_locking_manager_->is_locked() && + alignment != SHELF_ALIGNMENT_BOTTOM_LOCKED) { + shelf_locking_manager_->set_stored_alignment(alignment); + return; + } + + alignment_ = alignment; + // The ShelfWidget notifies the ShelfView of the alignment change. + shelf_widget_->OnShelfAlignmentChanged(); + shelf_layout_manager_->LayoutShelf(); + WmShell::Get()->shelf_controller()->NotifyShelfAlignmentChanged(this); + WmShell::Get()->NotifyShelfAlignmentChanged(GetWindow()->GetRootWindow()); +} + +bool WmShelf::IsHorizontalAlignment() const { + switch (alignment_) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + return true; + case SHELF_ALIGNMENT_LEFT: + case SHELF_ALIGNMENT_RIGHT: + return false; + } + NOTREACHED(); + return true; +} + +int WmShelf::SelectValueForShelfAlignment(int bottom, + int left, + int right) const { + switch (alignment_) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + return bottom; + case SHELF_ALIGNMENT_LEFT: + return left; + case SHELF_ALIGNMENT_RIGHT: + return right; + } + NOTREACHED(); + return bottom; +} + +int WmShelf::PrimaryAxisValue(int horizontal, int vertical) const { + return IsHorizontalAlignment() ? horizontal : vertical; +} + +void WmShelf::SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide_behavior) { + DCHECK(shelf_layout_manager_); + + if (auto_hide_behavior_ == auto_hide_behavior) + return; + + auto_hide_behavior_ = auto_hide_behavior; + WmShell::Get()->shelf_controller()->NotifyShelfAutoHideBehaviorChanged(this); + WmShell::Get()->NotifyShelfAutoHideBehaviorChanged( + GetWindow()->GetRootWindow()); +} + +ShelfAutoHideState WmShelf::GetAutoHideState() const { + return shelf_layout_manager_->auto_hide_state(); +} + +void WmShelf::UpdateAutoHideState() { + shelf_layout_manager_->UpdateAutoHideState(); +} + +ShelfBackgroundType WmShelf::GetBackgroundType() const { + return shelf_widget_->GetBackgroundType(); +} + +bool WmShelf::IsVisible() const { + return shelf_widget_->IsShelfVisible(); +} + +void WmShelf::UpdateVisibilityState() { + if (shelf_layout_manager_) + shelf_layout_manager_->UpdateVisibilityState(); +} + +ShelfVisibilityState WmShelf::GetVisibilityState() const { + return shelf_layout_manager_ ? shelf_layout_manager_->visibility_state() + : SHELF_HIDDEN; +} + +gfx::Rect WmShelf::GetIdealBounds() { + return shelf_layout_manager_->GetIdealBounds(); +} + +gfx::Rect WmShelf::GetUserWorkAreaBounds() const { + return shelf_layout_manager_ ? shelf_layout_manager_->user_work_area_bounds() + : gfx::Rect(); +} + +void WmShelf::UpdateIconPositionForPanel(WmWindow* panel) { + shelf_widget_->UpdateIconPositionForPanel(panel); +} + +gfx::Rect WmShelf::GetScreenBoundsOfItemIconForWindow(WmWindow* window) { + if (!shelf_widget_) + return gfx::Rect(); + return shelf_widget_->GetScreenBoundsOfItemIconForWindow(window); +} + +// static +void WmShelf::LaunchShelfItem(int item_index) { + ShelfModel* shelf_model = WmShell::Get()->shelf_model(); + const ShelfItems& items = shelf_model->items(); + int item_count = shelf_model->item_count(); + int indexes_left = item_index >= 0 ? item_index : item_count; + int found_index = -1; + + // Iterating until we have hit the index we are interested in which + // is true once indexes_left becomes negative. + for (int i = 0; i < item_count && indexes_left >= 0; i++) { + if (items[i].type != TYPE_APP_LIST) { + found_index = i; + indexes_left--; + } + } + + // There are two ways how found_index can be valid: a.) the nth item was + // found (which is true when indexes_left is -1) or b.) the last item was + // requested (which is true when index was passed in as a negative number). + if (found_index >= 0 && (indexes_left == -1 || item_index < 0)) { + // Then set this one as active (or advance to the next item of its kind). + ActivateShelfItem(found_index); + } +} + +// static +void WmShelf::ActivateShelfItem(int item_index) { + ShelfModel* shelf_model = WmShell::Get()->shelf_model(); + const ShelfItem& item = shelf_model->items()[item_index]; + ShelfItemDelegate* item_delegate = shelf_model->GetShelfItemDelegate(item.id); + item_delegate->ItemSelected(ui::ET_KEY_RELEASED, ui::EF_NONE, + display::kInvalidDisplayId, LAUNCH_FROM_UNKNOWN); +} + +bool WmShelf::ProcessGestureEvent(const ui::GestureEvent& event) { + // Can be called at login screen. + if (!shelf_layout_manager_) + return false; + return shelf_layout_manager_->ProcessGestureEvent(event); +} + +void WmShelf::AddObserver(WmShelfObserver* observer) { + observers_.AddObserver(observer); +} + +void WmShelf::RemoveObserver(WmShelfObserver* observer) { + observers_.RemoveObserver(observer); +} + +void WmShelf::NotifyShelfIconPositionsChanged() { + for (auto& observer : observers_) + observer.OnShelfIconPositionsChanged(); +} + +StatusAreaWidget* WmShelf::GetStatusAreaWidget() const { + return shelf_widget_->status_area_widget(); +} + +void WmShelf::SetVirtualKeyboardBoundsForTesting(const gfx::Rect& bounds) { + shelf_layout_manager_->OnKeyboardBoundsChanging(bounds); +} + +ShelfLockingManager* WmShelf::GetShelfLockingManagerForTesting() { + return shelf_locking_manager_.get(); +} + +ShelfView* WmShelf::GetShelfViewForTesting() { + return shelf_view_; +} + +void WmShelf::WillDeleteShelfLayoutManager() { + if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS) { + // TODO(sky): this should be removed once Shell is used everywhere. + ShutdownShelfWidget(); + } + + // Clear event handlers that might forward events to the destroyed instance. + auto_hide_event_handler_.reset(); + bezel_event_handler_.reset(); + + DCHECK(shelf_layout_manager_); + shelf_layout_manager_->RemoveObserver(this); + shelf_layout_manager_ = nullptr; +} + +void WmShelf::WillChangeVisibilityState(ShelfVisibilityState new_state) { + for (auto& observer : observers_) + observer.WillChangeVisibilityState(new_state); + if (new_state != SHELF_AUTO_HIDE) { + auto_hide_event_handler_.reset(); + } else if (!auto_hide_event_handler_ && + aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL) { + auto_hide_event_handler_ = + base::MakeUnique<AutoHideEventHandler>(shelf_layout_manager()); + } +} + +void WmShelf::OnAutoHideStateChanged(ShelfAutoHideState new_state) { + for (auto& observer : observers_) + observer.OnAutoHideStateChanged(new_state); +} + +void WmShelf::OnBackgroundUpdated(ShelfBackgroundType background_type, + AnimationChangeType change_type) { + if (background_type == GetBackgroundType()) + return; + for (auto& observer : observers_) + observer.OnBackgroundTypeChanged(background_type, change_type); +} + +} // namespace ash
diff --git a/ash/common/shelf/wm_shelf.h b/ash/common/shelf/wm_shelf.h new file mode 100644 index 0000000..b2e858a --- /dev/null +++ b/ash/common/shelf/wm_shelf.h
@@ -0,0 +1,188 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_WM_SHELF_H_ +#define ASH_COMMON_SHELF_WM_SHELF_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_layout_manager_observer.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/observer_list.h" + +namespace gfx { +class Rect; +} + +namespace ui { +class GestureEvent; +} + +namespace ash { + +enum class AnimationChangeType; +class ShelfBezelEventHandler; +class ShelfLayoutManager; +class ShelfLayoutManagerTest; +class ShelfLockingManager; +class ShelfView; +class ShelfWidget; +class StatusAreaWidget; +class WmShelfObserver; +class WmWindow; + +// Controller for the shelf state. Exists for the lifetime of each root window +// controller. Note that the shelf widget may not be created until after login. +class ASH_EXPORT WmShelf : public ShelfLayoutManagerObserver { + public: + WmShelf(); + ~WmShelf() override; + + // Returns the shelf for the display that |window| is on. Note that the shelf + // widget may not exist, or the shelf may not be visible. + static WmShelf* ForWindow(WmWindow* window); + + // Returns if shelf alignment options are enabled, and the user is able to + // adjust the alignment (eg. not allowed in guest and supervised user modes). + static bool CanChangeShelfAlignment(); + + void CreateShelfWidget(WmWindow* root); + void ShutdownShelfWidget(); + void DestroyShelfWidget(); + + ShelfLayoutManager* shelf_layout_manager() const { + return shelf_layout_manager_; + } + + ShelfWidget* shelf_widget() { return shelf_widget_.get(); } + + // Creates the shelf view. + void CreateShelfView(); + + // TODO(jamescook): Eliminate this method. + void ShutdownShelf(); + + // True after the ShelfView has been created (e.g. after login). + bool IsShelfInitialized() const; + + // Returns the window showing the shelf. + WmWindow* GetWindow(); + + ShelfAlignment alignment() const { return alignment_; } + // TODO(jamescook): Replace with alignment(). + ShelfAlignment GetAlignment() const { return alignment_; } + void SetAlignment(ShelfAlignment alignment); + + // Returns true if the shelf alignment is horizontal (i.e. at the bottom). + bool IsHorizontalAlignment() const; + + // Returns a value based on shelf alignment. + int SelectValueForShelfAlignment(int bottom, int left, int right) const; + + // Returns |horizontal| is shelf is horizontal, otherwise |vertical|. + int PrimaryAxisValue(int horizontal, int vertical) const; + + ShelfAutoHideBehavior auto_hide_behavior() const { + return auto_hide_behavior_; + } + void SetAutoHideBehavior(ShelfAutoHideBehavior behavior); + + ShelfAutoHideState GetAutoHideState() const; + + // Invoke when the auto-hide state may have changed (for example, when the + // system tray bubble opens it should force the shelf to be visible). + void UpdateAutoHideState(); + + ShelfBackgroundType GetBackgroundType() const; + + // Whether the shelf view is visible. + // TODO(jamescook): Consolidate this with GetVisibilityState(). + bool IsVisible() const; + + void UpdateVisibilityState(); + + ShelfVisibilityState GetVisibilityState() const; + + // Returns the ideal bounds of the shelf assuming it is visible. + gfx::Rect GetIdealBounds(); + + gfx::Rect GetUserWorkAreaBounds() const; + + // Updates the icon position given the current window bounds. This is used + // when dragging panels to reposition them with respect to the other panels. + void UpdateIconPositionForPanel(WmWindow* window); + + // Returns the screen bounds of the item for the specified window. If there is + // no item for the specified window an empty rect is returned. + gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window); + + // Launch a 0-indexed shelf item in the shelf. A negative index launches the + // last shelf item in the shelf. + static void LaunchShelfItem(int item_index); + + // Activates the shelf item specified by the index in the list of shelf items. + static void ActivateShelfItem(int item_index); + + // Handles a gesture |event| coming from a source outside the shelf widget + // (e.g. the status area widget). Allows support for behaviors like toggling + // auto-hide with a swipe, even if that gesture event hits another window. + // Returns true if the event was handled. + bool ProcessGestureEvent(const ui::GestureEvent& event); + + void AddObserver(WmShelfObserver* observer); + void RemoveObserver(WmShelfObserver* observer); + + void NotifyShelfIconPositionsChanged(); + StatusAreaWidget* GetStatusAreaWidget() const; + + void SetVirtualKeyboardBoundsForTesting(const gfx::Rect& bounds); + ShelfLockingManager* GetShelfLockingManagerForTesting(); + ShelfView* GetShelfViewForTesting(); + + protected: + // ShelfLayoutManagerObserver: + void WillDeleteShelfLayoutManager() override; + void WillChangeVisibilityState(ShelfVisibilityState new_state) override; + void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; + void OnBackgroundUpdated(ShelfBackgroundType background_type, + AnimationChangeType change_type) override; + + private: + class AutoHideEventHandler; + friend class ShelfLayoutManagerTest; + + // Layout manager for the shelf container window. Instances are constructed by + // ShelfWidget and lifetimes are managed by the container windows themselves. + ShelfLayoutManager* shelf_layout_manager_ = nullptr; + + std::unique_ptr<ShelfWidget> shelf_widget_; + + // Internal implementation detail. Do not expose externally. Owned by views + // hierarchy. Null before login and in secondary display init. + ShelfView* shelf_view_ = nullptr; + + // These initial values hide the shelf until user preferences are available. + ShelfAlignment alignment_ = SHELF_ALIGNMENT_BOTTOM_LOCKED; + ShelfAutoHideBehavior auto_hide_behavior_ = SHELF_AUTO_HIDE_ALWAYS_HIDDEN; + + // Sets shelf alignment to bottom during login and screen lock. + std::unique_ptr<ShelfLockingManager> shelf_locking_manager_; + + base::ObserverList<WmShelfObserver> observers_; + + // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. + // TODO(mash): Facilitate simliar functionality in mash: crbug.com/631216 + std::unique_ptr<AutoHideEventHandler> auto_hide_event_handler_; + + // Forwards touch gestures on a bezel sensor to the shelf. + // TODO(mash): Facilitate simliar functionality in mash: crbug.com/636647 + std::unique_ptr<ShelfBezelEventHandler> bezel_event_handler_; + + DISALLOW_COPY_AND_ASSIGN(WmShelf); +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_WM_SHELF_H_
diff --git a/ash/common/shelf/wm_shelf_observer.h b/ash/common/shelf/wm_shelf_observer.h new file mode 100644 index 0000000..d137692 --- /dev/null +++ b/ash/common/shelf/wm_shelf_observer.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_WM_SHELF_OBSERVER_H_ +#define ASH_COMMON_SHELF_WM_SHELF_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_types.h" + +namespace ash { + +enum class AnimationChangeType; + +// Used to observe changes to the shelf. +class ASH_EXPORT WmShelfObserver { + public: + virtual void OnBackgroundTypeChanged(ShelfBackgroundType background_type, + AnimationChangeType change_type) {} + virtual void WillChangeVisibilityState(ShelfVisibilityState new_state) {} + virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) {} + virtual void OnShelfIconPositionsChanged() {} + + protected: + virtual ~WmShelfObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SHELF_WM_SHELF_OBSERVER_H_
diff --git a/ash/common/shelf/wm_shelf_util.cc b/ash/common/shelf/wm_shelf_util.cc new file mode 100644 index 0000000..05ba442 --- /dev/null +++ b/ash/common/shelf/wm_shelf_util.cc
@@ -0,0 +1,14 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/shelf/wm_shelf_util.h" + +namespace ash { + +bool IsHorizontalAlignment(ShelfAlignment alignment) { + return alignment == SHELF_ALIGNMENT_BOTTOM || + alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED; +} + +} // namespace ash
diff --git a/ash/common/shelf/wm_shelf_util.h b/ash/common/shelf/wm_shelf_util.h new file mode 100644 index 0000000..98bb1ad --- /dev/null +++ b/ash/common/shelf/wm_shelf_util.h
@@ -0,0 +1,19 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SHELF_WM_SHELF_UTIL_H_ +#define ASH_COMMON_SHELF_WM_SHELF_UTIL_H_ + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_types.h" + +namespace ash { + +// Returns true if the shelf |alignment| is horizontal. +// TODO(jamescook): Remove this in favor of WmShelf::IsHorizontalAlignment(). +ASH_EXPORT bool IsHorizontalAlignment(ShelfAlignment alignment); + +} // namespace ash + +#endif // ASH_COMMON_SHELF_WM_SHELF_UTIL_H_
diff --git a/ash/common/system/OWNERS b/ash/common/system/OWNERS new file mode 100644 index 0000000..dd3b192 --- /dev/null +++ b/ash/common/system/OWNERS
@@ -0,0 +1 @@ +file://ash/system/OWNERS
diff --git a/ash/common/system/accessibility_observer.h b/ash/common/system/accessibility_observer.h new file mode 100644 index 0000000..5de1ea2b --- /dev/null +++ b/ash/common/system/accessibility_observer.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_ACCESSIBILITY_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_ACCESSIBILITY_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "ash/common/accessibility_types.h" + +namespace ash { + +class ASH_EXPORT AccessibilityObserver { + public: + virtual ~AccessibilityObserver() {} + + // Notifies when accessibility mode changes. + virtual void OnAccessibilityModeChanged( + AccessibilityNotificationVisibility notify) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_ACCESSIBILITY_OBSERVER_H_
diff --git a/ash/common/system/brightness_control_delegate.h b/ash/common/system/brightness_control_delegate.h new file mode 100644 index 0000000..d85ce419 --- /dev/null +++ b/ash/common/system/brightness_control_delegate.h
@@ -0,0 +1,39 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_BRIGHTNESS_CONTROL_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_BRIGHTNESS_CONTROL_DELEGATE_H_ + +#include "base/callback.h" + +namespace ui { +class Accelerator; +} // namespace ui + +namespace ash { + +// Delegate for controlling the brightness. +class BrightnessControlDelegate { + public: + virtual ~BrightnessControlDelegate() {} + + // Handles an accelerator-driven request to decrease or increase the screen + // brightness. + virtual void HandleBrightnessDown(const ui::Accelerator& accelerator) = 0; + virtual void HandleBrightnessUp(const ui::Accelerator& accelerator) = 0; + + // Requests that the brightness be set to |percent|, in the range + // [0.0, 100.0]. |gradual| specifies whether the transition to the new + // brightness should be animated or instantaneous. + virtual void SetBrightnessPercent(double percent, bool gradual) = 0; + + // Asynchronously invokes |callback| with the current brightness, in the range + // [0.0, 100.0]. + virtual void GetBrightnessPercent( + const base::Callback<void(double)>& callback) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_BRIGHTNESS_CONTROL_DELEGATE_H_
diff --git a/ash/common/system/chromeos/DEPS b/ash/common/system/chromeos/DEPS new file mode 100644 index 0000000..5402b33 --- /dev/null +++ b/ash/common/system/chromeos/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+grit/ui_chromeos_strings.h", +]
diff --git a/ash/common/system/chromeos/audio/audio_detailed_view.cc b/ash/common/system/chromeos/audio/audio_detailed_view.cc new file mode 100644 index 0000000..b205903 --- /dev/null +++ b/ash/common/system/chromeos/audio/audio_detailed_view.cc
@@ -0,0 +1,198 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/audio/audio_detailed_view.h" + +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/utf_string_conversions.h" +#include "chromeos/audio/cras_audio_handler.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/separator.h" + +namespace { + +base::string16 GetAudioDeviceName(const chromeos::AudioDevice& device) { + switch (device.type) { + case chromeos::AUDIO_TYPE_FRONT_MIC: + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_FRONT_MIC); + case chromeos::AUDIO_TYPE_HEADPHONE: + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HEADPHONE); + case chromeos::AUDIO_TYPE_INTERNAL_SPEAKER: + return l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_SPEAKER); + case chromeos::AUDIO_TYPE_INTERNAL_MIC: + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_MIC); + case chromeos::AUDIO_TYPE_REAR_MIC: + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_REAR_MIC); + case chromeos::AUDIO_TYPE_USB: + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_AUDIO_USB_DEVICE, + base::UTF8ToUTF16(device.display_name)); + case chromeos::AUDIO_TYPE_BLUETOOTH: + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_AUDIO_BLUETOOTH_DEVICE, + base::UTF8ToUTF16(device.display_name)); + case chromeos::AUDIO_TYPE_HDMI: + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HDMI_DEVICE, + base::UTF8ToUTF16(device.display_name)); + case chromeos::AUDIO_TYPE_MIC: + return l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_AUDIO_MIC_JACK_DEVICE); + default: + return base::UTF8ToUTF16(device.display_name); + } +} + +} // namespace + +using chromeos::CrasAudioHandler; + +namespace ash { +namespace tray { + +AudioDetailedView::AudioDetailedView(SystemTrayItem* owner) + : TrayDetailsView(owner) { + CreateItems(); + Update(); +} + +AudioDetailedView::~AudioDetailedView() {} + +void AudioDetailedView::Update() { + UpdateAudioDevices(); + Layout(); +} + +void AudioDetailedView::AddInputHeader() { + AddScrollListInfoItem(IDS_ASH_STATUS_TRAY_AUDIO_INPUT, + kSystemMenuAudioInputIcon); +} + +void AudioDetailedView::AddOutputHeader() { + AddScrollListInfoItem(IDS_ASH_STATUS_TRAY_AUDIO_OUTPUT, + kSystemMenuAudioOutputIcon); +} + +void AudioDetailedView::AddScrollListInfoItem(int text_id, + const gfx::VectorIcon& icon) { + TriView* header = TrayPopupUtils::CreateDefaultRowView(); + TrayPopupUtils::ConfigureAsStickyHeader(header); + views::ImageView* image_view = TrayPopupUtils::CreateMainImageView(); + image_view->SetImage(gfx::CreateVectorIcon( + icon, GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ProminentButtonColor))); + header->AddView(TriView::Container::START, image_view); + + views::Label* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(l10n_util::GetStringUTF16(text_id)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); + style.SetupLabel(label); + header->AddView(TriView::Container::CENTER, label); + + header->SetContainerVisible(TriView::Container::END, false); + scroll_content()->AddChildView(header); +} + +HoverHighlightView* AudioDetailedView::AddScrollListItem( + const base::string16& text, + bool highlight, + bool checked) { + HoverHighlightView* container = new HoverHighlightView(this); + + container->AddLabelRowMd(text); + if (checked) { + gfx::ImageSkia check_mark = gfx::CreateVectorIcon( + gfx::VectorIconId::CHECK_CIRCLE, gfx::kGoogleGreen700); + container->AddRightIcon(check_mark, check_mark.width()); + container->SetRightViewVisible(true); + container->SetAccessiblityState( + HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); + } else { + container->SetAccessiblityState( + HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); + } + + scroll_content()->AddChildView(container); + return container; +} + +void AudioDetailedView::CreateItems() { + CreateScrollableList(); + CreateTitleRow(IDS_ASH_STATUS_TRAY_AUDIO); +} + +void AudioDetailedView::UpdateAudioDevices() { + output_devices_.clear(); + input_devices_.clear(); + chromeos::AudioDeviceList devices; + CrasAudioHandler::Get()->GetAudioDevices(&devices); + for (size_t i = 0; i < devices.size(); ++i) { + // Don't display keyboard mic or aokr type. + if (!devices[i].is_for_simple_usage()) + continue; + if (devices[i].is_input) + input_devices_.push_back(devices[i]); + else + output_devices_.push_back(devices[i]); + } + UpdateScrollableList(); +} + +void AudioDetailedView::UpdateScrollableList() { + scroll_content()->RemoveAllChildViews(true); + device_map_.clear(); + + // Add audio output devices. + const bool has_output_devices = output_devices_.size() > 0; + if (has_output_devices) + AddOutputHeader(); + + for (size_t i = 0; i < output_devices_.size(); ++i) { + HoverHighlightView* container = AddScrollListItem( + GetAudioDeviceName(output_devices_[i]), false /* highlight */, + output_devices_[i].active); /* checkmark if active */ + device_map_[container] = output_devices_[i]; + } + + if (has_output_devices) { + scroll_content()->AddChildView( + TrayPopupUtils::CreateListSubHeaderSeparator()); + } + + // Add audio input devices. + const bool has_input_devices = input_devices_.size() > 0; + if (has_input_devices) + AddInputHeader(); + + for (size_t i = 0; i < input_devices_.size(); ++i) { + HoverHighlightView* container = AddScrollListItem( + GetAudioDeviceName(input_devices_[i]), false /* highlight */, + input_devices_[i].active); /* checkmark if active */ + device_map_[container] = input_devices_[i]; + } + + scroll_content()->SizeToPreferredSize(); + scroller()->Layout(); +} + +void AudioDetailedView::HandleViewClicked(views::View* view) { + AudioDeviceMap::iterator iter = device_map_.find(view); + if (iter == device_map_.end()) + return; + chromeos::AudioDevice device = iter->second; + CrasAudioHandler::Get()->SwitchToDevice(device, true, + CrasAudioHandler::ACTIVATE_BY_USER); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/chromeos/audio/audio_detailed_view.h b/ash/common/system/chromeos/audio/audio_detailed_view.h new file mode 100644 index 0000000..1b33e44 --- /dev/null +++ b/ash/common/system/chromeos/audio/audio_detailed_view.h
@@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_AUDIO_DETAILED_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_AUDIO_DETAILED_VIEW_H_ + +#include <map> + +#include "ash/common/system/tray/tray_details_view.h" +#include "base/macros.h" +#include "chromeos/audio/audio_device.h" + +namespace gfx { +struct VectorIcon; +} + +namespace views { +class View; +} + +namespace ash { +class HoverHighlightView; + +namespace tray { + +class AudioDetailedView : public TrayDetailsView { + public: + explicit AudioDetailedView(SystemTrayItem* owner); + + ~AudioDetailedView() override; + + void Update(); + + private: + // Helper functions to add non-clickable header rows within the scrollable + // list. + void AddInputHeader(); + void AddOutputHeader(); + void AddScrollListInfoItem(int text_id, const gfx::VectorIcon& icon); + + HoverHighlightView* AddScrollListItem(const base::string16& text, + bool highlight, + bool checked); + + void CreateItems(); + + void UpdateScrollableList(); + void UpdateAudioDevices(); + + // TrayDetailsView: + void HandleViewClicked(views::View* view) override; + + typedef std::map<views::View*, chromeos::AudioDevice> AudioDeviceMap; + + chromeos::AudioDeviceList output_devices_; + chromeos::AudioDeviceList input_devices_; + AudioDeviceMap device_map_; + + DISALLOW_COPY_AND_ASSIGN(AudioDetailedView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_AUDIO_DETAILED_VIEW_H_
diff --git a/ash/common/system/chromeos/audio/tray_audio.cc b/ash/common/system/chromeos/audio/tray_audio.cc new file mode 100644 index 0000000..11fa71e77 --- /dev/null +++ b/ash/common/system/chromeos/audio/tray_audio.cc
@@ -0,0 +1,209 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/audio/tray_audio.h" + +#include "ash/common/system/chromeos/audio/audio_detailed_view.h" +#include "ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.h" +#include "ash/common/system/chromeos/audio/volume_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "ui/display/display.h" +#include "ui/display/manager/managed_display_info.h" +#include "ui/display/screen.h" +#include "ui/views/view.h" + +namespace ash { + +using chromeos::CrasAudioHandler; +using chromeos::DBusThreadManager; +using system::TrayAudioDelegate; +using system::TrayAudioDelegateChromeOs; + +TrayAudio::TrayAudio(SystemTray* system_tray) + : TrayImageItem(system_tray, kSystemTrayVolumeMuteIcon, UMA_AUDIO), + audio_delegate_(new TrayAudioDelegateChromeOs()), + volume_view_(nullptr), + pop_up_volume_view_(false), + audio_detail_view_(nullptr) { + if (CrasAudioHandler::IsInitialized()) + CrasAudioHandler::Get()->AddAudioObserver(this); + display::Screen::GetScreen()->AddObserver(this); + DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); +} + +TrayAudio::~TrayAudio() { + DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); + display::Screen::GetScreen()->RemoveObserver(this); + if (CrasAudioHandler::IsInitialized()) + CrasAudioHandler::Get()->RemoveAudioObserver(this); +} + +// static +void TrayAudio::ShowPopUpVolumeView() { + // Show the popup on all monitors with a system tray. + for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { + SystemTray* system_tray = root->GetRootWindowController()->GetSystemTray(); + if (!system_tray) + continue; + // Show the popup by simulating a volume change. The provided node id and + // volume value are ignored. + system_tray->GetTrayAudio()->OnOutputNodeVolumeChanged(0, 0); + } +} + +bool TrayAudio::GetInitialVisibility() { + return audio_delegate_->IsOutputAudioMuted(); +} + +views::View* TrayAudio::CreateDefaultView(LoginStatus status) { + volume_view_ = new tray::VolumeView(this, audio_delegate_.get(), true); + return volume_view_; +} + +views::View* TrayAudio::CreateDetailedView(LoginStatus status) { + if (pop_up_volume_view_) { + volume_view_ = new tray::VolumeView(this, audio_delegate_.get(), false); + return volume_view_; + } else { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DETAILED_AUDIO_VIEW); + audio_detail_view_ = new tray::AudioDetailedView(this); + return audio_detail_view_; + } +} + +void TrayAudio::DestroyDefaultView() { + volume_view_ = NULL; +} + +void TrayAudio::DestroyDetailedView() { + if (audio_detail_view_) { + audio_detail_view_ = nullptr; + } else if (volume_view_) { + volume_view_ = nullptr; + pop_up_volume_view_ = false; + } +} + +bool TrayAudio::ShouldShowShelf() const { + return !pop_up_volume_view_; +} + +void TrayAudio::OnOutputNodeVolumeChanged(uint64_t /* node_id */, + int /* volume */) { + float percent = + static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f; + if (tray_view()) + tray_view()->SetVisible(GetInitialVisibility()); + + if (volume_view_) { + volume_view_->SetVolumeLevel(percent); + SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); + return; + } + pop_up_volume_view_ = true; + PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); +} + +void TrayAudio::OnOutputMuteChanged(bool /* mute_on */, bool system_adjust) { + if (tray_view()) + tray_view()->SetVisible(GetInitialVisibility()); + + if (volume_view_) { + volume_view_->Update(); + SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); + } else if (!system_adjust) { + pop_up_volume_view_ = true; + PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); + } +} + +void TrayAudio::OnAudioNodesChanged() { + Update(); +} + +void TrayAudio::OnActiveOutputNodeChanged() { + Update(); +} + +void TrayAudio::OnActiveInputNodeChanged() { + Update(); +} + +void TrayAudio::ChangeInternalSpeakerChannelMode() { + // Swap left/right channel only if it is in Yoga mode. + system::TrayAudioDelegate::AudioChannelMode channel_mode = + system::TrayAudioDelegate::NORMAL; + if (display::Display::HasInternalDisplay()) { + const display::ManagedDisplayInfo& display_info = + WmShell::Get()->GetDisplayInfo(display::Display::InternalDisplayId()); + if (display_info.GetActiveRotation() == display::Display::ROTATE_180) + channel_mode = system::TrayAudioDelegate::LEFT_RIGHT_SWAPPED; + } + + audio_delegate_->SetInternalSpeakerChannelMode(channel_mode); +} + +void TrayAudio::OnDisplayAdded(const display::Display& new_display) { + if (!new_display.IsInternal()) + return; + ChangeInternalSpeakerChannelMode(); + + // This event will be triggered when the lid of the device is opened to exit + // the docked mode, we should always start or re-start HDMI re-discovering + // grace period right after this event. + audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(true); +} + +void TrayAudio::OnDisplayRemoved(const display::Display& old_display) { + if (!old_display.IsInternal()) + return; + ChangeInternalSpeakerChannelMode(); + + // This event will be triggered when the lid of the device is closed to enter + // the docked mode, we should always start or re-start HDMI re-discovering + // grace period right after this event. + audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(true); +} + +void TrayAudio::OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) { + if (!display.IsInternal()) + return; + + if (changed_metrics & display::DisplayObserver::DISPLAY_METRIC_ROTATION) + ChangeInternalSpeakerChannelMode(); + + // The event could be triggered multiple times during the HDMI display + // transition, we don't need to restart HDMI re-discovering grace period + // it is already started earlier. + audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(false); +} + +void TrayAudio::SuspendDone(const base::TimeDelta& sleep_duration) { + // This event is triggered when the device resumes after earlier suspension, + // we should always start or re-start HDMI re-discovering + // grace period right after this event. + audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(true); +} + +void TrayAudio::Update() { + if (tray_view()) + tray_view()->SetVisible(GetInitialVisibility()); + if (volume_view_) { + volume_view_->SetVolumeLevel( + static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f); + volume_view_->Update(); + } + + if (audio_detail_view_) + audio_detail_view_->Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/audio/tray_audio.h b/ash/common/system/chromeos/audio/tray_audio.h new file mode 100644 index 0000000..d5876447 --- /dev/null +++ b/ash/common/system/chromeos/audio/tray_audio.h
@@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_ + +#include <stdint.h> + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/system/tray/tray_image_item.h" +#include "base/macros.h" +#include "chromeos/audio/cras_audio_handler.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/display/display_observer.h" + +namespace ash { + +namespace system { +class TrayAudioDelegate; +} + +namespace tray { +class AudioDetailedView; +class VolumeView; +} + +// The system tray item for audio input and output. +class ASH_EXPORT TrayAudio : public TrayImageItem, + public chromeos::CrasAudioHandler::AudioObserver, + public display::DisplayObserver, + public chromeos::PowerManagerClient::Observer { + public: + explicit TrayAudio(SystemTray* system_tray); + ~TrayAudio() override; + + // Temporarily shows the pop-up volume slider on all displays. Used by ARC + // when an Android app changes the system volume. + static void ShowPopUpVolumeView(); + + tray::VolumeView* volume_view_for_testing() { return volume_view_; } + bool pop_up_volume_view_for_testing() { return pop_up_volume_view_; } + + private: + // Overridden from display::DisplayObserver. + void OnDisplayAdded(const display::Display& new_display) override; + void OnDisplayRemoved(const display::Display& old_display) override; + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) override; + + // Overridden from TrayImageItem. + bool GetInitialVisibility() override; + + // Overridden from SystemTrayItem. + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + bool ShouldShowShelf() const override; + + // Overridden from CrasAudioHandler::AudioObserver. + void OnOutputNodeVolumeChanged(uint64_t node_id, int volume) override; + void OnOutputMuteChanged(bool mute_on, bool system_adjust) override; + void OnAudioNodesChanged() override; + void OnActiveOutputNodeChanged() override; + void OnActiveInputNodeChanged() override; + + // Overridden from chromeos::PowerManagerClient::Observer. + void SuspendDone(const base::TimeDelta& sleep_duration) override; + + // Swaps the left and right channels on yoga devices based on orientation. + void ChangeInternalSpeakerChannelMode(); + + // Updates the UI views. + void Update(); + + // TODO(jamescook): Remove this delegate and inline all the code. + std::unique_ptr<system::TrayAudioDelegate> audio_delegate_; + tray::VolumeView* volume_view_; + + // True if VolumeView should be created for accelerator pop up; + // Otherwise, it should be created for detailed view in ash tray bubble. + bool pop_up_volume_view_; + + tray::AudioDetailedView* audio_detail_view_; + + DISALLOW_COPY_AND_ASSIGN(TrayAudio); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_H_
diff --git a/ash/common/system/chromeos/audio/tray_audio_delegate.h b/ash/common/system/chromeos/audio/tray_audio_delegate.h new file mode 100644 index 0000000..39d4b2a --- /dev/null +++ b/ash/common/system/chromeos/audio/tray_audio_delegate.h
@@ -0,0 +1,67 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_DELEGATE_H_ + +namespace gfx { +struct VectorIcon; +} + +namespace ash { +namespace system { + +class TrayAudioDelegate { + public: + enum { kNoAudioDeviceIcon = -1 }; + enum AudioChannelMode { + NORMAL, + LEFT_RIGHT_SWAPPED, + }; + + virtual ~TrayAudioDelegate() {} + + // Sets the volume level of the output device to the minimum level which is + // deemed to be audible. + virtual void AdjustOutputVolumeToAudibleLevel() = 0; + + // Gets the default level in the range 0%-100% at which the output device + // should be muted. + virtual int GetOutputDefaultVolumeMuteLevel() = 0; + + // Gets the MD icon to use for the active output device. + virtual const gfx::VectorIcon& GetActiveOutputDeviceVectorIcon() = 0; + + // Returns the volume level of the output device in the range 0%-100%. + virtual int GetOutputVolumeLevel() = 0; + + // Returns true if the device has alternative inputs or outputs. + virtual bool HasAlternativeSources() = 0; + + // Returns whether the output volume is muted. + virtual bool IsOutputAudioMuted() = 0; + + // Sets the mute state of the output device. + virtual void SetOutputAudioIsMuted(bool is_muted) = 0; + + // Sets the volume level of the output device in the range 0%-100% + virtual void SetOutputVolumeLevel(int level) = 0; + + // Sets the internal speaker's channel mode. + virtual void SetInternalSpeakerChannelMode(AudioChannelMode mode) = 0; + + // If necessary, sets the starting point for re-discovering the active HDMI + // output device caused by device entering/exiting docking mode, HDMI display + // changing resolution, or chromeos device suspend/resume. If + // |force_rediscovering| is true, it will force to set the starting point for + // re-discovering the active HDMI output device again if it has been in the + // middle of rediscovering the HDMI active output device. + virtual void SetActiveHDMIOutoutRediscoveringIfNecessary( + bool force_rediscovering) = 0; +}; + +} // namespace system +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_DELEGATE_H_
diff --git a/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc b/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc new file mode 100644 index 0000000..dfe5def --- /dev/null +++ b/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.cc
@@ -0,0 +1,75 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.h" + +#include "ash/resources/vector_icons/vector_icons.h" +#include "chromeos/audio/cras_audio_handler.h" +#include "ui/gfx/paint_vector_icon.h" + +using chromeos::CrasAudioHandler; + +namespace ash { +namespace system { + +void TrayAudioDelegateChromeOs::AdjustOutputVolumeToAudibleLevel() { + CrasAudioHandler::Get()->AdjustOutputVolumeToAudibleLevel(); +} + +int TrayAudioDelegateChromeOs::GetOutputDefaultVolumeMuteLevel() { + return CrasAudioHandler::Get()->GetOutputDefaultVolumeMuteThreshold(); +} + +int TrayAudioDelegateChromeOs::GetOutputVolumeLevel() { + return CrasAudioHandler::Get()->GetOutputVolumePercent(); +} + +const gfx::VectorIcon& +TrayAudioDelegateChromeOs::GetActiveOutputDeviceVectorIcon() { + chromeos::AudioDevice device; + if (CrasAudioHandler::Get()->GetPrimaryActiveOutputDevice(&device)) { + if (device.type == chromeos::AUDIO_TYPE_HEADPHONE) + return kSystemMenuHeadsetIcon; + if (device.type == chromeos::AUDIO_TYPE_USB) + return kSystemMenuUsbIcon; + if (device.type == chromeos::AUDIO_TYPE_BLUETOOTH) + return kSystemMenuBluetoothIcon; + if (device.type == chromeos::AUDIO_TYPE_HDMI) + return kSystemMenuHdmiIcon; + } + return gfx::kNoneIcon; +} + +bool TrayAudioDelegateChromeOs::HasAlternativeSources() { + CrasAudioHandler* audio_handler = CrasAudioHandler::Get(); + return (audio_handler->has_alternative_output() || + audio_handler->has_alternative_input()); +} + +bool TrayAudioDelegateChromeOs::IsOutputAudioMuted() { + return CrasAudioHandler::Get()->IsOutputMuted(); +} + +void TrayAudioDelegateChromeOs::SetOutputAudioIsMuted(bool is_muted) { + CrasAudioHandler::Get()->SetOutputMute(is_muted); +} + +void TrayAudioDelegateChromeOs::SetOutputVolumeLevel(int level) { + CrasAudioHandler::Get()->SetOutputVolumePercent(level); +} + +void TrayAudioDelegateChromeOs::SetInternalSpeakerChannelMode( + AudioChannelMode mode) { + CrasAudioHandler::Get()->SwapInternalSpeakerLeftRightChannel( + mode == LEFT_RIGHT_SWAPPED); +} + +void TrayAudioDelegateChromeOs::SetActiveHDMIOutoutRediscoveringIfNecessary( + bool force_rediscovering) { + CrasAudioHandler::Get()->SetActiveHDMIOutoutRediscoveringIfNecessary( + force_rediscovering); +} + +} // namespace system +} // namespace ash
diff --git a/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.h b/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.h new file mode 100644 index 0000000..df82e3b --- /dev/null +++ b/ash/common/system/chromeos/audio/tray_audio_delegate_chromeos.h
@@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/audio/tray_audio_delegate.h" + +namespace ash { +namespace system { + +class ASH_EXPORT TrayAudioDelegateChromeOs : public TrayAudioDelegate { + public: + ~TrayAudioDelegateChromeOs() override {} + + // Overridden from TrayAudioDelegate. + void AdjustOutputVolumeToAudibleLevel() override; + int GetOutputDefaultVolumeMuteLevel() override; + int GetOutputVolumeLevel() override; + const gfx::VectorIcon& GetActiveOutputDeviceVectorIcon() override; + bool HasAlternativeSources() override; + bool IsOutputAudioMuted() override; + void SetOutputAudioIsMuted(bool is_muted) override; + void SetOutputVolumeLevel(int level) override; + void SetInternalSpeakerChannelMode(AudioChannelMode mode) override; + void SetActiveHDMIOutoutRediscoveringIfNecessary( + bool force_rediscovering) override; +}; + +} // namespace system +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_
diff --git a/ash/common/system/chromeos/audio/tray_audio_unittest.cc b/ash/common/system/chromeos/audio/tray_audio_unittest.cc new file mode 100644 index 0000000..e0a21ac --- /dev/null +++ b/ash/common/system/chromeos/audio/tray_audio_unittest.cc
@@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/audio/tray_audio.h" + +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/test/ash_test.h" + +namespace ash { + +using TrayAudioTest = AshTest; + +// Tests that the volume popup view can be explicitly shown. +TEST_F(TrayAudioTest, ShowPopUpVolumeView) { + TrayAudio* tray_audio = GetPrimarySystemTray()->GetTrayAudio(); + ASSERT_TRUE(tray_audio); + + // The volume popup is not visible initially. + EXPECT_FALSE(tray_audio->volume_view_for_testing()); + EXPECT_FALSE(tray_audio->pop_up_volume_view_for_testing()); + + // Simulate ARC asking to show the volume view. + TrayAudio::ShowPopUpVolumeView(); + + // Volume view is now visible. + EXPECT_TRUE(tray_audio->volume_view_for_testing()); + EXPECT_TRUE(tray_audio->pop_up_volume_view_for_testing()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/audio/volume_view.cc b/ash/common/system/chromeos/audio/volume_view.cc new file mode 100644 index 0000000..47cfabe --- /dev/null +++ b/ash/common/system/chromeos/audio/volume_view.cc
@@ -0,0 +1,248 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/audio/volume_view.h" + +#include <algorithm> + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/system/chromeos/audio/tray_audio_delegate.h" +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_container.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icon_types.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/custom_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/slider.h" +#include "ui/views/layout/fill_layout.h" + +namespace { + +const gfx::VectorIcon* const kVolumeLevelIcons[] = { + &ash::kSystemMenuVolumeMuteIcon, // Muted. + &ash::kSystemMenuVolumeLowIcon, // Low volume. + &ash::kSystemMenuVolumeMediumIcon, // Medium volume. + &ash::kSystemMenuVolumeHighIcon, // High volume. + &ash::kSystemMenuVolumeHighIcon, // Full volume. +}; + +} // namespace + +namespace ash { +namespace tray { + +class VolumeButton : public ButtonListenerActionableView { + public: + VolumeButton(SystemTrayItem* owner, + views::ButtonListener* listener, + system::TrayAudioDelegate* audio_delegate) + : ButtonListenerActionableView(owner, + TrayPopupInkDropStyle::HOST_CENTERED, + listener), + audio_delegate_(audio_delegate), + image_(TrayPopupUtils::CreateMainImageView()), + image_index_(-1) { + TrayPopupUtils::ConfigureContainer(TriView::Container::START, this); + AddChildView(image_); + SetInkDropMode(InkDropMode::ON); + Update(); + + set_notify_enter_exit_on_child(true); + } + + ~VolumeButton() override {} + + void Update() { + float level = + static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f; + int volume_levels = arraysize(kVolumeLevelIcons) - 1; + int image_index = + audio_delegate_->IsOutputAudioMuted() + ? 0 + : (level == 1.0 ? volume_levels + : std::max(1, static_cast<int>(std::ceil( + level * (volume_levels - 1))))); + gfx::ImageSkia image_skia = + gfx::CreateVectorIcon(*kVolumeLevelIcons[image_index], kMenuIconColor); + image_->SetImage(&image_skia); + image_index_ = image_index; + } + + private: + // views::View: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->SetName( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VOLUME_MUTE)); + node_data->role = ui::AX_ROLE_TOGGLE_BUTTON; + if (audio_delegate_->IsOutputAudioMuted()) + node_data->AddStateFlag(ui::AX_STATE_PRESSED); + } + + system::TrayAudioDelegate* audio_delegate_; + views::ImageView* image_; + int image_index_; + + DISALLOW_COPY_AND_ASSIGN(VolumeButton); +}; + +VolumeView::VolumeView(SystemTrayItem* owner, + system::TrayAudioDelegate* audio_delegate, + bool is_default_view) + : owner_(owner), + tri_view_(TrayPopupUtils::CreateMultiTargetRowView()), + audio_delegate_(audio_delegate), + more_button_(nullptr), + icon_(nullptr), + slider_(nullptr), + device_type_(nullptr), + is_default_view_(is_default_view) { + SetLayoutManager(new views::FillLayout); + AddChildView(tri_view_); + + icon_ = new VolumeButton(owner, this, audio_delegate_); + tri_view_->AddView(TriView::Container::START, icon_); + + slider_ = TrayPopupUtils::CreateSlider(this); + slider_->SetValue( + static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f); + slider_->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VOLUME)); + tri_view_->AddView(TriView::Container::CENTER, slider_); + + set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + + if (!is_default_view_) { + tri_view_->SetContainerVisible(TriView::Container::END, false); + Update(); + return; + } + + more_button_ = new ButtonListenerActionableView( + owner_, TrayPopupInkDropStyle::INSET_BOUNDS, this); + TrayPopupUtils::ConfigureContainer(TriView::Container::END, more_button_); + + more_button_->SetInkDropMode(views::InkDropHostView::InkDropMode::ON); + more_button_->SetBorder(views::CreateEmptyBorder(gfx::Insets( + 0, kTrayPopupButtonEndMargin))); + tri_view_->AddView(TriView::Container::END, more_button_); + + device_type_ = TrayPopupUtils::CreateMoreImageView(); + device_type_->SetVisible(false); + more_button_->AddChildView(device_type_); + + more_button_->AddChildView(TrayPopupUtils::CreateMoreImageView()); + + Update(); +} + +VolumeView::~VolumeView() {} + +void VolumeView::Update() { + icon_->Update(); + slider_->UpdateState(!audio_delegate_->IsOutputAudioMuted()); + UpdateDeviceTypeAndMore(); + Layout(); +} + +void VolumeView::SetVolumeLevel(float percent) { + // Update volume level to the current audio level. + Update(); + + // Slider's value is in finer granularity than audio volume level(0.01), + // there will be a small discrepancy between slider's value and volume level + // on audio side. To avoid the jittering in slider UI, do not set change + // slider value if the change is less than 1%. + if (std::abs(percent - slider_->value()) < 0.01) + return; + slider_->SetValue(percent); + // It is possible that the volume was (un)muted, but the actual volume level + // did not change. In that case, setting the value of the slider won't + // trigger an update. So explicitly trigger an update. + Update(); + slider_->set_enable_accessibility_events(true); +} + +void VolumeView::UpdateDeviceTypeAndMore() { + bool show_more = is_default_view_ && audio_delegate_->HasAlternativeSources(); + + if (!show_more) + return; + + const gfx::VectorIcon& device_icon = + audio_delegate_->GetActiveOutputDeviceVectorIcon(); + const bool target_visibility = !device_icon.is_empty(); + if (target_visibility) + device_type_->SetImage(gfx::CreateVectorIcon(device_icon, kMenuIconColor)); + if (device_type_->visible() != target_visibility) { + device_type_->SetVisible(target_visibility); + device_type_->InvalidateLayout(); + } +} + +void VolumeView::HandleVolumeUp(int level) { + audio_delegate_->SetOutputVolumeLevel(level); + if (audio_delegate_->IsOutputAudioMuted() && + level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { + audio_delegate_->SetOutputAudioIsMuted(false); + } +} + +void VolumeView::HandleVolumeDown(int level) { + audio_delegate_->SetOutputVolumeLevel(level); + if (!audio_delegate_->IsOutputAudioMuted() && + level <= audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { + audio_delegate_->SetOutputAudioIsMuted(true); + } else if (audio_delegate_->IsOutputAudioMuted() && + level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { + audio_delegate_->SetOutputAudioIsMuted(false); + } +} + +void VolumeView::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (sender == icon_) { + bool mute_on = !audio_delegate_->IsOutputAudioMuted(); + audio_delegate_->SetOutputAudioIsMuted(mute_on); + if (!mute_on) + audio_delegate_->AdjustOutputVolumeToAudibleLevel(); + icon_->Update(); + } else if (sender == more_button_) { + owner_->TransitionDetailedView(); + } else { + NOTREACHED() << "Unexpected sender=" << sender->GetClassName() << "."; + } +} + +void VolumeView::SliderValueChanged(views::Slider* sender, + float value, + float old_value, + views::SliderChangeReason reason) { + if (reason == views::VALUE_CHANGED_BY_USER) { + int new_volume = static_cast<int>(value * 100); + int current_volume = audio_delegate_->GetOutputVolumeLevel(); + if (new_volume == current_volume) + return; + WmShell::Get()->RecordUserMetricsAction( + is_default_view_ ? UMA_STATUS_AREA_CHANGED_VOLUME_MENU + : UMA_STATUS_AREA_CHANGED_VOLUME_POPUP); + if (new_volume > current_volume) + HandleVolumeUp(new_volume); + else + HandleVolumeDown(new_volume); + } + icon_->Update(); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/chromeos/audio/volume_view.h b/ash/common/system/chromeos/audio/volume_view.h new file mode 100644 index 0000000..47835e5 --- /dev/null +++ b/ash/common/system/chromeos/audio/volume_view.h
@@ -0,0 +1,76 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_VOLUME_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_VOLUME_VIEW_H_ + +#include "base/macros.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/slider.h" +#include "ui/views/view.h" + +namespace views { +class CustomButton; +class ImageView; +} + +namespace ash { +class SystemTrayItem; +class TriView; + +namespace system { +class TrayAudioDelegate; +} + +namespace tray { +class VolumeButton; + +class VolumeView : public views::View, + public views::SliderListener, + public views::ButtonListener { + public: + VolumeView(SystemTrayItem* owner, + system::TrayAudioDelegate* audio_delegate, + bool is_default_view); + + ~VolumeView() override; + + void Update(); + + // Sets volume level on slider_, |percent| is ranged from [0.00] to [1.00]. + void SetVolumeLevel(float percent); + + private: + // Updates device_type_ icon and more_ button. + void UpdateDeviceTypeAndMore(); + void HandleVolumeUp(int percent); + void HandleVolumeDown(int percent); + + // SliderListener: + void SliderValueChanged(views::Slider* sender, + float value, + float old_value, + views::SliderChangeReason reason) override; + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + SystemTrayItem* owner_; + // The only immediate child view of |this|. All other view elements are added + // to the |tri_view_| to handle layout. + TriView* tri_view_; + system::TrayAudioDelegate* audio_delegate_; + views::CustomButton* more_button_; + VolumeButton* icon_; + views::Slider* slider_; + views::ImageView* device_type_; + bool is_default_view_; + + DISALLOW_COPY_AND_ASSIGN(VolumeView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_AUDIO_VOLUME_VIEW_H_
diff --git a/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc b/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc new file mode 100644 index 0000000..f36deec --- /dev/null +++ b/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.cc
@@ -0,0 +1,334 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.h" + +#include <memory> +#include <utility> + +#include "ash/common/system/system_notifier.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/bluetooth_device.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" +#include "ui/message_center/notification_types.h" + +using device::BluetoothAdapter; +using device::BluetoothAdapterFactory; +using device::BluetoothDevice; +using message_center::Notification; + +namespace { + +// Identifier for the discoverable notification. +const char kBluetoothDeviceDiscoverableNotificationId[] = + "chrome://settings/bluetooth/discoverable"; + +// Identifier for the pairing notification; the Bluetooth code ensures we +// only receive one pairing request at a time, so a single id is sufficient and +// means we "update" one notification if not handled rather than continually +// bugging the user. +const char kBluetoothDevicePairingNotificationId[] = + "chrome://settings/bluetooth/pairing"; + +// Identifier for the notification that a device has been paired with the +// system. +const char kBluetoothDevicePairedNotificationId[] = + "chrome://settings/bluetooth/paired"; + +// The BluetoothPairingNotificationDelegate handles user interaction with the +// pairing notification and sending the confirmation, rejection or cancellation +// back to the underlying device. +class BluetoothPairingNotificationDelegate + : public message_center::NotificationDelegate { + public: + BluetoothPairingNotificationDelegate(scoped_refptr<BluetoothAdapter> adapter, + const std::string& address); + + protected: + ~BluetoothPairingNotificationDelegate() override; + + // message_center::NotificationDelegate overrides. + void Close(bool by_user) override; + void ButtonClick(int button_index) override; + + private: + // Buttons that appear in notifications. + enum Button { BUTTON_ACCEPT, BUTTON_REJECT }; + + // Reference to the underlying Bluetooth Adapter, holding onto this + // reference ensures the adapter object doesn't go out of scope while we have + // a pending request and user interaction. + scoped_refptr<BluetoothAdapter> adapter_; + + // Address of the device being paired. + const std::string address_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothPairingNotificationDelegate); +}; + +BluetoothPairingNotificationDelegate::BluetoothPairingNotificationDelegate( + scoped_refptr<BluetoothAdapter> adapter, + const std::string& address) + : adapter_(adapter), address_(address) {} + +BluetoothPairingNotificationDelegate::~BluetoothPairingNotificationDelegate() {} + +void BluetoothPairingNotificationDelegate::Close(bool by_user) { + VLOG(1) << "Pairing notification closed. by_user = " << by_user; + // Ignore notification closes generated as a result of pairing completion. + if (!by_user) + return; + + // Cancel the pairing of the device, if the object still exists. + BluetoothDevice* device = adapter_->GetDevice(address_); + if (device) + device->CancelPairing(); +} + +void BluetoothPairingNotificationDelegate::ButtonClick(int button_index) { + VLOG(1) << "Pairing notification, button click: " << button_index; + // If the device object still exists, send the appropriate response either + // confirming or rejecting the pairing. + BluetoothDevice* device = adapter_->GetDevice(address_); + if (device) { + switch (button_index) { + case BUTTON_ACCEPT: + device->ConfirmPairing(); + break; + case BUTTON_REJECT: + device->RejectPairing(); + break; + } + } + + // In any case, remove this pairing notification. + message_center::MessageCenter::Get()->RemoveNotification( + kBluetoothDevicePairingNotificationId, false /* by_user */); +} + +} // namespace + +namespace ash { + +BluetoothNotificationController::BluetoothNotificationController() + : weak_ptr_factory_(this) { + BluetoothAdapterFactory::GetAdapter( + base::Bind(&BluetoothNotificationController::OnGetAdapter, + weak_ptr_factory_.GetWeakPtr())); +} + +BluetoothNotificationController::~BluetoothNotificationController() { + if (adapter_.get()) { + adapter_->RemoveObserver(this); + adapter_->RemovePairingDelegate(this); + adapter_ = NULL; + } +} + +void BluetoothNotificationController::AdapterDiscoverableChanged( + BluetoothAdapter* adapter, + bool discoverable) { + if (discoverable) { + NotifyAdapterDiscoverable(); + } else { + // Clear any previous discoverable notification. + message_center::MessageCenter::Get()->RemoveNotification( + kBluetoothDeviceDiscoverableNotificationId, false /* by_user */); + } +} + +void BluetoothNotificationController::DeviceAdded(BluetoothAdapter* adapter, + BluetoothDevice* device) { + // Add the new device to the list of currently paired devices; it doesn't + // receive a notification since it's assumed it was previously notified. + if (device->IsPaired()) + paired_devices_.insert(device->GetAddress()); +} + +void BluetoothNotificationController::DeviceChanged(BluetoothAdapter* adapter, + BluetoothDevice* device) { + // If the device is already in the list of paired devices, then don't + // notify. + if (paired_devices_.find(device->GetAddress()) != paired_devices_.end()) + return; + + // Otherwise if it's marked as paired then it must be newly paired, so + // notify the user about that. + if (device->IsPaired()) { + paired_devices_.insert(device->GetAddress()); + NotifyPairedDevice(device); + } +} + +void BluetoothNotificationController::DeviceRemoved(BluetoothAdapter* adapter, + BluetoothDevice* device) { + paired_devices_.erase(device->GetAddress()); +} + +void BluetoothNotificationController::RequestPinCode(BluetoothDevice* device) { + // Cannot provide keyboard entry in a notification; these devices (old car + // audio systems for the most part) will need pairing to be initiated from + // the Chromebook. + device->CancelPairing(); +} + +void BluetoothNotificationController::RequestPasskey(BluetoothDevice* device) { + // Cannot provide keyboard entry in a notification; fortunately the spec + // doesn't allow for this to be an option when we're receiving the pairing + // request anyway. + device->CancelPairing(); +} + +void BluetoothNotificationController::DisplayPinCode( + BluetoothDevice* device, + const std::string& pincode) { + base::string16 message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PINCODE, + device->GetNameForDisplay(), base::UTF8ToUTF16(pincode)); + + NotifyPairing(device, message, false); +} + +void BluetoothNotificationController::DisplayPasskey(BluetoothDevice* device, + uint32_t passkey) { + base::string16 message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PASSKEY, + device->GetNameForDisplay(), + base::UTF8ToUTF16(base::StringPrintf("%06i", passkey))); + + NotifyPairing(device, message, false); +} + +void BluetoothNotificationController::KeysEntered(BluetoothDevice* device, + uint32_t entered) { + // Ignored since we don't have CSS in the notification to update. +} + +void BluetoothNotificationController::ConfirmPasskey(BluetoothDevice* device, + uint32_t passkey) { + base::string16 message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BLUETOOTH_CONFIRM_PASSKEY, + device->GetNameForDisplay(), + base::UTF8ToUTF16(base::StringPrintf("%06i", passkey))); + + NotifyPairing(device, message, true); +} + +void BluetoothNotificationController::AuthorizePairing( + BluetoothDevice* device) { + base::string16 message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BLUETOOTH_AUTHORIZE_PAIRING, + device->GetNameForDisplay()); + + NotifyPairing(device, message, true); +} + +void BluetoothNotificationController::OnGetAdapter( + scoped_refptr<BluetoothAdapter> adapter) { + DCHECK(!adapter_.get()); + adapter_ = adapter; + adapter_->AddObserver(this); + adapter_->AddPairingDelegate(this, + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); + + // Notify a user if the adapter is already in the discoverable state. + if (adapter_->IsDiscoverable()) + NotifyAdapterDiscoverable(); + + // Build a list of the currently paired devices; these don't receive + // notifications since it's assumed they were previously notified. + BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); + for (BluetoothAdapter::DeviceList::const_iterator iter = devices.begin(); + iter != devices.end(); ++iter) { + const BluetoothDevice* device = *iter; + if (device->IsPaired()) + paired_devices_.insert(device->GetAddress()); + } +} + +void BluetoothNotificationController::NotifyAdapterDiscoverable() { + message_center::RichNotificationData optional; + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kBluetoothDeviceDiscoverableNotificationId, base::string16() /* title */, + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERABLE, + base::UTF8ToUTF16(adapter_->GetName()), + base::UTF8ToUTF16(adapter_->GetAddress())), + bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), + base::string16() /* display source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierBluetooth), + optional, NULL)); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +void BluetoothNotificationController::NotifyPairing( + BluetoothDevice* device, + const base::string16& message, + bool with_buttons) { + message_center::RichNotificationData optional; + if (with_buttons) { + optional.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_ACCEPT))); + optional.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_REJECT))); + } + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kBluetoothDevicePairingNotificationId, base::string16() /* title */, + message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), + base::string16() /* display source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierBluetooth), + optional, new BluetoothPairingNotificationDelegate( + adapter_, device->GetAddress()))); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +void BluetoothNotificationController::NotifyPairedDevice( + BluetoothDevice* device) { + // Remove the currently presented pairing notification; since only one + // pairing request is queued at a time, this is guaranteed to be the device + // that just became paired. + message_center::MessageCenter::Get()->RemoveNotification( + kBluetoothDevicePairingNotificationId, false /* by_user */); + + message_center::RichNotificationData optional; + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kBluetoothDevicePairedNotificationId, base::string16() /* title */, + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED, + device->GetNameForDisplay()), + bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), + base::string16() /* display source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierBluetooth), + optional, NULL)); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.h b/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.h new file mode 100644 index 0000000..5155c392 --- /dev/null +++ b/ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.h
@@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_ + +#include <stdint.h> + +#include <set> +#include <string> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" +#include "device/bluetooth/bluetooth_adapter.h" +#include "device/bluetooth/bluetooth_device.h" + +namespace ash { + +// The BluetoothNotificationController receives incoming pairing requests from +// the BluetoothAdapter, and notifications of changes to the adapter state and +// set of paired devices. It presents incoming pairing requests in the form of +// rich notifications that the user can interact with to approve the request. +class ASH_EXPORT BluetoothNotificationController + : public device::BluetoothAdapter::Observer, + public device::BluetoothDevice::PairingDelegate { + public: + BluetoothNotificationController(); + ~BluetoothNotificationController() override; + + // device::BluetoothAdapter::Observer override. + void AdapterDiscoverableChanged(device::BluetoothAdapter* adapter, + bool discoverable) override; + void DeviceAdded(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) override; + void DeviceChanged(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) override; + void DeviceRemoved(device::BluetoothAdapter* adapter, + device::BluetoothDevice* device) override; + + // device::BluetoothDevice::PairingDelegate override. + void RequestPinCode(device::BluetoothDevice* device) override; + void RequestPasskey(device::BluetoothDevice* device) override; + void DisplayPinCode(device::BluetoothDevice* device, + const std::string& pincode) override; + void DisplayPasskey(device::BluetoothDevice* device, + uint32_t passkey) override; + void KeysEntered(device::BluetoothDevice* device, uint32_t entered) override; + void ConfirmPasskey(device::BluetoothDevice* device, + uint32_t passkey) override; + void AuthorizePairing(device::BluetoothDevice* device) override; + + private: + // Internal method called by BluetoothAdapterFactory to provide the adapter + // object. + void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter); + + // Presents a notification to the user when the adapter becomes discoverable + // to other nearby devices. + void NotifyAdapterDiscoverable(); + + // Presents a notification to the user that a device |device| is making a + // pairing request. The exact message to display is given in |message| and + // should include all relevant instructions, if |with_buttons| is true then + // the notification will have Accept and Reject buttons, if false only the + // usual cancel/dismiss button will be present on the notification. + void NotifyPairing(device::BluetoothDevice* device, + const base::string16& message, + bool with_buttons); + + // Clears any shown pairing notification now that the device has been paired. + void NotifyPairedDevice(device::BluetoothDevice* device); + + // Reference to the underlying BluetoothAdapter object, holding this reference + // ensures we stay around as the pairing delegate for that adapter. + scoped_refptr<device::BluetoothAdapter> adapter_; + + // Set of currently paired devices, stored by Bluetooth address, used to + // filter out property changes for devices that were previously paired. + std::set<std::string> paired_devices_; + + // Note: This should remain the last member so it'll be destroyed and + // invalidate its weak pointers before any other members are destroyed. + base::WeakPtrFactory<BluetoothNotificationController> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothNotificationController); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_
diff --git a/ash/common/system/chromeos/bluetooth/bluetooth_observer.h b/ash/common/system/chromeos/bluetooth/bluetooth_observer.h new file mode 100644 index 0000000..f5cd484 --- /dev/null +++ b/ash/common/system/chromeos/bluetooth/bluetooth_observer.h
@@ -0,0 +1,20 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_OBSERVER_H_ + +namespace ash { + +class BluetoothObserver { + public: + virtual ~BluetoothObserver() {} + + virtual void OnBluetoothRefresh() = 0; + virtual void OnBluetoothDiscoveringChanged() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_BLUETOOTH_OBSERVER_H_
diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc new file mode 100644 index 0000000..bdd8119 --- /dev/null +++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
@@ -0,0 +1,632 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/bluetooth/tray_bluetooth.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/throbber_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "device/bluetooth/bluetooth_common.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/views/controls/button/toggle_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/progress_bar.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" + +namespace ash { +namespace tray { +namespace { + +// Updates bluetooth device |device| in the |list|. If it is new, append to the +// end of the |list|; otherwise, keep it at the same place, but update the data +// with new device info provided by |device|. +void UpdateBluetoothDeviceListHelper(BluetoothDeviceList* list, + const BluetoothDeviceInfo& device) { + for (BluetoothDeviceList::iterator it = list->begin(); it != list->end(); + ++it) { + if ((*it).address == device.address) { + *it = device; + return; + } + } + + list->push_back(device); +} + +// Removes the obsolete BluetoothDevices from |list|, if they are not in the +// |new_list|. +void RemoveObsoleteBluetoothDevicesFromList( + BluetoothDeviceList* list, + const std::set<std::string>& new_list) { + for (BluetoothDeviceList::iterator it = list->begin(); it != list->end(); + ++it) { + if (new_list.find((*it).address) == new_list.end()) { + it = list->erase(it); + if (it == list->end()) + return; + } + } +} + +// Returns corresponding device type icons for given Bluetooth device types and +// connection states. +const gfx::VectorIcon& GetBluetoothDeviceIcon( + device::BluetoothDeviceType device_type, + bool connected) { + switch (device_type) { + case device::BluetoothDeviceType::COMPUTER: + return ash::kSystemMenuComputerIcon; + case device::BluetoothDeviceType::PHONE: + return ash::kSystemMenuPhoneIcon; + case device::BluetoothDeviceType::AUDIO: + case device::BluetoothDeviceType::CAR_AUDIO: + return ash::kSystemMenuHeadsetIcon; + case device::BluetoothDeviceType::VIDEO: + return ash::kSystemMenuVideocamIcon; + case device::BluetoothDeviceType::JOYSTICK: + case device::BluetoothDeviceType::GAMEPAD: + return ash::kSystemMenuGamepadIcon; + case device::BluetoothDeviceType::KEYBOARD: + case device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO: + return ash::kSystemMenuKeyboardIcon; + case device::BluetoothDeviceType::TABLET: + return ash::kSystemMenuTabletIcon; + case device::BluetoothDeviceType::MOUSE: + return ash::kSystemMenuMouseIcon; + case device::BluetoothDeviceType::MODEM: + case device::BluetoothDeviceType::PERIPHERAL: + return ash::kSystemMenuBluetoothIcon; + case device::BluetoothDeviceType::UNKNOWN: + LOG(WARNING) << "Unknown device type icon for Bluetooth was requested."; + break; + } + return connected ? ash::kSystemMenuBluetoothConnectedIcon + : ash::kSystemMenuBluetoothIcon; +} + +const int kDisabledPanelLabelBaselineY = 20; + +} // namespace + +class BluetoothDefaultView : public TrayItemMore { + public: + explicit BluetoothDefaultView(SystemTrayItem* owner) : TrayItemMore(owner) {} + ~BluetoothDefaultView() override {} + + void Update() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + const bool enabled = delegate->GetBluetoothEnabled(); + if (delegate->GetBluetoothAvailable()) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + const base::string16 label = rb.GetLocalizedString( + enabled ? IDS_ASH_STATUS_TRAY_BLUETOOTH_ENABLED + : IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED); + SetLabel(label); + SetAccessibleName(label); + SetVisible(true); + } else { + SetVisible(false); + } + UpdateStyle(); + } + + protected: + // TrayItemMore: + std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const override { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + std::unique_ptr<TrayPopupItemStyle> style = + TrayItemMore::HandleCreateStyle(); + style->set_color_style( + delegate->GetBluetoothEnabled() + ? TrayPopupItemStyle::ColorStyle::ACTIVE + : delegate->GetBluetoothAvailable() + ? TrayPopupItemStyle::ColorStyle::INACTIVE + : TrayPopupItemStyle::ColorStyle::DISABLED); + + return style; + } + + void UpdateStyle() override { + TrayItemMore::UpdateStyle(); + std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); + SetImage(gfx::CreateVectorIcon(GetCurrentIcon(), style->GetIconColor())); + } + + private: + const gfx::VectorIcon& GetCurrentIcon() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (!delegate->GetBluetoothEnabled()) + return kSystemMenuBluetoothDisabledIcon; + + bool has_connected_device = false; + BluetoothDeviceList list; + delegate->GetAvailableBluetoothDevices(&list); + for (size_t i = 0; i < list.size(); ++i) { + if (list[i].connected) { + has_connected_device = true; + break; + } + } + return has_connected_device ? kSystemMenuBluetoothConnectedIcon + : kSystemMenuBluetoothIcon; + } + + DISALLOW_COPY_AND_ASSIGN(BluetoothDefaultView); +}; + +class BluetoothDetailedView : public TrayDetailsView { + public: + BluetoothDetailedView(SystemTrayItem* owner, LoginStatus login) + : TrayDetailsView(owner), + login_(login), + toggle_(nullptr), + settings_(nullptr), + disabled_panel_(nullptr) { + CreateItems(); + } + + ~BluetoothDetailedView() override { + // Stop discovering bluetooth devices when exiting BT detailed view. + BluetoothStopDiscovering(); + } + + void Update() { + BluetoothStartDiscovering(); + UpdateBluetoothDeviceList(); + + // Update UI. + UpdateDeviceScrollList(); + UpdateHeaderEntry(); + Layout(); + } + + private: + void CreateItems() { + CreateScrollableList(); + CreateTitleRow(IDS_ASH_STATUS_TRAY_BLUETOOTH); + } + + void BluetoothStartDiscovering() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (delegate->GetBluetoothDiscovering()) { + ShowLoadingIndicator(); + return; + } + HideLoadingIndicator(); + if (delegate->GetBluetoothEnabled()) + delegate->BluetoothStartDiscovering(); + } + + void BluetoothStopDiscovering() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (delegate && delegate->GetBluetoothDiscovering()) { + delegate->BluetoothStopDiscovering(); + HideLoadingIndicator(); + } + } + + void UpdateBluetoothDeviceList() { + std::set<std::string> new_connecting_devices; + std::set<std::string> new_connected_devices; + std::set<std::string> new_paired_not_connected_devices; + std::set<std::string> new_discovered_not_paired_devices; + + BluetoothDeviceList list; + WmShell::Get()->system_tray_delegate()->GetAvailableBluetoothDevices(&list); + for (size_t i = 0; i < list.size(); ++i) { + if (list[i].connecting) { + new_connecting_devices.insert(list[i].address); + UpdateBluetoothDeviceListHelper(&connecting_devices_, list[i]); + } else if (list[i].connected && list[i].paired) { + new_connected_devices.insert(list[i].address); + UpdateBluetoothDeviceListHelper(&connected_devices_, list[i]); + } else if (list[i].paired) { + new_paired_not_connected_devices.insert(list[i].address); + UpdateBluetoothDeviceListHelper(&paired_not_connected_devices_, + list[i]); + } else { + new_discovered_not_paired_devices.insert(list[i].address); + UpdateBluetoothDeviceListHelper(&discovered_not_paired_devices_, + list[i]); + } + } + RemoveObsoleteBluetoothDevicesFromList(&connecting_devices_, + new_connecting_devices); + RemoveObsoleteBluetoothDevicesFromList(&connected_devices_, + new_connected_devices); + RemoveObsoleteBluetoothDevicesFromList(&paired_not_connected_devices_, + new_paired_not_connected_devices); + RemoveObsoleteBluetoothDevicesFromList(&discovered_not_paired_devices_, + new_discovered_not_paired_devices); + } + + void UpdateHeaderEntry() { + bool is_bluetooth_enabled = + WmShell::Get()->system_tray_delegate()->GetBluetoothEnabled(); + if (toggle_) + toggle_->SetIsOn(is_bluetooth_enabled, false); + } + + void UpdateDeviceScrollList() { + device_map_.clear(); + scroll_content()->RemoveAllChildViews(true); + + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + bool bluetooth_enabled = delegate->GetBluetoothEnabled(); + bool bluetooth_available = delegate->GetBluetoothAvailable(); + + // If Bluetooth is disabled, show a panel which only indicates that it is + // disabled, instead of the scroller with Bluetooth devices. + if (bluetooth_enabled) { + HideDisabledPanel(); + } else { + ShowDisabledPanel(); + return; + } + + // Add paired devices (and their section header in MD) in the list. + size_t num_paired_devices = connected_devices_.size() + + connecting_devices_.size() + + paired_not_connected_devices_.size(); + if (num_paired_devices > 0) { + AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES); + AppendSameTypeDevicesToScrollList(connected_devices_, true, true, + bluetooth_enabled); + AppendSameTypeDevicesToScrollList(connecting_devices_, true, false, + bluetooth_enabled); + AppendSameTypeDevicesToScrollList(paired_not_connected_devices_, false, + false, bluetooth_enabled); + } + + // Add paired devices (and their section header in MD) in the list. + if (discovered_not_paired_devices_.size() > 0) { + if (num_paired_devices > 0) + AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES); + AppendSameTypeDevicesToScrollList(discovered_not_paired_devices_, false, + false, bluetooth_enabled); + } + + // Show user Bluetooth state if there is no bluetooth devices in list. + if (device_map_.size() == 0) { + if (bluetooth_available && bluetooth_enabled) { + HoverHighlightView* container = new HoverHighlightView(this); + container->AddLabel(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING), + gfx::ALIGN_LEFT, false); + scroll_content()->AddChildView(container); + } + } + + scroll_content()->InvalidateLayout(); + } + + void AppendSameTypeDevicesToScrollList(const BluetoothDeviceList& list, + bool highlight, + bool checked, + bool enabled) { + for (size_t i = 0; i < list.size(); ++i) { + HoverHighlightView* container = nullptr; + gfx::ImageSkia icon_image = CreateVectorIcon( + GetBluetoothDeviceIcon(list[i].device_type, list[i].connected), + kMenuIconColor); + container = AddScrollListItem(list[i].display_name, icon_image, + list[i].connected, list[i].connecting); + device_map_[container] = list[i].address; + } + } + + HoverHighlightView* AddScrollListItem(const base::string16& text, + const gfx::ImageSkia& image, + bool connected, + bool connecting) { + HoverHighlightView* container = new HoverHighlightView(this); + if (connected) { + SetupConnectedItem(container, text, image); + } else if (connecting) { + SetupConnectingItem(container, text, image); + } else { + container->AddIconAndLabel(image, text, false); + } + scroll_content()->AddChildView(container); + return container; + } + + void AddSubHeader(int message_id) { + TriView* header = TrayPopupUtils::CreateSubHeaderRowView(); + TrayPopupUtils::ConfigureAsStickyHeader(header); + + views::Label* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(l10n_util::GetStringUTF16(message_id)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); + style.SetupLabel(label); + header->AddView(TriView::Container::CENTER, label); + + scroll_content()->AddChildView(header); + } + + void SetupConnectedItem(HoverHighlightView* container, + const base::string16& text, + const gfx::ImageSkia& image) { + container->AddIconAndLabels( + image, text, l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); + style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); + style.SetupLabel(container->sub_text_label()); + } + + void SetupConnectingItem(HoverHighlightView* container, + const base::string16& text, + const gfx::ImageSkia& image) { + container->AddIconAndLabels( + image, text, l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); + ThrobberView* throbber = new ThrobberView; + throbber->Start(); + container->AddRightView(throbber); + } + + // Returns true if the device with |device_id| is found in |device_list|, + // and the display_name of the device will be returned in |display_name| if + // it's not NULL. + bool FoundDevice(const std::string& device_id, + const BluetoothDeviceList& device_list, + base::string16* display_name, + device::BluetoothDeviceType* device_type) { + for (size_t i = 0; i < device_list.size(); ++i) { + if (device_list[i].address == device_id) { + if (display_name) + *display_name = device_list[i].display_name; + if (device_type) + *device_type = device_list[i].device_type; + return true; + } + } + return false; + } + + // Updates UI of the clicked bluetooth device to show it is being connected + // or disconnected if such an operation is going to be performed underway. + void UpdateClickedDevice(const std::string& device_id, + views::View* item_container) { + base::string16 display_name; + device::BluetoothDeviceType device_type; + if (FoundDevice(device_id, paired_not_connected_devices_, &display_name, + &device_type)) { + item_container->RemoveAllChildViews(true); + HoverHighlightView* container = + static_cast<HoverHighlightView*>(item_container); + TrayPopupItemStyle style( + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + gfx::ImageSkia icon_image = CreateVectorIcon( + GetBluetoothDeviceIcon(device_type, false), style.GetIconColor()); + SetupConnectingItem(container, display_name, icon_image); + scroll_content()->SizeToPreferredSize(); + scroller()->Layout(); + } + } + + // TrayDetailsView: + void HandleViewClicked(views::View* view) override { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (!delegate->GetBluetoothEnabled()) + return; + + std::map<views::View*, std::string>::iterator find; + find = device_map_.find(view); + if (find == device_map_.end()) + return; + + const std::string device_id = find->second; + if (FoundDevice(device_id, connecting_devices_, nullptr, nullptr)) + return; + + UpdateClickedDevice(device_id, view); + delegate->ConnectToBluetoothDevice(device_id); + } + + void HandleButtonPressed(views::Button* sender, + const ui::Event& event) override { + if (sender == toggle_) { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + WmShell::Get()->RecordUserMetricsAction( + delegate->GetBluetoothEnabled() ? UMA_STATUS_AREA_BLUETOOTH_DISABLED + : UMA_STATUS_AREA_BLUETOOTH_ENABLED); + delegate->ToggleBluetooth(); + } else if (sender == settings_) { + ShowSettings(); + } else { + NOTREACHED(); + } + } + + void CreateExtraTitleRowButtons() override { + if (login_ == LoginStatus::LOCKED) + return; + + DCHECK(!toggle_); + DCHECK(!settings_); + + tri_view()->SetContainerVisible(TriView::Container::END, true); + + toggle_ = + TrayPopupUtils::CreateToggleButton(this, IDS_ASH_STATUS_TRAY_BLUETOOTH); + tri_view()->AddView(TriView::Container::END, toggle_); + + settings_ = + CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS); + tri_view()->AddView(TriView::Container::END, settings_); + } + + void ShowSettings() { + if (TrayPopupUtils::CanOpenWebUISettings(login_)) { + WmShell::Get()->system_tray_delegate()->ManageBluetoothDevices(); + owner()->system_tray()->CloseSystemBubble(); + } + } + + void ShowLoadingIndicator() { + // Setting a value of -1 gives progress_bar an infinite-loading behavior. + ShowProgress(-1, true); + } + + void HideLoadingIndicator() { ShowProgress(0, false); } + + void ShowDisabledPanel() { + DCHECK(scroller()); + if (!disabled_panel_) { + disabled_panel_ = CreateDisabledPanel(); + // Insert |disabled_panel_| before the scroller, since the scroller will + // have unnecessary bottom border when it is not the last child. + AddChildViewAt(disabled_panel_, GetIndexOf(scroller())); + // |disabled_panel_| need to fill the remaining space below the title row + // so that the inner contents of |disabled_panel_| are placed properly. + box_layout()->SetFlexForView(disabled_panel_, 1); + } + disabled_panel_->SetVisible(true); + scroller()->SetVisible(false); + } + + void HideDisabledPanel() { + DCHECK(scroller()); + if (disabled_panel_) + disabled_panel_->SetVisible(false); + scroller()->SetVisible(true); + } + + views::View* CreateDisabledPanel() { + views::View* container = new views::View; + views::BoxLayout* box_layout = + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); + box_layout->set_main_axis_alignment( + views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); + container->SetLayoutManager(box_layout); + + TrayPopupItemStyle style( + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + style.set_color_style(TrayPopupItemStyle::ColorStyle::DISABLED); + + views::ImageView* image_view = new views::ImageView; + image_view->SetImage(gfx::CreateVectorIcon(kSystemMenuBluetoothDisabledIcon, + style.GetIconColor())); + image_view->SetVerticalAlignment(views::ImageView::TRAILING); + container->AddChildView(image_view); + + views::Label* label = new views::Label( + ui::ResourceBundle::GetSharedInstance().GetLocalizedString( + IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED)); + style.SetupLabel(label); + label->SetBorder(views::CreateEmptyBorder( + kDisabledPanelLabelBaselineY - label->GetBaseline(), 0, 0, 0)); + container->AddChildView(label); + + // Make top padding of the icon equal to the height of the label so that the + // icon is vertically aligned to center of the container. + image_view->SetBorder( + views::CreateEmptyBorder(label->GetPreferredSize().height(), 0, 0, 0)); + return container; + } + + LoginStatus login_; + + std::map<views::View*, std::string> device_map_; + + BluetoothDeviceList connected_devices_; + BluetoothDeviceList connecting_devices_; + BluetoothDeviceList paired_not_connected_devices_; + BluetoothDeviceList discovered_not_paired_devices_; + + views::ToggleButton* toggle_; + views::Button* settings_; + + // The container of the message "Bluetooth is disabled" and an icon. It should + // be shown instead of Bluetooth device list when Bluetooth is disabled. + views::View* disabled_panel_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothDetailedView); +}; + +} // namespace tray + +TrayBluetooth::TrayBluetooth(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_BLUETOOTH), + default_(nullptr), + detailed_(nullptr) { + WmShell::Get()->system_tray_notifier()->AddBluetoothObserver(this); +} + +TrayBluetooth::~TrayBluetooth() { + WmShell::Get()->system_tray_notifier()->RemoveBluetoothObserver(this); +} + +views::View* TrayBluetooth::CreateTrayView(LoginStatus status) { + return NULL; +} + +views::View* TrayBluetooth::CreateDefaultView(LoginStatus status) { + CHECK(default_ == NULL); + default_ = new tray::BluetoothDefaultView(this); + default_->SetEnabled(status != LoginStatus::LOCKED); + default_->Update(); + return default_; +} + +views::View* TrayBluetooth::CreateDetailedView(LoginStatus status) { + if (!WmShell::Get()->system_tray_delegate()->GetBluetoothAvailable()) + return NULL; + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DETAILED_BLUETOOTH_VIEW); + CHECK(detailed_ == NULL); + detailed_ = new tray::BluetoothDetailedView(this, status); + detailed_->Update(); + return detailed_; +} + +void TrayBluetooth::DestroyTrayView() {} + +void TrayBluetooth::DestroyDefaultView() { + default_ = NULL; +} + +void TrayBluetooth::DestroyDetailedView() { + detailed_ = NULL; +} + +void TrayBluetooth::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayBluetooth::OnBluetoothRefresh() { + if (default_) + default_->Update(); + else if (detailed_) + detailed_->Update(); +} + +void TrayBluetooth::OnBluetoothDiscoveringChanged() { + if (!detailed_) + return; + detailed_->Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.h b/ash/common/system/chromeos/bluetooth/tray_bluetooth.h new file mode 100644 index 0000000..379671c --- /dev/null +++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.h
@@ -0,0 +1,45 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_TRAY_BLUETOOTH_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_TRAY_BLUETOOTH_H_ + +#include "ash/common/system/chromeos/bluetooth/bluetooth_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { +namespace tray { +class BluetoothDefaultView; +class BluetoothDetailedView; +} + +class TrayBluetooth : public SystemTrayItem, public BluetoothObserver { + public: + explicit TrayBluetooth(SystemTray* system_tray); + ~TrayBluetooth() override; + + private: + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + + // Overridden from BluetoothObserver. + void OnBluetoothRefresh() override; + void OnBluetoothDiscoveringChanged() override; + + tray::BluetoothDefaultView* default_; + tray::BluetoothDetailedView* detailed_; + + DISALLOW_COPY_AND_ASSIGN(TrayBluetooth); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_BLUETOOTH_TRAY_BLUETOOTH_H_
diff --git a/ash/common/system/chromeos/brightness/brightness_controller_chromeos.cc b/ash/common/system/chromeos/brightness/brightness_controller_chromeos.cc new file mode 100644 index 0000000..9ee4f779 --- /dev/null +++ b/ash/common/system/chromeos/brightness/brightness_controller_chromeos.cc
@@ -0,0 +1,50 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/brightness/brightness_controller_chromeos.h" + +#include "base/metrics/user_metrics.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/base/accelerators/accelerator.h" + +namespace ash { +namespace system { + +void BrightnessControllerChromeos::HandleBrightnessDown( + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_DOWN) + base::RecordAction(base::UserMetricsAction("Accel_BrightnessDown_F6")); + + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->DecreaseScreenBrightness(true); +} + +void BrightnessControllerChromeos::HandleBrightnessUp( + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_UP) + base::RecordAction(base::UserMetricsAction("Accel_BrightnessUp_F7")); + + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->IncreaseScreenBrightness(); +} + +void BrightnessControllerChromeos::SetBrightnessPercent(double percent, + bool gradual) { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->SetScreenBrightnessPercent(percent, gradual); +} + +void BrightnessControllerChromeos::GetBrightnessPercent( + const base::Callback<void(double)>& callback) { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->GetScreenBrightnessPercent(callback); +} + +} // namespace system +} // namespace ash
diff --git a/ash/common/system/chromeos/brightness/brightness_controller_chromeos.h b/ash/common/system/chromeos/brightness/brightness_controller_chromeos.h new file mode 100644 index 0000000..b9338320 --- /dev/null +++ b/ash/common/system/chromeos/brightness/brightness_controller_chromeos.h
@@ -0,0 +1,38 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_BRIGHTNESS_BRIGHTNESS_CONTROLLER_CHROMEOS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_BRIGHTNESS_BRIGHTNESS_CONTROLLER_CHROMEOS_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/brightness_control_delegate.h" +#include "base/compiler_specific.h" +#include "base/macros.h" + +namespace ash { +namespace system { + +// A class which controls brightness when F6, F7 or a multimedia key for +// brightness is pressed. +class ASH_EXPORT BrightnessControllerChromeos + : public ash::BrightnessControlDelegate { + public: + BrightnessControllerChromeos() {} + ~BrightnessControllerChromeos() override {} + + // Overridden from ash::BrightnessControlDelegate: + void HandleBrightnessDown(const ui::Accelerator& accelerator) override; + void HandleBrightnessUp(const ui::Accelerator& accelerator) override; + void SetBrightnessPercent(double percent, bool gradual) override; + void GetBrightnessPercent( + const base::Callback<void(double)>& callback) override; + + private: + DISALLOW_COPY_AND_ASSIGN(BrightnessControllerChromeos); +}; + +} // namespace system +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_BRIGHTNESS_BRIGHTNESS_CONTROLLER_CHROMEOS_H_
diff --git a/ash/common/system/chromeos/brightness/tray_brightness.cc b/ash/common/system/chromeos/brightness/tray_brightness.cc new file mode 100644 index 0000000..dc09756 --- /dev/null +++ b/ash/common/system/chromeos/brightness/tray_brightness.cc
@@ -0,0 +1,283 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/brightness/tray_brightness.h" + +#include <algorithm> + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/shell_observer.h" +#include "ash/common/system/brightness_control_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/display/display.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/slider.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" + +namespace ash { +namespace tray { +namespace { + +// We don't let the screen brightness go lower than this when it's being +// adjusted via the slider. Otherwise, if the user doesn't know about the +// brightness keys, they may turn the backlight off and not know how to turn it +// back on. +const double kMinBrightnessPercent = 5.0; + +} // namespace + +class BrightnessView : public ShellObserver, + public views::View, + public views::SliderListener { + public: + BrightnessView(bool default_view, double initial_percent); + ~BrightnessView() override; + + bool is_default_view() const { return is_default_view_; } + + // |percent| is in the range [0.0, 100.0]. + void SetBrightnessPercent(double percent); + + // ShellObserver: + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + + private: + // views::View: + void OnBoundsChanged(const gfx::Rect& old_bounds) override; + + // views:SliderListener: + void SliderValueChanged(views::Slider* sender, + float value, + float old_value, + views::SliderChangeReason reason) override; + + // views:SliderListener: + void SliderDragStarted(views::Slider* slider) override; + void SliderDragEnded(views::Slider* slider) override; + + views::Slider* slider_; + + // Is |slider_| currently being dragged? + bool dragging_; + + // True if this view is for the default tray view. Used to control hide/show + // behaviour of the default view when entering or leaving Maximize Mode. + bool is_default_view_; + + // Last brightness level that we observed, in the range [0.0, 100.0]. + double last_percent_; + + DISALLOW_COPY_AND_ASSIGN(BrightnessView); +}; + +BrightnessView::BrightnessView(bool default_view, double initial_percent) + : dragging_(false), + is_default_view_(default_view), + last_percent_(initial_percent) { + SetLayoutManager(new views::FillLayout); + // Use CreateMultiTargetRowView() instead of CreateDefaultRowView() because + // that's what the audio row uses and we want the two rows to layout with the + // same insets. + TriView* tri_view = TrayPopupUtils::CreateMultiTargetRowView(); + AddChildView(tri_view); + + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + views::ImageView* icon = TrayPopupUtils::CreateMainImageView(); + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + icon->SetImage( + gfx::CreateVectorIcon(kSystemMenuBrightnessIcon, kMenuIconColor)); + } else { + icon->SetImage( + rb.GetImageNamed(IDR_AURA_UBER_TRAY_BRIGHTNESS).ToImageSkia()); + } + tri_view->AddView(TriView::Container::START, icon); + + slider_ = TrayPopupUtils::CreateSlider(this); + slider_->SetValue(static_cast<float>(initial_percent / 100.0)); + slider_->SetAccessibleName( + rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_BRIGHTNESS)); + tri_view->AddView(TriView::Container::CENTER, slider_); + + if (is_default_view_) { + WmShell::Get()->AddShellObserver(this); + SetVisible(WmShell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled()); + } else { + tri_view->SetContainerVisible(TriView::Container::END, false); + } +} + +BrightnessView::~BrightnessView() { + if (is_default_view_) + WmShell::Get()->RemoveShellObserver(this); +} + +void BrightnessView::SetBrightnessPercent(double percent) { + last_percent_ = percent; + if (!dragging_) + slider_->SetValue(static_cast<float>(percent / 100.0)); +} + +void BrightnessView::OnMaximizeModeStarted() { + SetVisible(true); +} + +void BrightnessView::OnMaximizeModeEnded() { + SetVisible(false); +} + +void BrightnessView::OnBoundsChanged(const gfx::Rect& old_bounds) { + int w = width() - slider_->x(); + slider_->SetSize(gfx::Size(w, slider_->height())); +} + +void BrightnessView::SliderValueChanged(views::Slider* sender, + float value, + float old_value, + views::SliderChangeReason reason) { + DCHECK_EQ(sender, slider_); + if (reason != views::VALUE_CHANGED_BY_USER) + return; + BrightnessControlDelegate* brightness_control_delegate = + WmShell::Get()->brightness_control_delegate(); + if (brightness_control_delegate) { + double percent = std::max(value * 100.0, kMinBrightnessPercent); + brightness_control_delegate->SetBrightnessPercent(percent, true); + } +} + +void BrightnessView::SliderDragStarted(views::Slider* slider) { + DCHECK_EQ(slider, slider_); + dragging_ = true; +} + +void BrightnessView::SliderDragEnded(views::Slider* slider) { + DCHECK_EQ(slider, slider_); + dragging_ = false; + slider_->SetValue(static_cast<float>(last_percent_ / 100.0)); +} + +} // namespace tray + +TrayBrightness::TrayBrightness(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_DISPLAY_BRIGHTNESS), + brightness_view_(NULL), + current_percent_(100.0), + got_current_percent_(false), + weak_ptr_factory_(this) { + // Post a task to get the initial brightness; the BrightnessControlDelegate + // isn't created yet. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&TrayBrightness::GetInitialBrightness, + weak_ptr_factory_.GetWeakPtr())); + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( + this); +} + +TrayBrightness::~TrayBrightness() { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( + this); +} + +void TrayBrightness::GetInitialBrightness() { + BrightnessControlDelegate* brightness_control_delegate = + WmShell::Get()->brightness_control_delegate(); + // Worrisome, but happens in unit tests, so don't log anything. + if (!brightness_control_delegate) + return; + brightness_control_delegate->GetBrightnessPercent( + base::Bind(&TrayBrightness::HandleInitialBrightness, + weak_ptr_factory_.GetWeakPtr())); +} + +void TrayBrightness::HandleInitialBrightness(double percent) { + if (!got_current_percent_) + HandleBrightnessChanged(percent, false); +} + +views::View* TrayBrightness::CreateTrayView(LoginStatus status) { + return NULL; +} + +views::View* TrayBrightness::CreateDefaultView(LoginStatus status) { + CHECK(brightness_view_ == NULL); + brightness_view_ = new tray::BrightnessView(true, current_percent_); + return brightness_view_; +} + +views::View* TrayBrightness::CreateDetailedView(LoginStatus status) { + CHECK(brightness_view_ == NULL); + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW); + brightness_view_ = new tray::BrightnessView(false, current_percent_); + return brightness_view_; +} + +void TrayBrightness::DestroyTrayView() {} + +void TrayBrightness::DestroyDefaultView() { + if (brightness_view_ && brightness_view_->is_default_view()) + brightness_view_ = NULL; +} + +void TrayBrightness::DestroyDetailedView() { + if (brightness_view_ && !brightness_view_->is_default_view()) + brightness_view_ = NULL; +} + +void TrayBrightness::UpdateAfterLoginStatusChange(LoginStatus status) {} + +bool TrayBrightness::ShouldShowShelf() const { + return false; +} + +void TrayBrightness::BrightnessChanged(int level, bool user_initiated) { + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_BRIGHTNESS_CHANGED); + double percent = static_cast<double>(level); + HandleBrightnessChanged(percent, user_initiated); +} + +void TrayBrightness::HandleBrightnessChanged(double percent, + bool user_initiated) { + current_percent_ = percent; + got_current_percent_ = true; + + if (brightness_view_) + brightness_view_->SetBrightnessPercent(percent); + + if (!user_initiated) + return; + + // Never show the bubble on systems that lack internal displays: if an + // external display's brightness is changed, it may already display the new + // level via an on-screen display. + if (!display::Display::HasInternalDisplay()) + return; + + if (brightness_view_ && brightness_view_->visible()) + SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); + else + PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/brightness/tray_brightness.h b/ash/common/system/chromeos/brightness/tray_brightness.h new file mode 100644 index 0000000..01f5479 --- /dev/null +++ b/ash/common/system/chromeos/brightness/tray_brightness.h
@@ -0,0 +1,68 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_BRIGHTNESS_TRAY_BRIGHTNESS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_BRIGHTNESS_TRAY_BRIGHTNESS_H_ + +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chromeos/dbus/power_manager_client.h" + +namespace ash { +namespace tray { +class BrightnessView; +} + +class ASH_EXPORT TrayBrightness + : public SystemTrayItem, + public chromeos::PowerManagerClient::Observer { + public: + explicit TrayBrightness(SystemTray* system_tray); + ~TrayBrightness() override; + + private: + friend class TrayBrightnessTest; + + // Sends a request to get the current screen brightness so |current_percent_| + // can be initialized. + void GetInitialBrightness(); + + // Updates |current_percent_| with the initial brightness requested by + // GetInitialBrightness(), if we haven't seen the brightness already in the + // meantime. + void HandleInitialBrightness(double percent); + + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + bool ShouldShowShelf() const override; + + // Overriden from PowerManagerClient::Observer. + void BrightnessChanged(int level, bool user_initiated) override; + + void HandleBrightnessChanged(double percent, bool user_initiated); + + tray::BrightnessView* brightness_view_; + + // Brightness level in the range [0.0, 100.0] that we've heard about most + // recently. + double current_percent_; + + // Has |current_percent_| been initialized? + bool got_current_percent_; + + base::WeakPtrFactory<TrayBrightness> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(TrayBrightness); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_BRIGHTNESS_TRAY_BRIGHTNESS_H_
diff --git a/ash/common/system/chromeos/brightness/tray_brightness_unittest.cc b/ash/common/system/chromeos/brightness/tray_brightness_unittest.cc new file mode 100644 index 0000000..edc7ac09 --- /dev/null +++ b/ash/common/system/chromeos/brightness/tray_brightness_unittest.cc
@@ -0,0 +1,101 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/brightness/tray_brightness.h" + +#include <memory> + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/test/ash_test.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ui/views/view.h" + +namespace ash { + +class TrayBrightnessTest : public AshTest { + public: + TrayBrightnessTest() {} + ~TrayBrightnessTest() override {} + + protected: + views::View* CreateDefaultView() { + TrayBrightness tray(NULL); + // The login status doesn't matter here; supply any random value. + return tray.CreateDefaultView(LoginStatus::USER); + } + + views::View* CreateDetailedView() { + TrayBrightness tray(NULL); + // The login status doesn't matter here; supply any random value. + return tray.CreateDetailedView(LoginStatus::USER); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TrayBrightnessTest); +}; + +// Tests that when the default view is initially created, that its +// BrightnessView is created not visible. +TEST_F(TrayBrightnessTest, CreateDefaultView) { + std::unique_ptr<views::View> tray(CreateDefaultView()); + EXPECT_FALSE(tray->visible()); +} + +// Tests the construction of the default view while MaximizeMode is active. +// The BrightnessView should be visible. +TEST_F(TrayBrightnessTest, CreateDefaultViewDuringMaximizeMode) { + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + std::unique_ptr<views::View> tray(CreateDefaultView()); + EXPECT_TRUE(tray->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); +} + +// Tests that the enabling of MaximizeMode affects a previously created +// BrightnessView, changing the visibility. +TEST_F(TrayBrightnessTest, DefaultViewVisibilityChangesDuringMaximizeMode) { + std::unique_ptr<views::View> tray(CreateDefaultView()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + EXPECT_TRUE(tray->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_FALSE(tray->visible()); +} + +// Tests that when the detailed view is initially created that its +// BrightnessView is created as visible for both MD and non MD modes. +TEST_F(TrayBrightnessTest, CreateDetailedView) { + std::unique_ptr<views::View> tray(CreateDetailedView()); + EXPECT_TRUE(tray->visible()); +} + +// Tests that when the detailed view is created during MaximizeMode that its +// BrightnessView is visible. +TEST_F(TrayBrightnessTest, CreateDetailedViewDuringMaximizeMode) { + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + std::unique_ptr<views::View> tray(CreateDetailedView()); + EXPECT_TRUE(tray->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); +} + +// Tests that the enabling of MaximizeMode has no affect on the visibility of a +// previously created BrightnessView that belongs to a detailed view. +TEST_F(TrayBrightnessTest, DetailedViewVisibilityChangesDuringMaximizeMode) { + std::unique_ptr<views::View> tray(CreateDetailedView()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + EXPECT_TRUE(tray->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_TRUE(tray->visible()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/cast/tray_cast.cc b/ash/common/system/chromeos/cast/tray_cast.cc new file mode 100644 index 0000000..4ad2fd9 --- /dev/null +++ b/ash/common/system/chromeos/cast/tray_cast.cc
@@ -0,0 +1,572 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/cast/tray_cast.h" + +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "ash/common/cast_config_controller.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/throbber_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/public/interfaces/cast_config.mojom.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/bind.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/text_elider.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +namespace { + +const size_t kMaximumStatusStringLength = 100; + +// Helper method to elide the given string to the maximum length. If a string is +// contains user-input and is displayed, we should elide it. +// TODO(jdufault): This does not properly trim unicode characters. We should +// implement this properly by using views::Label::SetElideBehavior(...). See +// crbug.com/532496. +base::string16 ElideString(const base::string16& text) { + base::string16 elided; + gfx::ElideString(text, kMaximumStatusStringLength, &elided); + return elided; +} + +// Returns a vectorized version of the Cast icon. The icon's interior region is +// filled in if |is_casting| is true. +gfx::ImageSkia GetCastIconForSystemMenu(bool is_casting) { + return gfx::CreateVectorIcon( + kSystemMenuCastIcon, is_casting ? kMenuIconColor : SK_ColorTRANSPARENT); +} + +} // namespace + +namespace tray { + +// This view is displayed in the system tray when the cast extension is active. +// It asks the user if they want to cast the desktop. If they click on the +// chevron, then a detail view will replace this view where the user will +// actually pick the cast receiver. +class CastSelectDefaultView : public TrayItemMore { + public: + explicit CastSelectDefaultView(SystemTrayItem* owner); + ~CastSelectDefaultView() override; + + private: + DISALLOW_COPY_AND_ASSIGN(CastSelectDefaultView); +}; + +CastSelectDefaultView::CastSelectDefaultView(SystemTrayItem* owner) + : TrayItemMore(owner) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + + // Update the image and label. + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + SetImage(GetCastIconForSystemMenu(false)); + else + SetImage(*rb.GetImageNamed(IDR_AURA_UBER_TRAY_CAST).ToImageSkia()); + + base::string16 label = + rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAST_DESKTOP); + SetLabel(label); + SetAccessibleName(label); +} + +CastSelectDefaultView::~CastSelectDefaultView() {} + +// This view is displayed when the screen is actively being casted; it allows +// the user to easily stop casting. It fully replaces the +// |CastSelectDefaultView| view inside of the |CastDuplexView|. +class CastCastView : public ScreenStatusView { + public: + CastCastView(); + ~CastCastView() override; + + void StopCasting(); + + const std::string& displayed_route_id() const { return displayed_route_->id; } + + // Updates the label for the stop view to include information about the + // current device that is being casted. + void UpdateLabel(const std::vector<mojom::SinkAndRoutePtr>& sinks_routes); + + private: + // Overridden from views::ButtonListener. + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + // The cast activity id that we are displaying. If the user stops a cast, we + // send this value to the config delegate so that we stop the right cast. + mojom::CastRoutePtr displayed_route_; + + DISALLOW_COPY_AND_ASSIGN(CastCastView); +}; + +CastCastView::CastCastView() + : ScreenStatusView( + nullptr, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN), + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_STOP)) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + icon()->SetImage(GetCastIconForSystemMenu(true)); + } else { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + icon()->SetImage( + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAST_ENABLED).ToImageSkia()); + } +} + +CastCastView::~CastCastView() {} + +void CastCastView::StopCasting() { + WmShell::Get()->cast_config()->StopCasting(displayed_route_.Clone()); + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_CAST_STOP_CAST); +} + +void CastCastView::UpdateLabel( + const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) { + for (auto& i : sinks_routes) { + const mojom::CastSinkPtr& sink = i->sink; + const mojom::CastRoutePtr& route = i->route; + + // We only want to display casts that came from this machine, since on a + // busy network many other people could be casting. + if (!route->id.empty() && route->is_local_source) { + displayed_route_ = route.Clone(); + + // We want to display different labels inside of the title depending on + // what we are actually casting - either the desktop, a tab, or a fallback + // that catches everything else (ie, an extension tab). + switch (route->content_source) { + case ash::mojom::ContentSource::UNKNOWN: + label()->SetText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN)); + stop_button()->SetAccessibleName(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN_ACCESSIBILITY_STOP)); + break; + case ash::mojom::ContentSource::TAB: + label()->SetText(ElideString(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_CAST_CAST_TAB, + base::UTF8ToUTF16(route->title), base::UTF8ToUTF16(sink->name)))); + stop_button()->SetAccessibleName( + ElideString(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_CAST_CAST_TAB_ACCESSIBILITY_STOP, + base::UTF8ToUTF16(route->title), + base::UTF8ToUTF16(sink->name)))); + break; + case ash::mojom::ContentSource::DESKTOP: + label()->SetText(ElideString( + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP, + base::UTF8ToUTF16(sink->name)))); + stop_button()->SetAccessibleName( + ElideString(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP_ACCESSIBILITY_STOP, + base::UTF8ToUTF16(sink->name)))); + break; + } + + PreferredSizeChanged(); + Layout(); + // Only need to update labels once. + break; + } + } +} + +void CastCastView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + StopCasting(); +} + +// This view by itself does very little. It acts as a front-end for managing +// which of the two child views (|CastSelectDefaultView| and |CastCastView|) +// is active. +class CastDuplexView : public views::View { + public: + CastDuplexView(SystemTrayItem* owner, + bool enabled, + const std::vector<mojom::SinkAndRoutePtr>& sinks_routes); + ~CastDuplexView() override; + + // Activate either the casting or select view. + void ActivateCastView(); + void ActivateSelectView(); + + CastSelectDefaultView* select_view() { return select_view_; } + CastCastView* cast_view() { return cast_view_; } + + private: + // Overridden from views::View. + void ChildPreferredSizeChanged(views::View* child) override; + void Layout() override; + + // Only one of |select_view_| or |cast_view_| will be displayed at any given + // time. This will return the view is being displayed. + views::View* ActiveChildView(); + + CastSelectDefaultView* select_view_; + CastCastView* cast_view_; + + DISALLOW_COPY_AND_ASSIGN(CastDuplexView); +}; + +CastDuplexView::CastDuplexView( + SystemTrayItem* owner, + bool enabled, + const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) { + select_view_ = new CastSelectDefaultView(owner); + select_view_->SetEnabled(enabled); + cast_view_ = new CastCastView(); + cast_view_->UpdateLabel(sinks_routes); + SetLayoutManager(new views::FillLayout()); + + ActivateSelectView(); +} + +CastDuplexView::~CastDuplexView() { + RemoveChildView(ActiveChildView()); + delete select_view_; + delete cast_view_; +} + +void CastDuplexView::ActivateCastView() { + if (ActiveChildView() == cast_view_) + return; + + RemoveChildView(select_view_); + AddChildView(cast_view_); + InvalidateLayout(); +} + +void CastDuplexView::ActivateSelectView() { + if (ActiveChildView() == select_view_) + return; + + RemoveChildView(cast_view_); + AddChildView(select_view_); + InvalidateLayout(); +} + +void CastDuplexView::ChildPreferredSizeChanged(views::View* child) { + PreferredSizeChanged(); +} + +void CastDuplexView::Layout() { + views::View::Layout(); + + select_view_->SetBoundsRect(GetContentsBounds()); + cast_view_->SetBoundsRect(GetContentsBounds()); +} + +views::View* CastDuplexView::ActiveChildView() { + if (cast_view_->parent() == this) + return cast_view_; + if (select_view_->parent() == this) + return select_view_; + return nullptr; +} + +// Exposes an icon in the tray. |TrayCast| manages the visiblity of this. +class CastTrayView : public TrayItemView { + public: + explicit CastTrayView(SystemTrayItem* tray_item); + ~CastTrayView() override; + + private: + DISALLOW_COPY_AND_ASSIGN(CastTrayView); +}; + +CastTrayView::CastTrayView(SystemTrayItem* tray_item) + : TrayItemView(tray_item) { + CreateImageView(); + if (MaterialDesignController::UseMaterialDesignSystemIcons()) { + image_view()->SetImage( + gfx::CreateVectorIcon(kSystemTrayCastIcon, kTrayIconColor)); + } else { + image_view()->SetImage(ui::ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE) + .ToImageSkia()); + } +} + +CastTrayView::~CastTrayView() {} + +// This view displays a list of cast receivers that can be clicked on and casted +// to. It is activated by clicking on the chevron inside of +// |CastSelectDefaultView|. +class CastDetailedView : public TrayDetailsView { + public: + CastDetailedView(SystemTrayItem* owner, + const std::vector<mojom::SinkAndRoutePtr>& sinks_and_routes); + ~CastDetailedView() override; + + // Makes the detail view think the view associated with the given receiver_id + // was clicked. This will start a cast. + void SimulateViewClickedForTest(const std::string& receiver_id); + + // Updates the list of available receivers. + void UpdateReceiverList( + const std::vector<mojom::SinkAndRoutePtr>& sinks_routes); + + private: + void CreateItems(); + + void UpdateReceiverListFromCachedData(); + views::View* AddToReceiverList(const mojom::SinkAndRoutePtr& sink_route); + + // TrayDetailsView: + void HandleViewClicked(views::View* view) override; + + // A mapping from the receiver id to the receiver/activity data. + std::map<std::string, ash::mojom::SinkAndRoutePtr> sinks_and_routes_; + // A mapping from the view pointer to the associated activity id. + std::map<views::View*, ash::mojom::CastSinkPtr> view_to_sink_map_; + + DISALLOW_COPY_AND_ASSIGN(CastDetailedView); +}; + +CastDetailedView::CastDetailedView( + SystemTrayItem* owner, + const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) + : TrayDetailsView(owner) { + CreateItems(); + UpdateReceiverList(sinks_routes); +} + +CastDetailedView::~CastDetailedView() {} + +void CastDetailedView::SimulateViewClickedForTest( + const std::string& receiver_id) { + for (const auto& it : view_to_sink_map_) { + if (it.second->id == receiver_id) { + HandleViewClicked(it.first); + break; + } + } +} + +void CastDetailedView::CreateItems() { + CreateScrollableList(); + CreateTitleRow(IDS_ASH_STATUS_TRAY_CAST); +} + +void CastDetailedView::UpdateReceiverList( + const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) { + // Add/update existing. + for (const auto& it : sinks_routes) + sinks_and_routes_[it->sink->id] = it->Clone(); + + // Remove non-existent sinks. Removing an element invalidates all existing + // iterators. + auto i = sinks_and_routes_.begin(); + while (i != sinks_and_routes_.end()) { + bool has_receiver = false; + for (auto& receiver : sinks_routes) { + if (i->first == receiver->sink->id) + has_receiver = true; + } + + if (has_receiver) + ++i; + else + i = sinks_and_routes_.erase(i); + } + + // Update UI. + UpdateReceiverListFromCachedData(); + Layout(); +} + +void CastDetailedView::UpdateReceiverListFromCachedData() { + // Remove all of the existing views. + view_to_sink_map_.clear(); + scroll_content()->RemoveAllChildViews(true); + + // Add a view for each receiver. + for (auto& it : sinks_and_routes_) { + const ash::mojom::SinkAndRoutePtr& sink_route = it.second; + views::View* container = AddToReceiverList(sink_route); + view_to_sink_map_[container] = sink_route->sink.Clone(); + } + + scroll_content()->SizeToPreferredSize(); + scroller()->Layout(); +} + +views::View* CastDetailedView::AddToReceiverList( + const ash::mojom::SinkAndRoutePtr& sink_route) { + const gfx::ImageSkia image = + MaterialDesignController::IsSystemTrayMenuMaterial() + ? gfx::CreateVectorIcon(kSystemMenuCastDeviceIcon, kMenuIconColor) + : *ui::ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_AURA_UBER_TRAY_CAST_DEVICE_ICON) + .ToImageSkia(); + + HoverHighlightView* container = new HoverHighlightView(this); + container->AddIconAndLabelCustomSize( + image, base::UTF8ToUTF16(sink_route->sink->name), false, + kTrayPopupDetailsIconWidth, kTrayPopupPaddingHorizontal, + kTrayPopupPaddingBetweenItems); + + scroll_content()->AddChildView(container); + return container; +} + +void CastDetailedView::HandleViewClicked(views::View* view) { + // Find the receiver we are going to cast to. + auto it = view_to_sink_map_.find(view); + if (it != view_to_sink_map_.end()) { + WmShell::Get()->cast_config()->CastToSink(it->second.Clone()); + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST); + } +} + +} // namespace tray + +TrayCast::TrayCast(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_CAST) { + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->cast_config()->AddObserver(this); + WmShell::Get()->cast_config()->RequestDeviceRefresh(); +} + +TrayCast::~TrayCast() { + WmShell::Get()->cast_config()->RemoveObserver(this); + WmShell::Get()->RemoveShellObserver(this); +} + +void TrayCast::StartCastForTest(const std::string& receiver_id) { + if (detailed_ != nullptr) + detailed_->SimulateViewClickedForTest(receiver_id); +} + +void TrayCast::StopCastForTest() { + default_->cast_view()->StopCasting(); +} + +const std::string& TrayCast::GetDisplayedCastId() { + return default_->cast_view()->displayed_route_id(); +} + +const views::View* TrayCast::GetDefaultView() const { + return default_; +} + +views::View* TrayCast::CreateTrayView(LoginStatus status) { + CHECK(tray_ == nullptr); + tray_ = new tray::CastTrayView(this); + tray_->SetVisible(HasActiveRoute()); + return tray_; +} + +views::View* TrayCast::CreateDefaultView(LoginStatus status) { + CHECK(default_ == nullptr); + + default_ = new tray::CastDuplexView(this, status != LoginStatus::LOCKED, + sinks_and_routes_); + default_->set_id(TRAY_VIEW); + default_->select_view()->set_id(SELECT_VIEW); + default_->cast_view()->set_id(CAST_VIEW); + + UpdatePrimaryView(); + return default_; +} + +views::View* TrayCast::CreateDetailedView(LoginStatus status) { + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_DETAILED_CAST_VIEW); + CHECK(detailed_ == nullptr); + detailed_ = new tray::CastDetailedView(this, sinks_and_routes_); + return detailed_; +} + +void TrayCast::DestroyTrayView() { + tray_ = nullptr; +} + +void TrayCast::DestroyDefaultView() { + default_ = nullptr; +} + +void TrayCast::DestroyDetailedView() { + detailed_ = nullptr; +} + +void TrayCast::OnDevicesUpdated(std::vector<mojom::SinkAndRoutePtr> devices) { + sinks_and_routes_ = std::move(devices); + UpdatePrimaryView(); + + if (default_) { + bool has_receivers = !sinks_and_routes_.empty(); + default_->SetVisible(has_receivers); + default_->cast_view()->UpdateLabel(sinks_and_routes_); + } + if (detailed_) + detailed_->UpdateReceiverList(sinks_and_routes_); +} + +void TrayCast::UpdatePrimaryView() { + if (WmShell::Get()->cast_config()->Connected() && + !sinks_and_routes_.empty()) { + if (default_) { + if (HasActiveRoute()) + default_->ActivateCastView(); + else + default_->ActivateSelectView(); + } + + if (tray_) + tray_->SetVisible(is_mirror_casting_); + } else { + if (default_) + default_->SetVisible(false); + if (tray_) + tray_->SetVisible(false); + } +} + +bool TrayCast::HasActiveRoute() { + for (const auto& sr : sinks_and_routes_) { + if (!sr->route->title.empty() && sr->route->is_local_source) + return true; + } + + return false; +} + +void TrayCast::OnCastingSessionStartedOrStopped(bool started) { + is_mirror_casting_ = started; + UpdatePrimaryView(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/cast/tray_cast.h b/ash/common/system/chromeos/cast/tray_cast.h new file mode 100644 index 0000000..ae7fda7 --- /dev/null +++ b/ash/common/system/chromeos/cast/tray_cast.h
@@ -0,0 +1,84 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_CAST_TRAY_CAST_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_CAST_TRAY_CAST_H_ + +#include <string> +#include <vector> + +#include "ash/common/cast_config_controller.h" +#include "ash/common/shell_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { +namespace tray { +class CastTrayView; +class CastDetailedView; +class CastDuplexView; +} // namespace tray + +class ASH_EXPORT TrayCast : public SystemTrayItem, + public ShellObserver, + public CastConfigControllerObserver { + public: + explicit TrayCast(SystemTray* system_tray); + ~TrayCast() override; + + private: + // Helper/utility methods for testing. + friend class TrayCastTestAPI; + void StartCastForTest(const std::string& sink_id); + void StopCastForTest(); + // Returns the id of the item we are currently displaying in the cast view. + // This assumes that the cast view is active. + const std::string& GetDisplayedCastId(); + const views::View* GetDefaultView() const; + enum ChildViewId { TRAY_VIEW = 1, SELECT_VIEW, CAST_VIEW }; + + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + + // Overridden from ShellObserver. + void OnCastingSessionStartedOrStopped(bool started) override; + + // Overridden from CastConfigObserver. + void OnDevicesUpdated(std::vector<mojom::SinkAndRoutePtr> devices) override; + + // This makes sure that the current view displayed in the tray is the correct + // one, depending on if we are currently casting. If we're casting, then a + // view with a stop button is displayed; otherwise, a view that links to a + // detail view is displayed instead that allows the user to easily begin a + // casting session. + void UpdatePrimaryView(); + + // Returns true if there is an active cast route. The route may be DIAL based, + // such as casting YouTube where the cast sink directly streams content from + // another server. In that case, is_mirror_casting_ will be false since this + // device is not actively transmitting information to the cast sink. + bool HasActiveRoute(); + + std::vector<mojom::SinkAndRoutePtr> sinks_and_routes_; + + // True if there is a mirror-based cast session and the active-cast tray icon + // should be shown. + bool is_mirror_casting_ = false; + + // Not owned. + tray::CastTrayView* tray_ = nullptr; + tray::CastDuplexView* default_ = nullptr; + tray::CastDetailedView* detailed_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(TrayCast); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_CAST_TRAY_CAST_H_
diff --git a/ash/common/system/chromeos/devicetype_utils.cc b/ash/common/system/chromeos/devicetype_utils.cc new file mode 100644 index 0000000..6feac8d --- /dev/null +++ b/ash/common/system/chromeos/devicetype_utils.cc
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/devicetype_utils.h" + +#include "ash/strings/grit/ash_strings.h" +#include "chromeos/system/devicetype.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +base::string16 SubstituteChromeOSDeviceType(int resource_id) { + return l10n_util::GetStringFUTF16(resource_id, GetChromeOSDeviceName()); +} + +base::string16 GetChromeOSDeviceName() { + return l10n_util::GetStringUTF16(GetChromeOSDeviceTypeResourceId()); +} + +int GetChromeOSDeviceTypeResourceId() { + switch (chromeos::GetDeviceType()) { + case chromeos::DeviceType::kChromebase: + return IDS_ASH_CHROMEBASE; + case chromeos::DeviceType::kChromebook: + return IDS_ASH_CHROMEBOOK; + case chromeos::DeviceType::kChromebox: + return IDS_ASH_CHROMEBOX; + case chromeos::DeviceType::kChromebit: + return IDS_ASH_CHROMEBIT; + case chromeos::DeviceType::kUnknown: + default: + return IDS_ASH_CHROMEDEVICE; + } +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/devicetype_utils.h b/ash/common/system/chromeos/devicetype_utils.h new file mode 100644 index 0000000..a84fd87 --- /dev/null +++ b/ash/common/system/chromeos/devicetype_utils.h
@@ -0,0 +1,26 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_ + +#include "ash/ash_export.h" +#include "base/strings/string16.h" + +namespace ash { + +// Assuming the given localization resources takes a device type parameter, this +// will substitute the appropriate device in (e.g. Chromebook, Chromebox). +ASH_EXPORT base::string16 SubstituteChromeOSDeviceType(int resource_id); + +// Returns the name of the Chrome device type (e.g. Chromebook, Chromebox). +ASH_EXPORT base::string16 GetChromeOSDeviceName(); + +// Returns the resource ID for the current Chrome device type (e.g. Chromebook, +// Chromebox). +ASH_EXPORT int GetChromeOSDeviceTypeResourceId(); + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_DEVICETYPE_UTILS_H_
diff --git a/ash/common/system/chromeos/enterprise/enterprise_domain_observer.h b/ash/common/system/chromeos/enterprise/enterprise_domain_observer.h new file mode 100644 index 0000000..35839764 --- /dev/null +++ b/ash/common/system/chromeos/enterprise/enterprise_domain_observer.h
@@ -0,0 +1,19 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_ENTERPRISE_ENTERPRISE_DOMAIN_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_ENTERPRISE_ENTERPRISE_DOMAIN_OBSERVER_H_ + +namespace ash { + +class EnterpriseDomainObserver { + public: + virtual ~EnterpriseDomainObserver() {} + + virtual void OnEnterpriseDomainChanged() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_ENTERPRISE_ENTERPRISE_DOMAIN_OBSERVER_H_
diff --git a/ash/common/system/chromeos/enterprise/tray_enterprise.cc b/ash/common/system/chromeos/enterprise/tray_enterprise.cc new file mode 100644 index 0000000..26f48cab --- /dev/null +++ b/ash/common/system/chromeos/enterprise/tray_enterprise.cc
@@ -0,0 +1,57 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/enterprise/tray_enterprise.h" + +#include "ash/common/login_status.h" +#include "ash/common/system/tray/label_tray_view.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "base/logging.h" +#include "base/strings/string16.h" + +namespace ash { + +TrayEnterprise::TrayEnterprise(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_ENTERPRISE), tray_view_(nullptr) { + WmShell::Get()->system_tray_notifier()->AddEnterpriseDomainObserver(this); +} + +TrayEnterprise::~TrayEnterprise() { + WmShell::Get()->system_tray_notifier()->RemoveEnterpriseDomainObserver(this); +} + +void TrayEnterprise::UpdateEnterpriseMessage() { + base::string16 message = + WmShell::Get()->system_tray_delegate()->GetEnterpriseMessage(); + if (tray_view_) + tray_view_->SetMessage(message); +} + +views::View* TrayEnterprise::CreateDefaultView(LoginStatus status) { + CHECK(tray_view_ == NULL); + // For public accounts, enterprise ownership is indicated in the user details + // instead. + if (status == LoginStatus::PUBLIC) + return NULL; + tray_view_ = new LabelTrayView(this, IDR_AURA_UBER_TRAY_ENTERPRISE); + UpdateEnterpriseMessage(); + return tray_view_; +} + +void TrayEnterprise::DestroyDefaultView() { + tray_view_ = NULL; +} + +void TrayEnterprise::OnEnterpriseDomainChanged() { + UpdateEnterpriseMessage(); +} + +void TrayEnterprise::OnViewClicked(views::View* sender) { + WmShell::Get()->system_tray_delegate()->ShowEnterpriseInfo(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/enterprise/tray_enterprise.h b/ash/common/system/chromeos/enterprise/tray_enterprise.h new file mode 100644 index 0000000..bc33519 --- /dev/null +++ b/ash/common/system/chromeos/enterprise/tray_enterprise.h
@@ -0,0 +1,46 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_ENTERPRISE_TRAY_ENTERPRISE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_ENTERPRISE_TRAY_ENTERPRISE_H_ + +#include "ash/common/system/chromeos/enterprise/enterprise_domain_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "base/macros.h" + +namespace ash { +class LabelTrayView; +class SystemTray; + +class TrayEnterprise : public SystemTrayItem, + public ViewClickListener, + public EnterpriseDomainObserver { + public: + explicit TrayEnterprise(SystemTray* system_tray); + ~TrayEnterprise() override; + + // If message is not empty updates content of default view, otherwise hides + // tray items. + void UpdateEnterpriseMessage(); + + // Overridden from SystemTrayItem. + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyDefaultView() override; + + // Overridden from EnterpriseDomainObserver. + void OnEnterpriseDomainChanged() override; + + // Overridden from ViewClickListener. + void OnViewClicked(views::View* sender) override; + + private: + LabelTrayView* tray_view_; + + DISALLOW_COPY_AND_ASSIGN(TrayEnterprise); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_ENTERPRISE_TRAY_ENTERPRISE_H_
diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.cc b/ash/common/system/chromeos/ime_menu/ime_list_view.cc new file mode 100644 index 0000000..c26468c --- /dev/null +++ b/ash/common/system/chromeos/ime_menu/ime_list_view.cc
@@ -0,0 +1,469 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_popup_header_button.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/keyboard/keyboard_util.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/toggle_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +const int kMinFontSizeDelta = -10; + +const SkColor kKeyboardRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); + +// A |HoverHighlightView| that uses bold or normal font depending on whether it +// is selected. This view exposes itself as a checkbox to the accessibility +// framework. +class SelectableHoverHighlightView : public HoverHighlightView { + public: + SelectableHoverHighlightView(ViewClickListener* listener, + const base::string16& label, + bool selected) + : HoverHighlightView(listener), selected_(selected) { + AddLabel(label, gfx::ALIGN_LEFT, selected); + } + + ~SelectableHoverHighlightView() override {} + + protected: + // views::View: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + HoverHighlightView::GetAccessibleNodeData(node_data); + node_data->role = ui::AX_ROLE_CHECK_BOX; + if (selected_) + node_data->AddStateFlag(ui::AX_STATE_CHECKED); + } + + private: + bool selected_; + + DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView); +}; + +// The IME list item view used in the material design. It contains IME info +// (name and label) and a check button if the item is selected. It's also used +// for IME property item, which has no name but label and a gray checked icon. +class ImeListItemView : public ActionableView { + public: + ImeListItemView(SystemTrayItem* owner, + ImeListView* list_view, + const base::string16& id, + const base::string16& label, + bool selected, + const SkColor button_color) + : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), + ime_list_view_(list_view), + selected_(selected) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + SetInkDropMode(InkDropHostView::InkDropMode::ON); + + TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view); + SetLayoutManager(new views::FillLayout); + + // The id button shows the IME short name. + views::Label* id_label = TrayPopupUtils::CreateDefaultLabel(); + id_label->SetText(id); + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + const gfx::FontList& base_font_list = + rb.GetFontList(ui::ResourceBundle::MediumBoldFont); + id_label->SetFontList(base_font_list); + + // For IMEs whose short name are more than 2 characters (INTL, EXTD, etc.), + // |kMenuIconSize| is not enough. The label will trigger eliding as "I..." + // or "...". So we shrink the font size until it fits within the bounds. + int size_delta = -1; + while ((id_label->GetPreferredSize().width() - + id_label->GetInsets().width()) > kMenuIconSize && + size_delta >= kMinFontSizeDelta) { + id_label->SetFontList(base_font_list.DeriveWithSizeDelta(size_delta)); + --size_delta; + } + tri_view->AddView(TriView::Container::START, id_label); + + // The label shows the IME name. + auto* label_view = TrayPopupUtils::CreateDefaultLabel(); + label_view->SetText(label); + TrayPopupItemStyle style( + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + style.SetupLabel(label_view); + + label_view->SetHorizontalAlignment(gfx::ALIGN_LEFT); + tri_view->AddView(TriView::Container::CENTER, label_view); + + if (selected) { + // The checked button indicates the IME is selected. + views::ImageView* checked_image = TrayPopupUtils::CreateMainImageView(); + checked_image->SetImage(gfx::CreateVectorIcon( + gfx::VectorIconId::CHECK_CIRCLE, kMenuIconSize, button_color)); + tri_view->AddView(TriView::Container::END, checked_image); + } + SetAccessibleName(label_view->text()); + } + + ~ImeListItemView() override {} + + // ActionableView: + bool PerformAction(const ui::Event& event) override { + if (ime_list_view_->should_focus_ime_after_selection_with_keyboard() && + event.type() == ui::EventType::ET_KEY_PRESSED) { + ime_list_view_->set_last_item_selected_with_keyboard(true); + } else { + ime_list_view_->set_last_item_selected_with_keyboard(false); + } + + ime_list_view_->HandleViewClicked(this); + return true; + } + + void OnFocus() override { + ActionableView::OnFocus(); + if (ime_list_view_ && ime_list_view_->scroll_content()) + ime_list_view_->scroll_content()->ScrollRectToVisible(bounds()); + } + + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + ActionableView::GetAccessibleNodeData(node_data); + node_data->role = ui::AX_ROLE_CHECK_BOX; + node_data->AddStateFlag(selected_ ? ui::AX_STATE_CHECKED + : ui::AX_STATE_NONE); + } + + private: + ImeListView* ime_list_view_; + bool selected_; + + DISALLOW_COPY_AND_ASSIGN(ImeListItemView); +}; + +} // namespace + +// The view that contains a |KeyboardButtonView| and a toggle button. +class MaterialKeyboardStatusRowView : public views::View { + public: + MaterialKeyboardStatusRowView(views::ButtonListener* listener, bool enabled) + : listener_(listener), toggle_(nullptr) { + Init(); + toggle_->SetIsOn(enabled, false); + } + + ~MaterialKeyboardStatusRowView() override {} + + views::Button* toggle() const { return toggle_; } + bool is_toggled() const { return toggle_->is_on(); } + + protected: + // views::View: + int GetHeightForWidth(int w) const override { + return GetPreferredSize().height(); + } + + private: + void Init() { + TrayPopupUtils::ConfigureAsStickyHeader(this); + SetLayoutManager(new views::FillLayout); + + TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view); + + // The on-screen keyboard image button. + views::ImageView* keyboard_image = TrayPopupUtils::CreateMainImageView(); + keyboard_image->SetImage(gfx::CreateVectorIcon( + kImeMenuOnScreenKeyboardIcon, kMenuIconSize, kMenuIconColor)); + tri_view->AddView(TriView::Container::START, keyboard_image); + + // The on-screen keyboard label ('On-screen keyboard'). + auto* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(ui::ResourceBundle::GetSharedInstance().GetLocalizedString( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD)); + TrayPopupItemStyle style( + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + style.SetupLabel(label); + tri_view->AddView(TriView::Container::CENTER, label); + + // The on-screen keyboard toggle button. + toggle_ = TrayPopupUtils::CreateToggleButton( + listener_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD); + tri_view->AddView(TriView::Container::END, toggle_); + } + + // ButtonListener to notify when |toggle_| is clicked. + views::ButtonListener* listener_; + + // ToggleButton to toggle keyboard on or off. + views::ToggleButton* toggle_; + + DISALLOW_COPY_AND_ASSIGN(MaterialKeyboardStatusRowView); +}; + +ImeListView::ImeListView(SystemTrayItem* owner) + : TrayDetailsView(owner), + last_item_selected_with_keyboard_(false), + should_focus_ime_after_selection_with_keyboard_(false), + current_ime_view_(nullptr) {} + +ImeListView::~ImeListView() {} + +void ImeListView::Init(bool show_keyboard_toggle, + SingleImeBehavior single_ime_behavior) { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + IMEInfoList list; + delegate->GetAvailableIMEList(&list); + IMEPropertyInfoList property_list; + delegate->GetCurrentIMEProperties(&property_list); + Update(list, property_list, show_keyboard_toggle, single_ime_behavior); +} + +void ImeListView::Update(const IMEInfoList& list, + const IMEPropertyInfoList& property_list, + bool show_keyboard_toggle, + SingleImeBehavior single_ime_behavior) { + ResetImeListView(); + ime_map_.clear(); + property_map_.clear(); + CreateScrollableList(); + + // Appends IME list and IME properties. + if (single_ime_behavior == ImeListView::SHOW_SINGLE_IME || list.size() > 1) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + AppendImeListAndProperties(list, property_list); + } else { + AppendIMEList(list); + if (!property_list.empty()) + AppendIMEProperties(property_list); + } + } + + if (show_keyboard_toggle) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + PrependMaterialKeyboardStatus(); + } else { + if (list.size() > 1 || !property_list.empty()) + AddScrollSeparator(); + AppendKeyboardStatus(); + } + } + + Layout(); + SchedulePaint(); + + if (should_focus_ime_after_selection_with_keyboard_ && + last_item_selected_with_keyboard_) { + FocusCurrentImeIfNeeded(); + } else if (current_ime_view_) { + scroll_content()->ScrollRectToVisible(current_ime_view_->bounds()); + } +} + +void ImeListView::ResetImeListView() { + // Children are removed from the view hierarchy and deleted in Reset(). + Reset(); + material_keyboard_status_view_ = nullptr; + keyboard_status_ = nullptr; + current_ime_view_ = nullptr; +} + +void ImeListView::CloseImeListView() { + last_selected_item_id_.clear(); + current_ime_view_ = nullptr; + last_item_selected_with_keyboard_ = false; + GetWidget()->Close(); +} + +void ImeListView::AppendIMEList(const IMEInfoList& list) { + DCHECK(ime_map_.empty()); + for (size_t i = 0; i < list.size(); i++) { + HoverHighlightView* container = + new SelectableHoverHighlightView(this, list[i].name, list[i].selected); + scroll_content()->AddChildView(container); + ime_map_[container] = list[i].id; + } +} + +void ImeListView::AppendIMEProperties( + const IMEPropertyInfoList& property_list) { + DCHECK(property_map_.empty()); + for (size_t i = 0; i < property_list.size(); i++) { + HoverHighlightView* container = new SelectableHoverHighlightView( + this, property_list[i].name, property_list[i].selected); + if (i == 0) + container->SetBorder( + views::CreateSolidSidedBorder(1, 0, 0, 0, kBorderLightColor)); + scroll_content()->AddChildView(container); + property_map_[container] = property_list[i].key; + } +} + +void ImeListView::AppendImeListAndProperties( + const IMEInfoList& list, + const IMEPropertyInfoList& property_list) { + DCHECK(ime_map_.empty()); + for (size_t i = 0; i < list.size(); i++) { + views::View* ime_view = + new ImeListItemView(owner(), this, list[i].short_name, list[i].name, + list[i].selected, gfx::kGoogleGreen700); + scroll_content()->AddChildView(ime_view); + ime_map_[ime_view] = list[i].id; + + if (list[i].selected) + current_ime_view_ = ime_view; + + // In material design, the property items will be added after the current + // selected IME item. + if (list[i].selected && !property_list.empty()) { + // Adds a separator on the top of property items. + scroll_content()->AddChildView( + TrayPopupUtils::CreateListItemSeparator(true)); + + // Adds the property items. + for (size_t i = 0; i < property_list.size(); i++) { + ImeListItemView* property_view = new ImeListItemView( + owner(), this, base::string16(), property_list[i].name, + property_list[i].selected, kMenuIconColor); + scroll_content()->AddChildView(property_view); + property_map_[property_view] = property_list[i].key; + } + + // Adds a separator on the bottom of property items if there are still + // other IMEs under the current one. + if (i < list.size() - 1) + scroll_content()->AddChildView( + TrayPopupUtils::CreateListItemSeparator(true)); + } + } +} + +void ImeListView::AppendKeyboardStatus() { + DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); + HoverHighlightView* container = new HoverHighlightView(this); + int id = keyboard::IsKeyboardEnabled() ? IDS_ASH_STATUS_TRAY_DISABLE_KEYBOARD + : IDS_ASH_STATUS_TRAY_ENABLE_KEYBOARD; + container->AddLabel( + ui::ResourceBundle::GetSharedInstance().GetLocalizedString(id), + gfx::ALIGN_LEFT, false /* highlight */); + scroll_content()->AddChildView(container); + keyboard_status_ = container; +} + +void ImeListView::PrependMaterialKeyboardStatus() { + DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); + DCHECK(!material_keyboard_status_view_); + MaterialKeyboardStatusRowView* view = + new MaterialKeyboardStatusRowView(this, keyboard::IsKeyboardEnabled()); + scroll_content()->AddChildViewAt(view, 0); + material_keyboard_status_view_ = view; +} + +void ImeListView::HandleViewClicked(views::View* view) { + if (view == keyboard_status_) { + WmShell::Get()->ToggleIgnoreExternalKeyboard(); + last_selected_item_id_.clear(); + last_item_selected_with_keyboard_ = false; + return; + } + + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + std::map<views::View*, std::string>::const_iterator ime = ime_map_.find(view); + if (ime != ime_map_.end()) { + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_IME_SWITCH_MODE); + std::string ime_id = ime->second; + last_selected_item_id_ = ime_id; + delegate->SwitchIME(ime_id); + } else { + std::map<views::View*, std::string>::const_iterator property = + property_map_.find(view); + if (property == property_map_.end()) + return; + const std::string key = property->second; + last_selected_item_id_ = key; + delegate->ActivateIMEProperty(key); + } + + if (!should_focus_ime_after_selection_with_keyboard_ || + !last_item_selected_with_keyboard_) { + CloseImeListView(); + } +} + +void ImeListView::HandleButtonPressed(views::Button* sender, + const ui::Event& event) { + if (material_keyboard_status_view_ && + sender == material_keyboard_status_view_->toggle()) { + WmShell::Get()->ToggleIgnoreExternalKeyboard(); + last_selected_item_id_.clear(); + last_item_selected_with_keyboard_ = false; + } +} + +void ImeListView::VisibilityChanged(View* starting_from, bool is_visible) { + if (!is_visible || (should_focus_ime_after_selection_with_keyboard_ && + last_item_selected_with_keyboard_) || + !current_ime_view_) { + return; + } + + scroll_content()->ScrollRectToVisible(current_ime_view_->bounds()); +} + +void ImeListView::FocusCurrentImeIfNeeded() { + views::FocusManager* manager = GetFocusManager(); + if (!manager || manager->GetFocusedView() || last_selected_item_id_.empty()) + return; + + for (auto ime_map : ime_map_) { + if (ime_map.second == last_selected_item_id_) { + (ime_map.first)->RequestFocus(); + return; + } + } + + for (auto property_map : property_map_) { + if (property_map.second == last_selected_item_id_) { + (property_map.first)->RequestFocus(); + return; + } + } +} + +ImeListViewTestApi::ImeListViewTestApi(ImeListView* ime_list_view) + : ime_list_view_(ime_list_view) {} + +ImeListViewTestApi::~ImeListViewTestApi() {} + +views::View* ImeListViewTestApi::GetToggleView() const { + return ime_list_view_->material_keyboard_status_view_->toggle(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.h b/ash/common/system/chromeos/ime_menu/ime_list_view.h new file mode 100644 index 0000000..e756514b --- /dev/null +++ b/ash/common/system/chromeos/ime_menu/ime_list_view.h
@@ -0,0 +1,135 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_LIST_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_LIST_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ui/views/controls/button/button.h" + +namespace ash { +class MaterialKeyboardStatusRowView; + +// The detailed view for showing IME list. +class ImeListView : public TrayDetailsView { + public: + enum SingleImeBehavior { + // Shows the IME menu if there's only one IME in system. + SHOW_SINGLE_IME, + // Hides the IME menu if there's only one IME in system. + HIDE_SINGLE_IME + }; + + ImeListView(SystemTrayItem* owner); + + ~ImeListView() override; + + // Initializes the contents of a newly-instantiated ImeListView. + void Init(bool show_keyboard_toggle, SingleImeBehavior single_ime_behavior); + + // Updates the view. + virtual void Update(const IMEInfoList& list, + const IMEPropertyInfoList& property_list, + bool show_keyboard_toggle, + SingleImeBehavior single_ime_behavior); + + // Removes (and destroys) all child views. + virtual void ResetImeListView(); + + // Closes the view. + void CloseImeListView(); + + void set_last_item_selected_with_keyboard( + bool last_item_selected_with_keyboard) { + last_item_selected_with_keyboard_ = last_item_selected_with_keyboard; + } + + void set_should_focus_ime_after_selection_with_keyboard( + const bool focus_current_ime) { + should_focus_ime_after_selection_with_keyboard_ = focus_current_ime; + } + + bool should_focus_ime_after_selection_with_keyboard() const { + return should_focus_ime_after_selection_with_keyboard_; + } + + // TrayDetailsView: + void HandleViewClicked(views::View* view) override; + void HandleButtonPressed(views::Button* sender, + const ui::Event& event) override; + + // views::View: + void VisibilityChanged(View* starting_from, bool is_visible) override; + + private: + friend class ImeListViewTestApi; + + // Appends the IMEs to the scrollable area of the detailed view. + void AppendIMEList(const IMEInfoList& list); + + // Appends the IME listed to the scrollable area of the detailed view. + void AppendIMEProperties(const IMEPropertyInfoList& property_list); + + // Appends the IMEs and properties to the scrollable area in the material + // design IME menu. + void AppendImeListAndProperties(const IMEInfoList& list, + const IMEPropertyInfoList& property_list); + + // Appends the on-screen keyboard status to the last area of the detailed + // view. + void AppendKeyboardStatus(); + + // Inserts the material on-screen keyboard status in the detailed view. + void PrependMaterialKeyboardStatus(); + + // Requests focus on the current IME if it was selected with keyboard so that + // accessible text will alert the user of the IME change. + void FocusCurrentImeIfNeeded(); + + std::map<views::View*, std::string> ime_map_; + std::map<views::View*, std::string> property_map_; + // On-screen keyboard view which is not used in material design. + views::View* keyboard_status_; + // On-screen keyboard view which is only used in material design. + MaterialKeyboardStatusRowView* material_keyboard_status_view_; + + // The id of the last item selected with keyboard. It will be empty if the + // item is not selected with keyboard. + std::string last_selected_item_id_; + + // True if the last item is selected with keyboard. + bool last_item_selected_with_keyboard_; + + // True if focus should be requested after switching IMEs with keyboard in + // order to trigger spoken feedback with ChromeVox enabled. + bool should_focus_ime_after_selection_with_keyboard_; + + // The item view of the current selected IME. + views::View* current_ime_view_; + + DISALLOW_COPY_AND_ASSIGN(ImeListView); +}; + +class ASH_EXPORT ImeListViewTestApi { + public: + explicit ImeListViewTestApi(ImeListView* ime_list_view); + virtual ~ImeListViewTestApi(); + + views::View* GetToggleView() const; + + const std::map<views::View*, std::string>& ime_map() const { + return ime_list_view_->ime_map_; + } + + private: + ImeListView* ime_list_view_; + + DISALLOW_COPY_AND_ASSIGN(ImeListViewTestApi); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_LIST_VIEW_H_
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc new file mode 100644 index 0000000..b683e1c --- /dev/null +++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray.cc
@@ -0,0 +1,650 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/ime_menu/ime_menu_tray.h" + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/ash_constants.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/metrics/histogram_macros.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/base/ime/ime_bridge.h" +#include "ui/base/ime/text_input_client.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/range/range.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_util.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" + +using chromeos::input_method::InputMethodManager; + +namespace ash { + +namespace { +// Returns the height range of ImeListView. +gfx::Range GetImeListViewRange() { + const int max_items = 5; + const int min_items = 1; + const int tray_item_height = kTrayPopupItemMinHeight; + return gfx::Range(tray_item_height * min_items, tray_item_height * max_items); +} + +// Returns the minimum with of IME menu. +int GetMinimumMenuWidth() { + return MaterialDesignController::IsSystemTrayMenuMaterial() + ? kTrayMenuMinimumWidthMd + : kTrayMenuMinimumWidth; +} + +// Shows language and input settings page. +void ShowIMESettings() { + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_IME_SHOW_DETAILED); + WmShell::Get()->system_tray_controller()->ShowIMESettings(); +} + +// Records the number of times users click buttons in opt-in IME menu. +void RecordButtonsClicked(const std::string& button_name) { + enum { + UNKNOWN = 0, + EMOJI = 1, + HANDWRITING = 2, + VOICE = 3, + // SETTINGS is not used for now. + SETTINGS = 4, + BUTTON_MAX + } button = UNKNOWN; + if (button_name == "emoji") { + button = EMOJI; + } else if (button_name == "hwt") { + button = HANDWRITING; + } else if (button_name == "voice") { + button = VOICE; + } + UMA_HISTOGRAM_ENUMERATION("InputMethod.ImeMenu.EmojiHandwritingVoiceButton", + button, BUTTON_MAX); +} + +// Returns true if the current screen is login or lock screen. +bool IsInLoginOrLockScreen() { + LoginStatus login = + WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); + return !TrayPopupUtils::CanOpenWebUISettings(login); +} + +// Returns true if the current input context type is password. +bool IsInPasswordInputContext() { + return ui::IMEBridge::Get()->GetCurrentInputContext().type == + ui::TEXT_INPUT_TYPE_PASSWORD; +} + +class ImeMenuLabel : public views::Label { + public: + ImeMenuLabel() {} + ~ImeMenuLabel() override {} + + // views:Label: + gfx::Size GetPreferredSize() const override { + return gfx::Size(kTrayItemSize, kTrayItemSize); + } + int GetHeightForWidth(int width) const override { return kTrayItemSize; } + + private: + DISALLOW_COPY_AND_ASSIGN(ImeMenuLabel); +}; + +SystemMenuButton* CreateImeMenuButton(views::ButtonListener* listener, + const gfx::VectorIcon& icon, + int accessible_name_id, + int right_border) { + SystemMenuButton* button = new SystemMenuButton( + listener, TrayPopupInkDropStyle::HOST_CENTERED, icon, accessible_name_id); + if (!MaterialDesignController::IsShelfMaterial()) { + button->SetBorder( + views::CreateSolidSidedBorder(0, 0, 0, right_border, kBorderDarkColor)); + } + return button; +} + +// The view that contains IME menu title in the material design. +class ImeTitleView : public views::View, public views::ButtonListener { + public: + explicit ImeTitleView(bool show_settings_button) : settings_button_(nullptr) { + SetBorder(views::CreatePaddedBorder( + views::CreateSolidSidedBorder(0, 0, kSeparatorWidth, 0, + kMenuSeparatorColor), + gfx::Insets(kMenuSeparatorVerticalPadding - kSeparatorWidth, 0))); + auto* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + box_layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); + SetLayoutManager(box_layout); + auto* title_label = + new views::Label(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME)); + title_label->SetBorder( + views::CreateEmptyBorder(0, kMenuEdgeEffectivePadding, 1, 0)); + title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); + style.SetupLabel(title_label); + + AddChildView(title_label); + box_layout->SetFlexForView(title_label, 1); + + if (show_settings_button) { + settings_button_ = CreateImeMenuButton( + this, kSystemMenuSettingsIcon, IDS_ASH_STATUS_TRAY_IME_SETTINGS, 0); + if (IsInLoginOrLockScreen()) + settings_button_->SetEnabled(false); + AddChildView(settings_button_); + } + } + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + DCHECK_EQ(sender, settings_button_); + ShowIMESettings(); + } + + ~ImeTitleView() override {} + + private: + // Settings button that is only used in material design, and only if the + // emoji, handwriting and voice buttons are not available. + SystemMenuButton* settings_button_; + + DISALLOW_COPY_AND_ASSIGN(ImeTitleView); +}; + +// The view that contains buttons shown on the bottom of IME menu. +class ImeButtonsView : public views::View, + public views::ButtonListener, + public ViewClickListener { + public: + ImeButtonsView(ImeMenuTray* ime_menu_tray, + bool show_emoji_button, + bool show_voice_button, + bool show_handwriting_button, + bool show_settings_button) + : ime_menu_tray_(ime_menu_tray) { + DCHECK(ime_menu_tray_); + + if (!MaterialDesignController::IsSystemTrayMenuMaterial()) + SetBorder(views::CreateSolidSidedBorder(1, 0, 0, 0, kBorderDarkColor)); + + // If there's only one settings button, the bottom should be a label with + // normal background. Otherwise, show button icons with header background. + if (show_settings_button && !show_emoji_button && + !show_handwriting_button && !show_voice_button) { + DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); + ShowOneSettingButton(); + } else { + ShowButtons(show_emoji_button, show_handwriting_button, show_voice_button, + show_settings_button); + } + } + + ~ImeButtonsView() override {} + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + if (sender == settings_button_) { + ime_menu_tray_->HideImeMenuBubble(); + ShowIMESettings(); + return; + } + + // The |keyset| will be used for drawing input view keyset in IME + // extensions. InputMethodManager::ShowKeyboardWithKeyset() will deal with + // the |keyset| string to generate the right input view url. + std::string keyset; + if (sender == emoji_button_) { + keyset = "emoji"; + RecordButtonsClicked(keyset); + } else if (sender == voice_button_) { + keyset = "voice"; + RecordButtonsClicked(keyset); + } else if (sender == handwriting_button_) { + keyset = "hwt"; + RecordButtonsClicked(keyset); + } else { + NOTREACHED(); + } + + ime_menu_tray_->ShowKeyboardWithKeyset(keyset); + } + + // ViewClickListener: + void OnViewClicked(views::View* sender) override { + if (one_settings_button_view_ && sender == one_settings_button_view_) { + ime_menu_tray_->HideImeMenuBubble(); + ShowIMESettings(); + } + } + + private: + // Shows the UI of one settings button. + void ShowOneSettingButton() { + auto* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + box_layout->SetDefaultFlex(1); + SetLayoutManager(box_layout); + one_settings_button_view_ = new HoverHighlightView(this); + one_settings_button_view_->AddLabel( + ui::ResourceBundle::GetSharedInstance().GetLocalizedString( + IDS_ASH_STATUS_TRAY_IME_SETTINGS), + gfx::ALIGN_LEFT, false /* highlight */); + if (IsInLoginOrLockScreen()) + one_settings_button_view_->SetEnabled(false); + AddChildView(one_settings_button_view_); + } + + // Shows the UI of more than one buttons. + void ShowButtons(bool show_emoji_button, + bool show_handwriting_button, + bool show_voice_button, + bool show_settings_button) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + auto* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + box_layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); + SetLayoutManager(box_layout); + SetBorder(views::CreatePaddedBorder( + views::CreateSolidSidedBorder(kSeparatorWidth, 0, 0, 0, + kMenuSeparatorColor), + gfx::Insets(kMenuSeparatorVerticalPadding - kSeparatorWidth, + kMenuExtraMarginFromLeftEdge))); + } else { + auto* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 4, 4, 0); + set_background( + views::Background::CreateSolidBackground(kHeaderBackgroundColor)); + box_layout->SetDefaultFlex(1); + SetLayoutManager(box_layout); + } + + const int right_border = 1; + if (show_emoji_button) { + emoji_button_ = + CreateImeMenuButton(this, kImeMenuEmoticonIcon, + IDS_ASH_STATUS_TRAY_IME_EMOJI, right_border); + AddChildView(emoji_button_); + } + + if (show_handwriting_button) { + handwriting_button_ = CreateImeMenuButton( + this, kImeMenuWriteIcon, IDS_ASH_STATUS_TRAY_IME_HANDWRITING, + right_border); + AddChildView(handwriting_button_); + } + + if (show_voice_button) { + voice_button_ = + CreateImeMenuButton(this, kImeMenuMicrophoneIcon, + IDS_ASH_STATUS_TRAY_IME_VOICE, right_border); + AddChildView(voice_button_); + } + + if (show_settings_button) { + settings_button_ = CreateImeMenuButton( + this, kSystemMenuSettingsIcon, IDS_ASH_STATUS_TRAY_IME_SETTINGS, 0); + AddChildView(settings_button_); + } + } + + ImeMenuTray* ime_menu_tray_; + SystemMenuButton* emoji_button_; + SystemMenuButton* handwriting_button_; + SystemMenuButton* voice_button_; + SystemMenuButton* settings_button_; + HoverHighlightView* one_settings_button_view_; + + DISALLOW_COPY_AND_ASSIGN(ImeButtonsView); +}; + +// The list view that contains the selected IME and property items. +class ImeMenuListView : public ImeListView { + public: + ImeMenuListView(SystemTrayItem* owner) : ImeListView(owner) { + set_should_focus_ime_after_selection_with_keyboard(true); + } + + ~ImeMenuListView() override {} + + protected: + void Layout() override { + gfx::Range height_range = GetImeListViewRange(); + scroller()->ClipHeightTo(height_range.start(), height_range.end()); + ImeListView::Layout(); + } + + DISALLOW_COPY_AND_ASSIGN(ImeMenuListView); +}; + +} // namespace + +ImeMenuTray::ImeMenuTray(WmShelf* wm_shelf) + : TrayBackgroundView(wm_shelf), + label_(new ImeMenuLabel()), + show_keyboard_(false), + force_show_keyboard_(false), + should_block_shelf_auto_hide_(false), + keyboard_suppressed_(false), + show_bubble_after_keyboard_hidden_(false) { + if (MaterialDesignController::IsShelfMaterial()) { + SetInkDropMode(InkDropMode::ON); + SetContentsBackground(false); + } else { + SetContentsBackground(true); + } + SetupLabelForTray(label_); + tray_container()->AddChildView(label_); + SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); + tray_notifier->AddIMEObserver(this); + tray_notifier->AddVirtualKeyboardObserver(this); +} + +ImeMenuTray::~ImeMenuTray() { + if (bubble_) + bubble_->bubble_view()->reset_delegate(); + SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); + tray_notifier->RemoveIMEObserver(this); + tray_notifier->RemoveVirtualKeyboardObserver(this); + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) + keyboard_controller->RemoveObserver(this); +} + +void ImeMenuTray::ShowImeMenuBubble() { + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller && keyboard_controller->keyboard_visible()) { + show_bubble_after_keyboard_hidden_ = true; + keyboard_controller->AddObserver(this); + keyboard_controller->HideKeyboard( + keyboard::KeyboardController::HIDE_REASON_AUTOMATIC); + } else { + ShowImeMenuBubbleInternal(); + } +} + +void ImeMenuTray::ShowImeMenuBubbleInternal() { + int minimum_menu_width = GetMinimumMenuWidth(); + should_block_shelf_auto_hide_ = true; + views::TrayBubbleView::InitParams init_params( + GetAnchorAlignment(), minimum_menu_width, minimum_menu_width); + init_params.can_activate = true; + init_params.close_on_deactivate = true; + + views::TrayBubbleView* bubble_view = + views::TrayBubbleView::Create(GetBubbleAnchor(), this, &init_params); + bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets()); + + // In the material design, we will add a title item with a separator on the + // top of the IME menu. + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + bubble_view->AddChildView( + new ImeTitleView(!ShouldShowEmojiHandwritingVoiceButtons())); + } else { + bubble_view->set_margins(gfx::Insets(7, 0, 0, 0)); + } + + // Adds IME list to the bubble. + ime_list_view_ = new ImeMenuListView(nullptr); + ime_list_view_->Init(ShouldShowKeyboardToggle(), + ImeListView::SHOW_SINGLE_IME); + bubble_view->AddChildView(ime_list_view_); + + if (ShouldShowEmojiHandwritingVoiceButtons()) { + bubble_view->AddChildView(new ImeButtonsView(this, true, true, true, true)); + } else if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { + // For MD, we don't need |ImeButtonsView| as the settings button will be + // shown in the title row. + bubble_view->AddChildView( + new ImeButtonsView(this, false, false, false, true)); + } + + bubble_.reset(new TrayBubbleWrapper(this, bubble_view)); + SetIsActive(true); +} + +void ImeMenuTray::HideImeMenuBubble() { + bubble_.reset(); + ime_list_view_ = nullptr; + SetIsActive(false); + should_block_shelf_auto_hide_ = false; + shelf()->UpdateAutoHideState(); +} + +bool ImeMenuTray::IsImeMenuBubbleShown() { + return !!bubble_; +} + +void ImeMenuTray::ShowKeyboardWithKeyset(const std::string& keyset) { + HideImeMenuBubble(); + + // Overrides the keyboard url ref to make it shown with the given keyset. + if (InputMethodManager::Get()) + InputMethodManager::Get()->OverrideKeyboardUrlRef(keyset); + + // If onscreen keyboard has been enabled, shows the keyboard directly. + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + show_keyboard_ = true; + if (keyboard_controller) { + keyboard_controller->AddObserver(this); + // If the keyboard window hasn't been created yet, it means the extension + // cannot receive anything to show the keyboard. Therefore, instead of + // relying the extension to show the keyboard, forcibly show the keyboard + // window here (which will cause the keyboard window to be created). + // Otherwise, the extension will show keyboard by calling private api. The + // native side could just skip showing the keyboard. + if (!keyboard_controller->IsKeyboardWindowCreated()) + keyboard_controller->ShowKeyboard(false); + return; + } + + AccessibilityDelegate* accessibility_delegate = + WmShell::Get()->accessibility_delegate(); + // Fails to show the keyboard. + if (accessibility_delegate->IsVirtualKeyboardEnabled()) + return; + + // Onscreen keyboard has not been enabled yet, forces to bring out the + // keyboard for one time. + force_show_keyboard_ = true; + accessibility_delegate->SetVirtualKeyboardEnabled(true); + keyboard_controller = keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) { + keyboard_controller->AddObserver(this); + keyboard_controller->ShowKeyboard(false); + } +} + +bool ImeMenuTray::ShouldBlockShelfAutoHide() const { + return should_block_shelf_auto_hide_; +} + +bool ImeMenuTray::ShouldShowEmojiHandwritingVoiceButtons() const { + // Emoji, handwriting and voice input is not supported for these cases: + // 1) features::kEHVInputOnImeMenu is not enabled. + // 2) third party IME extensions. + // 3) login/lock screen. + // 4) password input client. + return InputMethodManager::Get() && + InputMethodManager::Get()->IsEmojiHandwritingVoiceOnImeMenuEnabled() && + !current_ime_.third_party && !IsInLoginOrLockScreen() && + !IsInPasswordInputContext(); +} + +bool ImeMenuTray::ShouldShowKeyboardToggle() const { + return keyboard_suppressed_ && + !WmShell::Get()->accessibility_delegate()->IsVirtualKeyboardEnabled(); +} + +void ImeMenuTray::SetShelfAlignment(ShelfAlignment alignment) { + TrayBackgroundView::SetShelfAlignment(alignment); + if (!MaterialDesignController::IsShelfMaterial()) + tray_container()->SetBorder(views::NullBorder()); +} + +base::string16 ImeMenuTray::GetAccessibleNameForTray() { + return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME); +} + +void ImeMenuTray::HideBubbleWithView(const views::TrayBubbleView* bubble_view) { + if (bubble_->bubble_view() == bubble_view) + HideImeMenuBubble(); +} + +void ImeMenuTray::ClickedOutsideBubble() { + HideImeMenuBubble(); +} + +bool ImeMenuTray::PerformAction(const ui::Event& event) { + if (bubble_) + HideImeMenuBubble(); + else + ShowImeMenuBubble(); + return true; +} + +void ImeMenuTray::OnIMERefresh() { + UpdateTrayLabel(); + if (bubble_ && ime_list_view_) { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + IMEInfoList list; + delegate->GetAvailableIMEList(&list); + IMEPropertyInfoList property_list; + delegate->GetCurrentIMEProperties(&property_list); + ime_list_view_->Update(list, property_list, false, + ImeListView::SHOW_SINGLE_IME); + } +} + +void ImeMenuTray::OnIMEMenuActivationChanged(bool is_activated) { + SetVisible(is_activated); + if (is_activated) + UpdateTrayLabel(); + else + HideImeMenuBubble(); +} + +void ImeMenuTray::BubbleViewDestroyed() { +} + +void ImeMenuTray::OnMouseEnteredView() {} + +void ImeMenuTray::OnMouseExitedView() {} + +base::string16 ImeMenuTray::GetAccessibleNameForBubble() { + return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME); +} + +void ImeMenuTray::OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const { + // Place the bubble in the same root window as |anchor_widget|. + WmWindow::Get(anchor_widget->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + bubble_widget, kShellWindowId_SettingBubbleContainer, params); +} + +void ImeMenuTray::HideBubble(const views::TrayBubbleView* bubble_view) { + HideBubbleWithView(bubble_view); +} + +void ImeMenuTray::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) {} + +void ImeMenuTray::OnKeyboardClosed() { + if (InputMethodManager::Get()) + InputMethodManager::Get()->OverrideKeyboardUrlRef(std::string()); + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) + keyboard_controller->RemoveObserver(this); + + show_keyboard_ = false; + force_show_keyboard_ = false; +} + +void ImeMenuTray::OnKeyboardHidden() { + if (show_bubble_after_keyboard_hidden_) { + show_bubble_after_keyboard_hidden_ = false; + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) + keyboard_controller->RemoveObserver(this); + + ShowImeMenuBubbleInternal(); + return; + } + + if (!show_keyboard_) + return; + + // If the the IME menu has overriding the input view url, we should write it + // back to normal keyboard when hiding the input view. + if (InputMethodManager::Get()) + InputMethodManager::Get()->OverrideKeyboardUrlRef(std::string()); + show_keyboard_ = false; + + // If the keyboard is forced to be shown by IME menu for once, we need to + // disable the keyboard when it's hidden. + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) + keyboard_controller->RemoveObserver(this); + + if (!force_show_keyboard_) + return; + + WmShell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(false); + force_show_keyboard_ = false; +} + +void ImeMenuTray::OnKeyboardSuppressionChanged(bool suppressed) { + if (suppressed != keyboard_suppressed_ && bubble_) + HideImeMenuBubble(); + keyboard_suppressed_ = suppressed; +} + +void ImeMenuTray::UpdateTrayLabel() { + WmShell::Get()->system_tray_delegate()->GetCurrentIME(¤t_ime_); + + // Updates the tray label based on the current input method. + if (current_ime_.third_party) + label_->SetText(current_ime_.short_name + base::UTF8ToUTF16("*")); + else + label_->SetText(current_ime_.short_name); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray.h b/ash/common/system/chromeos/ime_menu/ime_menu_tray.h new file mode 100644 index 0000000..0c83552 --- /dev/null +++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray.h
@@ -0,0 +1,118 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_MENU_TRAY_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_MENU_TRAY_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h" +#include "ash/common/system/ime/ime_observer.h" +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "ash/common/system/tray/tray_bubble_wrapper.h" +#include "base/macros.h" +#include "ui/keyboard/keyboard_controller_observer.h" +#include "ui/views/bubble/tray_bubble_view.h" + +namespace views { +class Label; +} // namespace views + +namespace ash { +class ImeListView; + +// The tray item for IME menu, which shows the detailed view of a null single +// item. +class ASH_EXPORT ImeMenuTray : public TrayBackgroundView, + public IMEObserver, + public views::TrayBubbleView::Delegate, + public keyboard::KeyboardControllerObserver, + public VirtualKeyboardObserver { + public: + explicit ImeMenuTray(WmShelf* wm_shelf); + ~ImeMenuTray() override; + + // Shows the IME menu bubble and highlights the button. + void ShowImeMenuBubble(); + + // Hides the IME menu bubble and lowlights the button. + void HideImeMenuBubble(); + + // Returns true if the IME menu bubble has been shown. + bool IsImeMenuBubbleShown(); + + // Shows the virtual keyboard with the given keyset: emoji, handwriting or + // voice. + void ShowKeyboardWithKeyset(const std::string& keyset); + + // Returns true if it should block the auto hide behavior of the shelf. + bool ShouldBlockShelfAutoHide() const; + + // Returns true if the menu should show emoji, handwriting and voice buttons + // on the bottom. Otherwise, the menu will show a 'Customize...' bottom row + // for non-MD UI, and a Settings button in the title row for MD. + bool ShouldShowEmojiHandwritingVoiceButtons() const; + + // Returns whether the virtual keyboard toggle should be shown in shown in the + // opt-in IME menu. + bool ShouldShowKeyboardToggle() const; + + // TrayBackgroundView: + void SetShelfAlignment(ShelfAlignment alignment) override; + base::string16 GetAccessibleNameForTray() override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void ClickedOutsideBubble() override; + bool PerformAction(const ui::Event& event) override; + + // IMEObserver: + void OnIMERefresh() override; + void OnIMEMenuActivationChanged(bool is_activated) override; + + // views::TrayBubbleView::Delegate: + void BubbleViewDestroyed() override; + void OnMouseEnteredView() override; + void OnMouseExitedView() override; + base::string16 GetAccessibleNameForBubble() override; + void OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const override; + void HideBubble(const views::TrayBubbleView* bubble_view) override; + + // keyboard::KeyboardControllerObserver: + void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; + void OnKeyboardClosed() override; + void OnKeyboardHidden() override; + + // VirtualKeyboardObserver: + void OnKeyboardSuppressionChanged(bool suppressed) override; + + private: + // To allow the test class to access |label_|. + friend class ImeMenuTrayTest; + + // Show the IME menu bubble immediately. + void ShowImeMenuBubbleInternal(); + + // Updates the text of the label on the tray. + void UpdateTrayLabel(); + + // Bubble for default and detailed views. + std::unique_ptr<TrayBubbleWrapper> bubble_; + ImeListView* ime_list_view_; + + views::Label* label_; + IMEInfo current_ime_; + bool show_keyboard_; + bool force_show_keyboard_; + bool should_block_shelf_auto_hide_; + bool keyboard_suppressed_; + bool show_bubble_after_keyboard_hidden_; + + DISALLOW_COPY_AND_ASSIGN(ImeMenuTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_IME_MENU_IME_MENU_TRAY_H_
diff --git a/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc b/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc new file mode 100644 index 0000000..a7ebfc31 --- /dev/null +++ b/ash/common/system/chromeos/ime_menu/ime_menu_tray_unittest.cc
@@ -0,0 +1,313 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/ime_menu/ime_menu_tray.h" + +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accessibility_delegate.h" +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/status_area_widget_test_helper.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/base/ime/chromeos/mock_input_method_manager.h" +#include "ui/base/ime/ime_bridge.h" +#include "ui/base/ime/text_input_flags.h" +#include "ui/events/event.h" +#include "ui/views/controls/label.h" + +using base::UTF8ToUTF16; + +namespace ash { + +ImeMenuTray* GetTray() { + return StatusAreaWidgetTestHelper::GetStatusAreaWidget()->ime_menu_tray(); +} + +class ImeMenuTrayTest : public test::AshTestBase { + public: + ImeMenuTrayTest() {} + ~ImeMenuTrayTest() override {} + + protected: + // Returns true if the IME menu tray is visible. + bool IsVisible() { return GetTray()->visible(); } + + // Returns the label text of the tray. + const base::string16& GetTrayText() { return GetTray()->label_->text(); } + + // Returns true if the background color of the tray is active. + bool IsTrayBackgroundActive() { return GetTray()->is_active(); } + + // Returns true if the IME menu bubble has been shown. + bool IsBubbleShown() { return GetTray()->IsImeMenuBubbleShown(); } + + // Returns true if the IME menu list has been updated with the right IME list. + bool IsTrayImeListValid(const std::vector<IMEInfo>& expected_imes, + const IMEInfo& expected_current_ime) { + const std::map<views::View*, std::string>& ime_map = + ImeListViewTestApi(GetTray()->ime_list_view_).ime_map(); + if (ime_map.size() != expected_imes.size()) + return false; + + std::vector<std::string> expected_ime_ids; + for (const auto& ime : expected_imes) { + expected_ime_ids.push_back(ime.id); + } + for (const auto& ime : ime_map) { + // Tests that all the IMEs on the view is in the list of selected IMEs. + if (std::find(expected_ime_ids.begin(), expected_ime_ids.end(), + ime.second) == expected_ime_ids.end()) { + return false; + } + + // Tests that the checked IME is the current IME. + ui::AXNodeData node_data; + node_data.state = 0; + ime.first->GetAccessibleNodeData(&node_data); + if (node_data.HasStateFlag(ui::AX_STATE_CHECKED)) { + if (ime.second != expected_current_ime.id) + return false; + } + } + return true; + } + + // Focuses in the given type of input context. + void FocusInInputContext(ui::TextInputType input_type) { + ui::IMEEngineHandlerInterface::InputContext input_context( + input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE); + ui::IMEBridge::Get()->SetCurrentInputContext(input_context); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ImeMenuTrayTest); +}; + +// Tests that visibility of IME menu tray should be consistent with the +// activation of the IME menu. +TEST_F(ImeMenuTrayTest, ImeMenuTrayVisibility) { + ASSERT_FALSE(IsVisible()); + + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + EXPECT_TRUE(IsVisible()); + + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(false); + EXPECT_FALSE(IsVisible()); +} + +// Tests that IME menu tray shows the right info of the current IME. +TEST_F(ImeMenuTrayTest, TrayLabelTest) { + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + ASSERT_TRUE(IsVisible()); + + // Changes the input method to "ime1". + IMEInfo info1; + info1.id = "ime1"; + info1.name = UTF8ToUTF16("English"); + info1.medium_name = UTF8ToUTF16("English"); + info1.short_name = UTF8ToUTF16("US"); + info1.third_party = false; + info1.selected = true; + GetSystemTrayDelegate()->SetCurrentIME(info1); + WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); + EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); + + // Changes the input method to a third-party IME extension. + IMEInfo info2; + info2.id = "ime2"; + info2.name = UTF8ToUTF16("English UK"); + info2.medium_name = UTF8ToUTF16("English UK"); + info2.short_name = UTF8ToUTF16("UK"); + info2.third_party = true; + info2.selected = true; + GetSystemTrayDelegate()->SetCurrentIME(info2); + WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); + EXPECT_EQ(UTF8ToUTF16("UK*"), GetTrayText()); +} + +// Tests that IME menu tray changes background color when tapped/clicked. And +// tests that the background color becomes 'inactive' when disabling the IME +// menu feature. +TEST_F(ImeMenuTrayTest, PerformAction) { + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + ASSERT_TRUE(IsVisible()); + ASSERT_FALSE(IsTrayBackgroundActive()); + + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + GetTray()->PerformAction(tap); + EXPECT_TRUE(IsTrayBackgroundActive()); + EXPECT_TRUE(IsBubbleShown()); + + GetTray()->PerformAction(tap); + EXPECT_FALSE(IsTrayBackgroundActive()); + EXPECT_FALSE(IsBubbleShown()); + + // If disabling the IME menu feature when the menu tray is activated, the tray + // element will be deactivated. + GetTray()->PerformAction(tap); + EXPECT_TRUE(IsTrayBackgroundActive()); + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(false); + EXPECT_FALSE(IsVisible()); + EXPECT_FALSE(IsBubbleShown()); + EXPECT_FALSE(IsTrayBackgroundActive()); +} + +// Tests that IME menu list updates when changing the current IME. This should +// only happen by using shortcuts (Ctrl + Space / Ctrl + Shift + Space) to +// switch IMEs. +TEST_F(ImeMenuTrayTest, RefreshImeWithListViewCreated) { + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + GetTray()->PerformAction(tap); + + EXPECT_TRUE(IsTrayBackgroundActive()); + EXPECT_TRUE(IsBubbleShown()); + + IMEInfo info1, info2, info3; + info1.id = "ime1"; + info1.name = UTF8ToUTF16("English"); + info1.medium_name = UTF8ToUTF16("English"); + info1.short_name = UTF8ToUTF16("US"); + info1.third_party = false; + info1.selected = true; + + info2.id = "ime2"; + info2.name = UTF8ToUTF16("English UK"); + info2.medium_name = UTF8ToUTF16("English UK"); + info2.short_name = UTF8ToUTF16("UK"); + info2.third_party = true; + info2.selected = false; + + info3.id = "ime3"; + info3.name = UTF8ToUTF16("Pinyin"); + info3.medium_name = UTF8ToUTF16("Chinese Pinyin"); + info3.short_name = UTF8ToUTF16("拼"); + info3.third_party = false; + info3.selected = false; + + std::vector<IMEInfo> ime_info_list{info1, info2, info3}; + + GetSystemTrayDelegate()->SetAvailableIMEList(ime_info_list); + GetSystemTrayDelegate()->SetCurrentIME(info1); + WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); + EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); + EXPECT_TRUE(IsTrayImeListValid(ime_info_list, info1)); + + ime_info_list[0].selected = false; + ime_info_list[2].selected = true; + GetSystemTrayDelegate()->SetAvailableIMEList(ime_info_list); + GetSystemTrayDelegate()->SetCurrentIME(info3); + WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); + EXPECT_EQ(UTF8ToUTF16("拼"), GetTrayText()); + EXPECT_TRUE(IsTrayImeListValid(ime_info_list, info3)); + + // Closes the menu before quitting. + GetTray()->PerformAction(tap); + EXPECT_FALSE(IsTrayBackgroundActive()); + EXPECT_FALSE(IsBubbleShown()); +} + +// Tests that quits Chrome with IME menu openned will not crash. +TEST_F(ImeMenuTrayTest, QuitChromeWithMenuOpen) { + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + ASSERT_TRUE(IsVisible()); + ASSERT_FALSE(IsTrayBackgroundActive()); + + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + GetTray()->PerformAction(tap); + EXPECT_TRUE(IsTrayBackgroundActive()); + EXPECT_TRUE(IsBubbleShown()); +} + +// Tests using 'Alt+Shift+K' to open the menu. +TEST_F(ImeMenuTrayTest, TestAccelerator) { + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + ASSERT_TRUE(IsVisible()); + ASSERT_FALSE(IsTrayBackgroundActive()); + + WmShell::Get()->accelerator_controller()->PerformActionIfEnabled( + SHOW_IME_MENU_BUBBLE); + EXPECT_TRUE(IsTrayBackgroundActive()); + EXPECT_TRUE(IsBubbleShown()); + + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + GetTray()->PerformAction(tap); + EXPECT_FALSE(IsTrayBackgroundActive()); + EXPECT_FALSE(IsBubbleShown()); +} + +TEST_F(ImeMenuTrayTest, ShowEmojiKeyset) { + WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); + ASSERT_TRUE(IsVisible()); + ASSERT_FALSE(IsTrayBackgroundActive()); + + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + GetTray()->PerformAction(tap); + EXPECT_TRUE(IsTrayBackgroundActive()); + EXPECT_TRUE(IsBubbleShown()); + + AccessibilityDelegate* accessibility_delegate = + WmShell::Get()->accessibility_delegate(); + + accessibility_delegate->SetVirtualKeyboardEnabled(true); + EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); + + GetTray()->ShowKeyboardWithKeyset("emoji"); + // The menu should be hidden. + EXPECT_FALSE(IsBubbleShown()); + // The virtual keyboard should be enabled. + EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); + + // Hides the keyboard. + GetTray()->OnKeyboardHidden(); + // The keyboard should still be enabled. + EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); +} + +TEST_F(ImeMenuTrayTest, ForceToShowEmojiKeyset) { + AccessibilityDelegate* accessibility_delegate = + WmShell::Get()->accessibility_delegate(); + accessibility_delegate->SetVirtualKeyboardEnabled(false); + ASSERT_FALSE(accessibility_delegate->IsVirtualKeyboardEnabled()); + + GetTray()->ShowKeyboardWithKeyset("emoji"); + // The virtual keyboard should be enabled. + EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); + + // Hides the keyboard. + GetTray()->OnKeyboardHidden(); + // The keyboard should still be disabled. + EXPECT_FALSE(accessibility_delegate->IsVirtualKeyboardEnabled()); +} + +TEST_F(ImeMenuTrayTest, ShowEmojiHandwritingVoiceButtons) { + FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT); + EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons()); + + chromeos::input_method::InputMethodManager* input_method_manager = + chromeos::input_method::InputMethodManager::Get(); + EXPECT_FALSE(input_method_manager); + chromeos::input_method::InputMethodManager::Initialize( + new chromeos::input_method::MockInputMethodManager); + input_method_manager = chromeos::input_method::InputMethodManager::Get(); + EXPECT_TRUE(input_method_manager && + input_method_manager->IsEmojiHandwritingVoiceOnImeMenuEnabled()); + EXPECT_TRUE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons()); + + FocusInInputContext(ui::TEXT_INPUT_TYPE_PASSWORD); + EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/keyboard_brightness_controller.cc b/ash/common/system/chromeos/keyboard_brightness_controller.cc new file mode 100644 index 0000000..0d2cc1f --- /dev/null +++ b/ash/common/system/chromeos/keyboard_brightness_controller.cc
@@ -0,0 +1,38 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/keyboard_brightness_controller.h" + +#include "ash/common/wm_shell.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/base/accelerators/accelerator.h" + +namespace ash { + +void KeyboardBrightnessController::HandleKeyboardBrightnessDown( + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_DOWN) { + WmShell::Get()->RecordUserMetricsAction( + UMA_ACCEL_KEYBOARD_BRIGHTNESS_DOWN_F6); + } + + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->DecreaseKeyboardBrightness(); +} + +void KeyboardBrightnessController::HandleKeyboardBrightnessUp( + const ui::Accelerator& accelerator) { + if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_UP) { + WmShell::Get()->RecordUserMetricsAction( + UMA_ACCEL_KEYBOARD_BRIGHTNESS_UP_F7); + } + + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->IncreaseKeyboardBrightness(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/keyboard_brightness_controller.h b/ash/common/system/chromeos/keyboard_brightness_controller.h new file mode 100644 index 0000000..a305aab6 --- /dev/null +++ b/ash/common/system/chromeos/keyboard_brightness_controller.h
@@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_KEYBOARD_BRIGHTNESS_CONTROLLER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_KEYBOARD_BRIGHTNESS_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/keyboard_brightness_control_delegate.h" +#include "base/compiler_specific.h" +#include "base/macros.h" + +namespace ash { + +// A class which controls keyboard brightness when Alt+F6, Alt+F7 or a +// multimedia key for keyboard brightness is pressed. +class ASH_EXPORT KeyboardBrightnessController + : public KeyboardBrightnessControlDelegate { + public: + KeyboardBrightnessController() {} + ~KeyboardBrightnessController() override {} + + private: + // Overridden from KeyboardBrightnessControlDelegate: + void HandleKeyboardBrightnessDown( + const ui::Accelerator& accelerator) override; + void HandleKeyboardBrightnessUp(const ui::Accelerator& accelerator) override; + + DISALLOW_COPY_AND_ASSIGN(KeyboardBrightnessController); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_KEYBOARD_BRIGHTNESS_CONTROLLER_H_
diff --git a/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc new file mode 100644 index 0000000..0029822e --- /dev/null +++ b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.cc
@@ -0,0 +1,75 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/media_security/multi_profile_media_tray_item.h" + +#include "ash/common/ash_view_ids.h" +#include "ash/common/media_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/image_view.h" + +namespace ash { +namespace tray { + +class MultiProfileMediaTrayView : public TrayItemView, + public MediaCaptureObserver { + public: + explicit MultiProfileMediaTrayView(SystemTrayItem* system_tray_item) + : TrayItemView(system_tray_item) { + CreateImageView(); + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + image_view()->SetImage( + UseMd() + ? gfx::CreateVectorIcon(kSystemTrayRecordingIcon, kTrayIconColor) + : *bundle.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_RECORDING)); + WmShell::Get()->media_controller()->AddObserver(this); + SetVisible(false); + WmShell::Get()->media_controller()->RequestCaptureState(); + set_id(VIEW_ID_MEDIA_TRAY_VIEW); + } + + ~MultiProfileMediaTrayView() override { + WmShell::Get()->media_controller()->RemoveObserver(this); + } + + // MediaCaptureObserver: + void OnMediaCaptureChanged( + const std::vector<mojom::MediaCaptureState>& capture_states) override { + SessionStateDelegate* session_state_delegate = + WmShell::Get()->GetSessionStateDelegate(); + // The user at 0 is the current desktop user. + for (UserIndex index = 1; + index < session_state_delegate->NumberOfLoggedInUsers(); ++index) { + if (capture_states[index] != mojom::MediaCaptureState::NONE) { + SetVisible(true); + return; + } + } + SetVisible(false); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayView); +}; + +} // namespace tray + +MultiProfileMediaTrayItem::MultiProfileMediaTrayItem(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_MULTI_PROFILE_MEDIA) {} + +MultiProfileMediaTrayItem::~MultiProfileMediaTrayItem() {} + +views::View* MultiProfileMediaTrayItem::CreateTrayView(LoginStatus status) { + return new tray::MultiProfileMediaTrayView(this); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.h b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.h new file mode 100644 index 0000000..d4c9aa9 --- /dev/null +++ b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item.h
@@ -0,0 +1,28 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_MEDIA_SECURITY_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_MEDIA_SECURITY_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ + +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { + +// The tray item for media recording. +class ASH_EXPORT MultiProfileMediaTrayItem : public SystemTrayItem { + public: + explicit MultiProfileMediaTrayItem(SystemTray* system_tray); + ~MultiProfileMediaTrayItem() override; + + // SystemTrayItem: + views::View* CreateTrayView(LoginStatus status) override; + + private: + DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_MEDIA_SECURITY_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_
diff --git a/ash/common/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc new file mode 100644 index 0000000..d09cd84 --- /dev/null +++ b/ash/common/system/chromeos/media_security/multi_profile_media_tray_item_unittest.cc
@@ -0,0 +1,78 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/media_security/multi_profile_media_tray_item.h" + +#include "ash/common/ash_view_ids.h" +#include "ash/common/media_controller.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_bubble.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/public/interfaces/media.mojom.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/ash_test_helper.h" +#include "ash/test/status_area_widget_test_helper.h" +#include "ash/test/test_shell_delegate.h" +#include "ui/views/bubble/tray_bubble_view.h" + +namespace ash { + +class MultiProfileMediaTrayItemTest : public test::AshTestBase { + public: + MultiProfileMediaTrayItemTest() {} + ~MultiProfileMediaTrayItemTest() override {} + + void SetMediaCaptureState(mojom::MediaCaptureState state) { + // Create the fake update. + test::TestSessionStateDelegate* session_state_delegate = + test::AshTestHelper::GetTestSessionStateDelegate(); + std::vector<mojom::MediaCaptureState> v; + for (int i = 0; i < session_state_delegate->NumberOfLoggedInUsers(); ++i) + v.push_back(state); + WmShell::Get()->media_controller()->NotifyCaptureState(v); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayItemTest); +}; + +// ash_unittests. still failing. +TEST_F(MultiProfileMediaTrayItemTest, NotifyMediaCaptureChange) { + TrayItemView::DisableAnimationsForTest(); + test::TestSessionStateDelegate* session_state_delegate = + test::AshTestHelper::GetTestSessionStateDelegate(); + session_state_delegate->set_logged_in_users(2); + + SystemTray* system_tray = GetPrimarySystemTray(); + system_tray->ShowDefaultView(BUBBLE_CREATE_NEW); + views::View* in_user_view = + system_tray->GetSystemBubble()->bubble_view()->GetViewByID( + VIEW_ID_USER_VIEW_MEDIA_INDICATOR); + + StatusAreaWidget* widget = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); + EXPECT_TRUE(widget->GetRootView()->visible()); + views::View* tray_view = + widget->GetRootView()->GetViewByID(VIEW_ID_MEDIA_TRAY_VIEW); + + SetMediaCaptureState(mojom::MediaCaptureState::NONE); + EXPECT_FALSE(tray_view->visible()); + EXPECT_FALSE(in_user_view->visible()); + + SetMediaCaptureState(mojom::MediaCaptureState::AUDIO); + EXPECT_TRUE(tray_view->visible()); + EXPECT_TRUE(in_user_view->visible()); + + SetMediaCaptureState(mojom::MediaCaptureState::AUDIO_VIDEO); + EXPECT_TRUE(tray_view->visible()); + EXPECT_TRUE(in_user_view->visible()); + + SetMediaCaptureState(mojom::MediaCaptureState::NONE); + EXPECT_FALSE(tray_view->visible()); + EXPECT_FALSE(in_user_view->visible()); +} + +} // namespace ash
diff --git a/ash/system/network/DEPS b/ash/common/system/chromeos/network/DEPS similarity index 100% rename from ash/system/network/DEPS rename to ash/common/system/chromeos/network/DEPS
diff --git a/ash/common/system/chromeos/network/network_detailed_view.h b/ash/common/system/chromeos/network/network_detailed_view.h new file mode 100644 index 0000000..4180d622 --- /dev/null +++ b/ash/common/system/chromeos/network/network_detailed_view.h
@@ -0,0 +1,43 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_DETAILED_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_DETAILED_VIEW_H_ + +#include "ash/common/system/tray/tray_details_view.h" +#include "chromeos/network/network_state_handler.h" + +namespace ash { +namespace tray { + +// Abstract base class for all NetworkDetailedView derived subclasses, +// which includes NetworkWifiDetailedView and NetworkStateListDetailedView. +class NetworkDetailedView : public TrayDetailsView { + public: + enum DetailedViewType { + LIST_VIEW, + STATE_LIST_VIEW, + WIFI_VIEW, + }; + + explicit NetworkDetailedView(SystemTrayItem* owner) + : TrayDetailsView(owner) {} + + virtual void Init() = 0; + + virtual DetailedViewType GetViewType() const = 0; + + // Called when the contents of the network list have changed or when any + // Manager properties (e.g. technology state) have changed. + // (Called only from TrayNetworkStateObserver). + virtual void Update() = 0; + + protected: + ~NetworkDetailedView() override {} +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_DETAILED_VIEW_H_
diff --git a/ash/common/system/chromeos/network/network_icon.cc b/ash/common/system/chromeos/network/network_icon.cc new file mode 100644 index 0000000..d4297bc --- /dev/null +++ b/ash/common/system/chromeos/network/network_icon.cc
@@ -0,0 +1,957 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_icon.h" + +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/macros.h" +#include "base/strings/utf_string_conversions.h" +#include "chromeos/network/device_state.h" +#include "chromeos/network/network_connection_handler.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/portal_detector/network_portal_detector.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size_conversions.h" +#include "ui/gfx/image/canvas_image_source.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/image/image_skia_source.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/skia_util.h" +#include "ui/gfx/vector_icon_types.h" + +using chromeos::DeviceState; +using chromeos::NetworkConnectionHandler; +using chromeos::NetworkHandler; +using chromeos::NetworkPortalDetector; +using chromeos::NetworkState; +using chromeos::NetworkStateHandler; +using chromeos::NetworkTypePattern; + +namespace ash { +namespace network_icon { + +namespace { + +// Constants for offseting the badge displayed on top of the signal strength +// icon. The badge will extend outside of the base icon bounds by these amounts. +// All values are in dp. + +// The badge offsets are different depending on whether the icon is in the tray +// or menu. +const int kTrayIconBadgeOffset = 3; +const int kMenuIconBadgeOffset = 2; + +//------------------------------------------------------------------------------ +// Struct to pass icon badges to NetworkIconImageSource. +struct Badges { + gfx::ImageSkia top_left; + gfx::ImageSkia top_right; + gfx::ImageSkia bottom_left; + gfx::ImageSkia bottom_right; +}; + +//------------------------------------------------------------------------------ +// class used for maintaining a map of network state and images. +class NetworkIconImpl { + public: + NetworkIconImpl(const std::string& path, IconType icon_type); + + // Determines whether or not the associated network might be dirty and if so + // updates and generates the icon. Does nothing if network no longer exists. + void Update(const chromeos::NetworkState* network); + + const gfx::ImageSkia& image() const { return image_; } + + private: + // Updates |strength_index_| for wireless networks. Returns true if changed. + bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network); + + // Updates the local state for cellular networks. Returns true if changed. + bool UpdateCellularState(const chromeos::NetworkState* network); + + // Updates the portal state for wireless networks. Returns true if changed. + bool UpdatePortalState(const chromeos::NetworkState* network); + + // Updates the VPN badge. Returns true if changed. + bool UpdateVPNBadge(); + + // Gets |badges| based on |network| and the current state. + void GetBadges(const NetworkState* network, Badges* badges); + + // Gets the appropriate icon and badges and composites the image. + void GenerateImage(const chromeos::NetworkState* network); + + // Network path, used for debugging. + std::string network_path_; + + // Defines color theme and VPN badging + const IconType icon_type_; + + // Cached state of the network when the icon was last generated. + std::string state_; + + // Cached strength index of the network when the icon was last generated. + int strength_index_; + + // Cached technology badge for the network when the icon was last generated. + gfx::ImageSkia technology_badge_; + + // Cached vpn badge for the network when the icon was last generated. + gfx::ImageSkia vpn_badge_; + + // Cached roaming state of the network when the icon was last generated. + std::string roaming_state_; + + // Cached portal state of the network when the icon was last generated. + bool behind_captive_portal_; + + // Generated icon image. + gfx::ImageSkia image_; + + DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl); +}; + +//------------------------------------------------------------------------------ +// Maintain a static (global) icon map. Note: Icons are never destroyed; +// it is assumed that a finite and reasonable number of network icons will be +// created during a session. + +typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap; + +NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) { + typedef std::map<IconType, NetworkIconMap*> IconTypeMap; + static IconTypeMap* s_icon_map = nullptr; + if (s_icon_map == nullptr) { + if (!create) + return nullptr; + s_icon_map = new IconTypeMap; + } + if (s_icon_map->count(icon_type) == 0) { + if (!create) + return nullptr; + (*s_icon_map)[icon_type] = new NetworkIconMap; + } + return (*s_icon_map)[icon_type]; +} + +NetworkIconMap* GetIconMap(IconType icon_type) { + return GetIconMapInstance(icon_type, true); +} + +void PurgeIconMap(IconType icon_type, + const std::set<std::string>& network_paths) { + NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false); + if (!icon_map) + return; + for (NetworkIconMap::iterator loop_iter = icon_map->begin(); + loop_iter != icon_map->end();) { + NetworkIconMap::iterator cur_iter = loop_iter++; + if (network_paths.count(cur_iter->first) == 0) { + delete cur_iter->second; + icon_map->erase(cur_iter); + } + } +} + +//------------------------------------------------------------------------------ +// Utilities for generating icon images. + +// 'NONE' will default to ARCS behavior where appropriate (e.g. no network or +// if a new type gets added). +enum ImageType { ARCS, BARS, NONE }; + +// Amount to fade icons while connecting. +const double kConnectingImageAlpha = 0.5; + +// Images for strength arcs for wireless networks or strength bars for cellular +// networks. +const int kNumNetworkImages = 5; + +// Number of discrete images to use for alpha fade animation +const int kNumFadeImages = 10; + +SkColor GetDefaultColorForIconType(IconType icon_type) { + return icon_type == ICON_TYPE_TRAY ? kTrayIconColor : kMenuIconColor; +} + +bool IconTypeIsDark(IconType icon_type) { + return (icon_type != ICON_TYPE_TRAY); +} + +bool IconTypeHasVPNBadge(IconType icon_type) { + return (icon_type != ICON_TYPE_LIST && icon_type != ICON_TYPE_MENU_LIST); +} + +// This defines how we assemble a network icon. +class NetworkIconImageSource : public gfx::CanvasImageSource { + public: + static gfx::ImageSkia CreateImage(const gfx::ImageSkia& icon, + const Badges& badges) { + auto* source = new NetworkIconImageSource(icon, badges); + return gfx::ImageSkia(source, source->size()); + } + + // gfx::CanvasImageSource: + void Draw(gfx::Canvas* canvas) override { + const int width = size().width(); + const int height = size().height(); + + // The base icon is centered in both dimensions. + const int icon_y = (height - icon_.height()) / 2; + canvas->DrawImageInt(icon_, (width - icon_.width()) / 2, icon_y); + + // The badges are flush against the edges of the canvas, except at the top, + // where the badge is only 1dp higher than the base image. + const int top_badge_y = icon_y - 1; + if (!badges_.top_left.isNull()) + canvas->DrawImageInt(badges_.top_left, 0, top_badge_y); + if (!badges_.top_right.isNull()) { + canvas->DrawImageInt(badges_.top_right, width - badges_.top_right.width(), + top_badge_y); + } + if (!badges_.bottom_left.isNull()) { + canvas->DrawImageInt(badges_.bottom_left, 0, + height - badges_.bottom_left.height()); + } + if (!badges_.bottom_right.isNull()) { + canvas->DrawImageInt(badges_.bottom_right, + width - badges_.bottom_right.width(), + height - badges_.bottom_right.height()); + } + } + + bool HasRepresentationAtAllScales() const override { return true; } + + private: + NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges) + : CanvasImageSource(GetSizeForBaseIconSize(icon.size()), false), + icon_(icon), + badges_(badges) {} + ~NetworkIconImageSource() override {} + + static gfx::Size GetSizeForBaseIconSize(const gfx::Size& base_icon_size) { + gfx::Size size = base_icon_size; + const int badge_offset = base_icon_size.width() == kTrayIconSize + ? kTrayIconBadgeOffset + : kMenuIconBadgeOffset; + size.Enlarge(badge_offset * 2, badge_offset * 2); + return size; + } + + const gfx::ImageSkia icon_; + const Badges badges_; + + DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource); +}; + +// Depicts a given signal strength using arcs (e.g. for WiFi connections) or +// bars (e.g. for cell connections). +class SignalStrengthImageSource : public gfx::CanvasImageSource { + public: + SignalStrengthImageSource(ImageType image_type, + IconType icon_type, + int signal_strength) + : CanvasImageSource(GetSizeForIconType(icon_type), false), + image_type_(image_type), + icon_type_(icon_type), + color_(GetDefaultColorForIconType(icon_type_)), + signal_strength_(signal_strength) { + if (image_type_ == NONE) + image_type_ = ARCS; + + DCHECK_GE(signal_strength, 0); + DCHECK_LT(signal_strength, kNumNetworkImages); + } + ~SignalStrengthImageSource() override {} + + void set_color(SkColor color) { color_ = color; } + + // gfx::CanvasImageSource: + void Draw(gfx::Canvas* canvas) override { + if (image_type_ == ARCS) + DrawArcs(canvas); + else + DrawBars(canvas); + } + + bool HasRepresentationAtAllScales() const override { return true; } + + private: + static gfx::Size GetSizeForIconType(IconType icon_type) { + int side = icon_type == ICON_TYPE_TRAY ? kTrayIconSize : kMenuIconSize; + return gfx::Size(side, side); + } + + void DrawArcs(gfx::Canvas* canvas) { + gfx::RectF oval_bounds((gfx::Rect(size()))); + oval_bounds.Inset(gfx::Insets(kIconInset)); + // Double the width and height. The new midpoint should be the former + // bottom center. + oval_bounds.Inset(-oval_bounds.width() / 2, 0, -oval_bounds.width() / 2, + -oval_bounds.height()); + + const SkScalar kAngleAboveHorizontal = 51.f; + const SkScalar kStartAngle = 180.f + kAngleAboveHorizontal; + const SkScalar kSweepAngle = 180.f - 2 * kAngleAboveHorizontal; + + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); + // Background. Skip drawing for full signal. + if (signal_strength_ != kNumNetworkImages - 1) { + flags.setColor(SkColorSetA(color_, kBgAlpha)); + canvas->sk_canvas()->drawArc(gfx::RectFToSkRect(oval_bounds), kStartAngle, + kSweepAngle, true, flags); + } + // Foreground (signal strength). + if (signal_strength_ != 0) { + flags.setColor(color_); + // Percent of the height of the background wedge that we draw the + // foreground wedge, indexed by signal strength. + static const float kWedgeHeightPercentages[] = {0.f, 0.375f, 0.5833f, + 0.75f, 1.f}; + const float wedge_percent = kWedgeHeightPercentages[signal_strength_]; + oval_bounds.Inset( + gfx::InsetsF((oval_bounds.height() / 2) * (1.f - wedge_percent))); + canvas->sk_canvas()->drawArc(gfx::RectFToSkRect(oval_bounds), kStartAngle, + kSweepAngle, true, flags); + } + } + + void DrawBars(gfx::Canvas* canvas) { + // Undo the canvas's device scaling and round values to the nearest whole + // number so we can draw on exact pixel boundaries. + const float dsf = canvas->UndoDeviceScaleFactor(); + auto scale = [dsf](SkScalar dimension) { + return std::round(dimension * dsf); + }; + + // Length of short side of an isosceles right triangle, in dip. + const SkScalar kFullTriangleSide = + SkIntToScalar(size().width()) - kIconInset * 2; + + auto make_triangle = [scale, kFullTriangleSide](SkScalar side) { + SkPath triangle; + triangle.moveTo(scale(kIconInset), scale(kIconInset + kFullTriangleSide)); + triangle.rLineTo(scale(side), 0); + triangle.rLineTo(0, -scale(side)); + triangle.close(); + return triangle; + }; + + cc::PaintFlags flags; + flags.setAntiAlias(true); + flags.setStyle(cc::PaintFlags::kFill_Style); + // Background. Skip drawing for full signal. + if (signal_strength_ != kNumNetworkImages - 1) { + flags.setColor(SkColorSetA(color_, kBgAlpha)); + canvas->DrawPath(make_triangle(kFullTriangleSide), flags); + } + // Foreground (signal strength). + if (signal_strength_ != 0) { + flags.setColor(color_); + // As a percentage of the bg triangle, the length of one of the short + // sides of the fg triangle, indexed by signal strength. + static const float kTriangleSidePercents[] = {0.f, 0.5f, 0.625f, 0.75f, + 1.f}; + canvas->DrawPath(make_triangle(kTriangleSidePercents[signal_strength_] * + kFullTriangleSide), + flags); + } + } + + ImageType image_type_; + IconType icon_type_; + SkColor color_; + + // On a scale of 0 to kNum{Arcs,Bars}Images - 1, how connected we are. + int signal_strength_; + + // Padding between outside of icon and edge of the canvas, in dp. This value + // stays the same regardless of the canvas size (which depends on + // |icon_type_|). + static constexpr int kIconInset = 2; + + // TODO(estade): share this alpha with other things in ash (battery, etc.). + // See crbug.com/623987 and crbug.com/632827 + static constexpr int kBgAlpha = 0x4D; + + DISALLOW_COPY_AND_ASSIGN(SignalStrengthImageSource); +}; + +//------------------------------------------------------------------------------ +// Utilities for extracting icon images. + +ImageType ImageTypeForNetworkType(const std::string& type) { + if (type == shill::kTypeWifi) + return ARCS; + else if (type == shill::kTypeCellular || type == shill::kTypeWimax) + return BARS; + return NONE; +} + +gfx::ImageSkia GetImageForIndex(ImageType image_type, + IconType icon_type, + int index) { + gfx::CanvasImageSource* source = + new SignalStrengthImageSource(image_type, icon_type, index); + return gfx::ImageSkia(source, source->size()); +} + +const gfx::ImageSkia GetDisconnectedImage(IconType icon_type, + const std::string& network_type) { + DCHECK_NE(shill::kTypeVPN, network_type); + ImageType image_type = ImageTypeForNetworkType(network_type); + const int disconnected_index = 0; + return GetImageForIndex(image_type, icon_type, disconnected_index); +} + +gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type, + IconType icon_type, + double animation) { + static const int kImageCount = kNumNetworkImages - 1; + static gfx::ImageSkia* s_bars_images_dark[kImageCount]; + static gfx::ImageSkia* s_bars_images_light[kImageCount]; + static gfx::ImageSkia* s_arcs_images_dark[kImageCount]; + static gfx::ImageSkia* s_arcs_images_light[kImageCount]; + int index = animation * nextafter(static_cast<float>(kImageCount), 0); + index = std::max(std::min(index, kImageCount - 1), 0); + gfx::ImageSkia** images; + bool dark = IconTypeIsDark(icon_type); + if (image_type == BARS) + images = dark ? s_bars_images_dark : s_bars_images_light; + else + images = dark ? s_arcs_images_dark : s_arcs_images_light; + if (!images[index]) { + // Lazily cache images. + // TODO(estade): should the alpha be applied in SignalStrengthImageSource? + gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1); + images[index] = + new gfx::ImageSkia(gfx::ImageSkiaOperations::CreateTransparentImage( + source, kConnectingImageAlpha)); + } + return images[index]; +} + +gfx::ImageSkia ConnectingVpnImage(double animation) { + int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); + static gfx::ImageSkia* s_vpn_images[kNumFadeImages]; + if (!s_vpn_images[index]) { + // Lazily cache images. + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + // TODO(estade): update this icon to MD. See crbug.com/690176 + gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); + s_vpn_images[index] = new gfx::ImageSkia( + gfx::ImageSkiaOperations::CreateTransparentImage(*icon, animation)); + } + return *s_vpn_images[index]; +} + +gfx::ImageSkia ConnectingVpnBadge(double animation, IconType icon_type) { + int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); + static gfx::ImageSkia* s_vpn_badges[kNumFadeImages]; + if (!s_vpn_badges[index]) { + // Lazily cache images. + gfx::ImageSkia badge = gfx::CreateVectorIcon( + kNetworkBadgeVpnIcon, GetDefaultColorForIconType(icon_type)); + s_vpn_badges[index] = new gfx::ImageSkia( + gfx::ImageSkiaOperations::CreateTransparentImage(badge, animation)); + } + return *s_vpn_badges[index]; +} + +int StrengthIndex(int strength) { + // Return an index in the range [1, kNumNetworkImages - 1]. + const float findex = (static_cast<float>(strength) / 100.0f) * + nextafter(static_cast<float>(kNumNetworkImages - 1), 0); + int index = 1 + static_cast<int>(findex); + index = std::max(std::min(index, kNumNetworkImages - 1), 1); + return index; +} + +gfx::ImageSkia BadgeForNetworkTechnology(const NetworkState* network, + IconType icon_type) { + const std::string& technology = network->network_technology(); + const gfx::VectorIcon* icon = &gfx::kNoneIcon; + if (technology == shill::kNetworkTechnologyEvdo) { + icon = &kNetworkBadgeTechnologyEvdoIcon; + } else if (technology == shill::kNetworkTechnology1Xrtt) { + icon = &kNetworkBadgeTechnology1xIcon; + } else if (technology == shill::kNetworkTechnologyGprs || + technology == shill::kNetworkTechnologyGsm) { + icon = &kNetworkBadgeTechnologyGprsIcon; + } else if (technology == shill::kNetworkTechnologyEdge) { + icon = &kNetworkBadgeTechnologyEdgeIcon; + } else if (technology == shill::kNetworkTechnologyUmts) { + icon = &kNetworkBadgeTechnology3gIcon; + } else if (technology == shill::kNetworkTechnologyHspa) { + icon = &kNetworkBadgeTechnologyHspaIcon; + } else if (technology == shill::kNetworkTechnologyHspaPlus) { + icon = &kNetworkBadgeTechnologyHspaPlusIcon; + } else if (technology == shill::kNetworkTechnologyLte) { + icon = &kNetworkBadgeTechnologyLteIcon; + } else if (technology == shill::kNetworkTechnologyLteAdvanced) { + icon = &kNetworkBadgeTechnologyLteAdvancedIcon; + } else { + return gfx::ImageSkia(); + } + return gfx::CreateVectorIcon(*icon, GetDefaultColorForIconType(icon_type)); +} + +gfx::ImageSkia GetIcon(const NetworkState* network, + IconType icon_type, + int strength_index) { + if (network->Matches(NetworkTypePattern::Ethernet())) { + DCHECK_NE(ICON_TYPE_TRAY, icon_type); + return gfx::CreateVectorIcon(kNetworkEthernetIcon, + GetDefaultColorForIconType(ICON_TYPE_LIST)); + } else if (network->Matches(NetworkTypePattern::Wireless())) { + DCHECK(strength_index > 0); + return GetImageForIndex(ImageTypeForNetworkType(network->type()), icon_type, + strength_index); + } else if (network->Matches(NetworkTypePattern::VPN())) { + DCHECK_NE(ICON_TYPE_TRAY, icon_type); + return gfx::CreateVectorIcon(kNetworkVpnIcon, + GetDefaultColorForIconType(ICON_TYPE_LIST)); + } + + NOTREACHED() << "Request for icon for unsupported type: " << network->type(); + return gfx::ImageSkia(); +} + +//------------------------------------------------------------------------------ +// Get connecting images + +gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) { + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + const NetworkState* connected_network = nullptr; + if (icon_type == ICON_TYPE_TRAY) { + connected_network = + handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); + } + double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); + + gfx::ImageSkia icon; + Badges badges; + if (connected_network) { + icon = GetImageForNetwork(connected_network, icon_type); + badges.bottom_left = ConnectingVpnBadge(animation, icon_type); + } else { + icon = ConnectingVpnImage(animation); + } + return NetworkIconImageSource::CreateImage(icon, badges); +} + +gfx::ImageSkia GetConnectingImage(IconType icon_type, + const std::string& network_type) { + if (network_type == shill::kTypeVPN) + return GetConnectingVpnImage(icon_type); + + ImageType image_type = ImageTypeForNetworkType(network_type); + double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); + + return NetworkIconImageSource::CreateImage( + *ConnectingWirelessImage(image_type, icon_type, animation), Badges()); +} + +} // namespace + +//------------------------------------------------------------------------------ +// NetworkIconImpl + +NetworkIconImpl::NetworkIconImpl(const std::string& path, IconType icon_type) + : network_path_(path), + icon_type_(icon_type), + strength_index_(-1), + behind_captive_portal_(false) { + // Default image + image_ = GetDisconnectedImage(icon_type, shill::kTypeWifi); +} + +void NetworkIconImpl::Update(const NetworkState* network) { + DCHECK(network); + // Determine whether or not we need to update the icon. + bool dirty = image_.isNull(); + + // If the network state has changed, the icon needs updating. + if (state_ != network->connection_state()) { + state_ = network->connection_state(); + dirty = true; + } + + dirty |= UpdatePortalState(network); + + if (network->Matches(NetworkTypePattern::Wireless())) { + dirty |= UpdateWirelessStrengthIndex(network); + } + + if (network->Matches(NetworkTypePattern::Cellular())) + dirty |= UpdateCellularState(network); + + if (IconTypeHasVPNBadge(icon_type_) && + network->Matches(NetworkTypePattern::NonVirtual())) { + dirty |= UpdateVPNBadge(); + } + + if (dirty) { + // Set the icon and badges based on the network and generate the image. + GenerateImage(network); + } +} + +bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) { + int index = StrengthIndex(network->signal_strength()); + if (index != strength_index_) { + strength_index_ = index; + return true; + } + return false; +} + +bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) { + bool dirty = false; + const gfx::ImageSkia technology_badge = + BadgeForNetworkTechnology(network, icon_type_); + if (!technology_badge.BackedBySameObjectAs(technology_badge_)) { + technology_badge_ = technology_badge; + dirty = true; + } + std::string roaming_state = network->roaming(); + if (roaming_state != roaming_state_) { + roaming_state_ = roaming_state; + dirty = true; + } + return dirty; +} + +bool NetworkIconImpl::UpdatePortalState(const NetworkState* network) { + bool behind_captive_portal = false; + if (network && chromeos::network_portal_detector::IsInitialized()) { + NetworkPortalDetector::CaptivePortalState state = + chromeos::network_portal_detector::GetInstance()->GetCaptivePortalState( + network->guid()); + behind_captive_portal = + state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; + } + + if (behind_captive_portal == behind_captive_portal_) + return false; + behind_captive_portal_ = behind_captive_portal; + return true; +} + +bool NetworkIconImpl::UpdateVPNBadge() { + const NetworkState* vpn = + NetworkHandler::Get()->network_state_handler()->ConnectedNetworkByType( + NetworkTypePattern::VPN()); + if (vpn && vpn_badge_.isNull()) { + vpn_badge_ = gfx::CreateVectorIcon(kNetworkBadgeVpnIcon, + GetDefaultColorForIconType(icon_type_)); + return true; + } + if (!vpn && !vpn_badge_.isNull()) { + vpn_badge_ = gfx::ImageSkia(); + return true; + } + return false; +} + +void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) { + DCHECK(network); + + const std::string& type = network->type(); + const SkColor icon_color = GetDefaultColorForIconType(icon_type_); + if (type == shill::kTypeWifi) { + if (network->security_class() != shill::kSecurityNone && + IconTypeIsDark(icon_type_)) { + badges->bottom_right = + gfx::CreateVectorIcon(kNetworkBadgeSecureIcon, icon_color); + } + } else if (type == shill::kTypeWimax) { + technology_badge_ = + gfx::CreateVectorIcon(kNetworkBadgeTechnology4gIcon, icon_color); + } else if (type == shill::kTypeCellular) { + if (network->roaming() == shill::kRoamingStateRoaming) { + // For networks that are always in roaming don't show roaming badge. + const DeviceState* device = + NetworkHandler::Get()->network_state_handler()->GetDeviceState( + network->device_path()); + LOG_IF(WARNING, !device) << "Could not find device state for " + << network->device_path(); + if (!device || !device->provider_requires_roaming()) { + badges->bottom_right = + gfx::CreateVectorIcon(kNetworkBadgeRoamingIcon, icon_color); + } + } + } + if (!network->IsConnectingState()) { + badges->top_left = technology_badge_; + badges->bottom_left = vpn_badge_; + } + + if (behind_captive_portal_) { + badges->bottom_right = + gfx::CreateVectorIcon(kNetworkBadgeCaptivePortalIcon, icon_color); + } +} + +void NetworkIconImpl::GenerateImage(const NetworkState* network) { + DCHECK(network); + gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_); + Badges badges; + GetBadges(network, &badges); + image_ = NetworkIconImageSource::CreateImage(icon, badges); +} + +namespace { + +NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network, + IconType icon_type) { + // Find or add the icon. + NetworkIconMap* icon_map = GetIconMap(icon_type); + NetworkIconImpl* icon; + NetworkIconMap::iterator iter = icon_map->find(network->path()); + if (iter == icon_map->end()) { + icon = new NetworkIconImpl(network->path(), icon_type); + icon_map->insert(std::make_pair(network->path(), icon)); + } else { + icon = iter->second; + } + + // Update and return the icon's image. + icon->Update(network); + return icon; +} + +} // namespace + +//------------------------------------------------------------------------------ +// Public interface + +gfx::ImageSkia GetImageForNetwork(const NetworkState* network, + IconType icon_type) { + DCHECK(network); + if (!network->visible()) + return GetDisconnectedImage(icon_type, network->type()); + + if (network->IsConnectingState()) + return GetConnectingImage(icon_type, network->type()); + + NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type); + return icon->image(); +} + +gfx::ImageSkia GetImageForConnectedMobileNetwork() { + ImageType image_type = ImageTypeForNetworkType(shill::kTypeWifi); + const IconType icon_type = ICON_TYPE_LIST; + const int connected_index = kNumNetworkImages - 1; + return GetImageForIndex(image_type, icon_type, connected_index); +} + +gfx::ImageSkia GetImageForDisconnectedCellNetwork() { + return GetDisconnectedImage(ICON_TYPE_LIST, shill::kTypeCellular); +} + +gfx::ImageSkia GetImageForNewWifiNetwork(SkColor icon_color, + SkColor badge_color) { + SignalStrengthImageSource* source = + new SignalStrengthImageSource(ImageTypeForNetworkType(shill::kTypeWifi), + ICON_TYPE_LIST, kNumNetworkImages - 1); + source->set_color(icon_color); + gfx::ImageSkia icon = gfx::ImageSkia(source, source->size()); + Badges badges; + badges.bottom_right = + gfx::CreateVectorIcon(kNetworkBadgeAddOtherIcon, badge_color); + return NetworkIconImageSource::CreateImage(icon, badges); +} + +base::string16 GetLabelForNetwork(const chromeos::NetworkState* network, + IconType icon_type) { + DCHECK(network); + std::string activation_state = network->activation_state(); + if (icon_type == ICON_TYPE_LIST || icon_type == ICON_TYPE_MENU_LIST) { + // Show "<network>: [Connecting|Activating|Reconnecting]..." + // TODO(varkha): Remaining states should migrate to secondary status in the + // network item and no longer be part of the label. + // See http://crbug.com/676181 . + if (network->IsReconnecting()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_RECONNECTING, + base::UTF8ToUTF16(network->name())); + } + if (icon_type != ICON_TYPE_MENU_LIST && network->IsConnectingState()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING, + base::UTF8ToUTF16(network->name())); + } + if (activation_state == shill::kActivationStateActivating) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING, + base::UTF8ToUTF16(network->name())); + } + // Show "Activate <network>" in list view only. + if (activation_state == shill::kActivationStateNotActivated || + activation_state == shill::kActivationStatePartiallyActivated) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE, + base::UTF8ToUTF16(network->name())); + } + } else { + // Show "[Connected to|Connecting to|Activating|Reconnecting to] <network>" + // (non-list view). + if (network->IsReconnecting()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_RECONNECTING, + base::UTF8ToUTF16(network->name())); + } + if (network->IsConnectedState()) { + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, + base::UTF8ToUTF16(network->name())); + } + if (network->IsConnectingState()) { + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, + base::UTF8ToUTF16(network->name())); + } + if (activation_state == shill::kActivationStateActivating) { + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, + base::UTF8ToUTF16(network->name())); + } + } + + // Otherwise just show the network name or 'Ethernet'. + if (network->Matches(NetworkTypePattern::Ethernet())) { + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET); + } else { + return base::UTF8ToUTF16(network->name()); + } +} + +int GetCellularUninitializedMsg() { + static base::Time s_uninitialized_state_time; + static int s_uninitialized_msg(0); + + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + if (handler->GetTechnologyState(NetworkTypePattern::Mobile()) == + NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) { + s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR; + s_uninitialized_state_time = base::Time::Now(); + return s_uninitialized_msg; + } else if (handler->GetScanningByType(NetworkTypePattern::Mobile())) { + s_uninitialized_msg = IDS_ASH_STATUS_TRAY_MOBILE_SCANNING; + s_uninitialized_state_time = base::Time::Now(); + return s_uninitialized_msg; + } + // There can be a delay between leaving the Initializing state and when + // a Cellular device shows up, so keep showing the initializing + // animation for a bit to avoid flashing the disconnect icon. + const int kInitializingDelaySeconds = 1; + base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time; + if (dtime.InSeconds() < kInitializingDelaySeconds) + return s_uninitialized_msg; + return 0; +} + +void GetDefaultNetworkImageAndLabel(IconType icon_type, + gfx::ImageSkia* image, + base::string16* label, + bool* animating) { + NetworkStateHandler* state_handler = + NetworkHandler::Get()->network_state_handler(); + NetworkConnectionHandler* connect_handler = + NetworkHandler::Get()->network_connection_handler(); + const NetworkState* connected_network = + state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); + const NetworkState* connecting_network = + state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless()); + if (!connecting_network && icon_type == ICON_TYPE_TRAY) { + connecting_network = + state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN()); + } + + const NetworkState* network; + // If we are connecting to a network, and there is either no connected + // network, or the connection was user requested, or shill triggered a + // reconnection, use the connecting network. + if (connecting_network && + (!connected_network || connecting_network->IsReconnecting() || + connect_handler->HasConnectingNetwork(connecting_network->path()))) { + network = connecting_network; + } else { + network = connected_network; + } + + // Don't show ethernet in the tray + if (icon_type == ICON_TYPE_TRAY && network && + network->Matches(NetworkTypePattern::Ethernet())) { + *image = gfx::ImageSkia(); + *animating = false; + return; + } + + if (!network) { + // If no connecting network, check if we are activating a network. + const NetworkState* mobile_network = + state_handler->FirstNetworkByType(NetworkTypePattern::Mobile()); + if (mobile_network && (mobile_network->activation_state() == + shill::kActivationStateActivating)) { + network = mobile_network; + } + } + if (!network) { + // If no connecting network, check for cellular initializing. + int uninitialized_msg = GetCellularUninitializedMsg(); + if (uninitialized_msg != 0) { + *image = GetConnectingImage(icon_type, shill::kTypeCellular); + if (label) + *label = l10n_util::GetStringUTF16(uninitialized_msg); + *animating = true; + } else { + // Otherwise show the disconnected wifi icon. + *image = GetDisconnectedImage(icon_type, shill::kTypeWifi); + if (label) { + *label = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED); + } + *animating = false; + } + return; + } + *animating = network->IsConnectingState(); + // Get icon and label for connected or connecting network. + *image = GetImageForNetwork(network, icon_type); + if (label) + *label = GetLabelForNetwork(network, icon_type); +} + +void PurgeNetworkIconCache() { + NetworkStateHandler::NetworkStateList networks; + NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList( + &networks); + std::set<std::string> network_paths; + for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin(); + iter != networks.end(); ++iter) { + network_paths.insert((*iter)->path()); + } + PurgeIconMap(ICON_TYPE_TRAY, network_paths); + PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths); + PurgeIconMap(ICON_TYPE_LIST, network_paths); + PurgeIconMap(ICON_TYPE_MENU_LIST, network_paths); +} + +} // namespace network_icon +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_icon.h b/ash/common/system/chromeos/network/network_icon.h new file mode 100644 index 0000000..b5824a0 --- /dev/null +++ b/ash/common/system/chromeos/network/network_icon.h
@@ -0,0 +1,74 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "base/strings/string16.h" +#include "ui/gfx/image/image_skia.h" + +namespace chromeos { +class NetworkState; +} + +namespace ash { +namespace network_icon { + +// Type of icon which dictates color theme and VPN badging +enum IconType { + ICON_TYPE_TRAY, // light icons with VPN badges + ICON_TYPE_DEFAULT_VIEW, // dark icons with VPN badges + ICON_TYPE_LIST, // dark icons without VPN badges; in-line status + ICON_TYPE_MENU_LIST, // dark icons without VPN badges; separate status +}; + +// Gets the image for provided |network|. |network| must not be NULL. +// |icon_type| determines the color theme and whether or not to show the VPN +// badge. This caches badged icons per network per |icon_type|. +ASH_EXPORT gfx::ImageSkia GetImageForNetwork( + const chromeos::NetworkState* network, + IconType icon_type); + +// Gets the full strength image for a Wi-Fi network. +// TODO(estade): Expose SignalStrengthImageSource and use that instead. +ASH_EXPORT gfx::ImageSkia GetImageForConnectedMobileNetwork(); + +// Gets the disconnected image for a cell network. +// TODO(estade): Expose SignalStrengthImageSource and use that instead. +ASH_EXPORT gfx::ImageSkia GetImageForDisconnectedCellNetwork(); + +// Gets the full strength image for a Wi-Fi network using |icon_color| for the +// main icon and |badge_color| for the badge. +ASH_EXPORT gfx::ImageSkia GetImageForNewWifiNetwork(SkColor icon_color, + SkColor badge_color); + +// Returns the label for |network| based on |icon_type|. |network| cannot be +// nullptr. +ASH_EXPORT base::string16 GetLabelForNetwork( + const chromeos::NetworkState* network, + IconType icon_type); + +// Updates and returns the appropriate message id if the cellular network +// is uninitialized. +ASH_EXPORT int GetCellularUninitializedMsg(); + +// Gets the correct icon and label for |icon_type|. Also sets |animating| +// based on whether or not the icon is animating (i.e. connecting). +ASH_EXPORT void GetDefaultNetworkImageAndLabel(IconType icon_type, + gfx::ImageSkia* image, + base::string16* label, + bool* animating); + +// Called when the list of networks changes. Retreives the list of networks +// from the global NetworkStateHandler instance and removes cached entries +// that are no longer in the list. +ASH_EXPORT void PurgeNetworkIconCache(); + +} // namespace network_icon +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_H_
diff --git a/ash/common/system/chromeos/network/network_icon_animation.cc b/ash/common/system/chromeos/network/network_icon_animation.cc new file mode 100644 index 0000000..26e6751 --- /dev/null +++ b/ash/common/system/chromeos/network/network_icon_animation.cc
@@ -0,0 +1,59 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_icon_animation.h" + +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" + +namespace { +const int kThrobDurationMs = 750; // Animation cycle length. +} + +namespace ash { +namespace network_icon { + +NetworkIconAnimation::NetworkIconAnimation() : animation_(this) { + // Set up the animation throbber. + animation_.SetThrobDuration(kThrobDurationMs); + animation_.SetTweenType(gfx::Tween::LINEAR); +} + +NetworkIconAnimation::~NetworkIconAnimation() {} + +void NetworkIconAnimation::AnimationProgressed( + const gfx::Animation* animation) { + if (animation != &animation_) + return; + for (AnimationObserver& observer : observers_) + observer.NetworkIconChanged(); +} + +double NetworkIconAnimation::GetAnimation() { + if (!animation_.is_animating()) { + animation_.Reset(); + animation_.StartThrobbing(-1 /*throb indefinitely*/); + return 0; + } + return animation_.GetCurrentValue(); +} + +void NetworkIconAnimation::AddObserver(AnimationObserver* observer) { + if (!observers_.HasObserver(observer)) + observers_.AddObserver(observer); +} + +void NetworkIconAnimation::RemoveObserver(AnimationObserver* observer) { + observers_.RemoveObserver(observer); + if (!observers_.might_have_observers()) + animation_.Reset(); // Stops the animation and resets the current value. +} + +// static +NetworkIconAnimation* NetworkIconAnimation::GetInstance() { + static NetworkIconAnimation* s_icon_animation = new NetworkIconAnimation(); + return s_icon_animation; +} + +} // namespace network_icon +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_icon_animation.h b/ash/common/system/chromeos/network/network_icon_animation.h new file mode 100644 index 0000000..0f28eb4 --- /dev/null +++ b/ash/common/system/chromeos/network/network_icon_animation.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_ANIMATION_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_ANIMATION_H_ + +#include <set> +#include <string> + +#include "ash/ash_export.h" +#include "base/observer_list.h" +#include "ui/gfx/animation/animation_delegate.h" +#include "ui/gfx/animation/throb_animation.h" + +namespace ash { +namespace network_icon { + +class AnimationObserver; + +// Single instance class to handle icon animations and keep them in sync. +class ASH_EXPORT NetworkIconAnimation : public gfx::AnimationDelegate { + public: + NetworkIconAnimation(); + ~NetworkIconAnimation() override; + + // Returns the current animation value, [0-1]. + double GetAnimation(); + + // The animation stops when all observers have been removed. + // Be sure to remove observers when no associated icons are animating. + void AddObserver(AnimationObserver* observer); + void RemoveObserver(AnimationObserver* observer); + + // gfx::AnimationDelegate implementation. + void AnimationProgressed(const gfx::Animation* animation) override; + + static NetworkIconAnimation* GetInstance(); + + private: + gfx::ThrobAnimation animation_; + base::ObserverList<AnimationObserver> observers_; +}; + +} // namespace network_icon +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_ANIMATION_H_
diff --git a/ash/common/system/chromeos/network/network_icon_animation_observer.h b/ash/common/system/chromeos/network/network_icon_animation_observer.h new file mode 100644 index 0000000..83729a3 --- /dev/null +++ b/ash/common/system/chromeos/network/network_icon_animation_observer.h
@@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_ANIMATION_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_ANIMATION_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { +namespace network_icon { + +// Observer interface class for animating network icons. +class ASH_EXPORT AnimationObserver { + public: + // Called when the image has changed due to animation. The callback should + // trigger a call to GetImageForNetwork() to retrieve the image. + virtual void NetworkIconChanged() = 0; + + protected: + virtual ~AnimationObserver() {} +}; + +} // namespace network_icon +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_ICON_ANIMATION_OBSERVER_H_
diff --git a/ash/common/system/chromeos/network/network_info.cc b/ash/common/system/chromeos/network/network_info.cc new file mode 100644 index 0000000..e58f5aa --- /dev/null +++ b/ash/common/system/chromeos/network/network_info.cc
@@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_info.h" + +namespace ash { + +NetworkInfo::NetworkInfo() + : disable(false), + highlight(false), + connected(false), + connecting(false), + type(Type::UNKNOWN) {} + +NetworkInfo::NetworkInfo(const std::string& guid) + : guid(guid), + disable(false), + highlight(false), + connected(false), + connecting(false), + type(Type::UNKNOWN) {} + +NetworkInfo::~NetworkInfo() {} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_info.h b/ash/common/system/chromeos/network/network_info.h new file mode 100644 index 0000000..c321a837 --- /dev/null +++ b/ash/common/system/chromeos/network/network_info.h
@@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_INFO_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_INFO_H_ + +#include <string> + +#include "base/strings/string16.h" +#include "ui/gfx/image/image_skia.h" + +namespace gfx { +class ImageSkia; +} + +namespace ash { + +// Includes information necessary about a network for displaying the appropriate +// UI to the user. +struct NetworkInfo { + enum class Type { UNKNOWN, WIFI, TETHER, CELLULAR }; + + NetworkInfo(); + NetworkInfo(const std::string& guid); + ~NetworkInfo(); + + std::string guid; + base::string16 label; + base::string16 tooltip; + gfx::ImageSkia image; + bool disable; + bool highlight; + bool connected; + bool connecting; + Type type; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_INFO_H_
diff --git a/ash/common/system/chromeos/network/network_list.cc b/ash/common/system/chromeos/network/network_list.cc new file mode 100644 index 0000000..d53e92d --- /dev/null +++ b/ash/common/system/chromeos/network/network_list.cc
@@ -0,0 +1,322 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_list.h" + +#include <stddef.h> + +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_info.h" +#include "ash/common/system/chromeos/network/network_list_delegate.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/ptr_util.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" +#include "chromeos/dbus/power_manager_client.h" +#include "chromeos/login/login_state.h" +#include "chromeos/network/managed_network_configuration_handler.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_state_handler_observer.h" +#include "components/device_event_log/device_event_log.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/font.h" +#include "ui/views/controls/label.h" +#include "ui/views/view.h" + +using chromeos::LoginState; +using chromeos::NetworkHandler; +using chromeos::NetworkStateHandler; +using chromeos::ManagedNetworkConfigurationHandler; +using chromeos::NetworkTypePattern; + +namespace ash { + +namespace { + +bool IsProhibitedByPolicy(const chromeos::NetworkState* network) { + if (!NetworkTypePattern::WiFi().MatchesType(network->type())) + return false; + if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn()) + return false; + ManagedNetworkConfigurationHandler* managed_configuration_handler = + NetworkHandler::Get()->managed_network_configuration_handler(); + const base::DictionaryValue* global_network_config = + managed_configuration_handler->GetGlobalConfigFromPolicy( + std::string() /* no username hash, device policy */); + bool policy_prohibites_unmanaged = false; + if (global_network_config) { + global_network_config->GetBooleanWithoutPathExpansion( + ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect, + &policy_prohibites_unmanaged); + } + if (!policy_prohibites_unmanaged) + return false; + return !managed_configuration_handler->FindPolicyByGuidAndProfile( + network->guid(), network->profile_path()); +} + +} // namespace + +// NetworkListView: + +NetworkListView::NetworkListView(NetworkListDelegate* delegate) + : delegate_(delegate), + no_wifi_networks_view_(nullptr), + no_cellular_networks_view_(nullptr) { + CHECK(delegate_); +} + +NetworkListView::~NetworkListView() { + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); +} + +void NetworkListView::Update() { + CHECK(container()); + NetworkStateHandler::NetworkStateList network_list; + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + handler->GetVisibleNetworkList(&network_list); + UpdateNetworks(network_list); + UpdateNetworkIcons(); + UpdateNetworkListInternal(); +} + +bool NetworkListView::IsNetworkEntry(views::View* view, + std::string* guid) const { + std::map<views::View*, std::string>::const_iterator found = + network_map_.find(view); + if (found == network_map_.end()) + return false; + *guid = found->second; + return true; +} + +void NetworkListView::UpdateNetworks( + const NetworkStateHandler::NetworkStateList& networks) { + SCOPED_NET_LOG_IF_SLOW(); + network_list_.clear(); + const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); + for (NetworkStateHandler::NetworkStateList::const_iterator iter = + networks.begin(); + iter != networks.end(); ++iter) { + const chromeos::NetworkState* network = *iter; + if (!pattern.MatchesType(network->type())) + continue; + network_list_.push_back(base::MakeUnique<NetworkInfo>(network->guid())); + } +} + +void NetworkListView::UpdateNetworkIcons() { + SCOPED_NET_LOG_IF_SLOW(); + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + // First, update state for all networks + bool animating = false; + + for (auto& info : network_list_) { + const chromeos::NetworkState* network = + handler->GetNetworkStateFromGuid(info->guid); + if (!network) + continue; + bool prohibited_by_policy = IsProhibitedByPolicy(network); + info->image = + network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); + info->label = + network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST); + info->highlight = + network->IsConnectedState() || network->IsConnectingState(); + info->disable = + (network->activation_state() == shill::kActivationStateActivating) || + prohibited_by_policy; + if (network->Matches(NetworkTypePattern::WiFi())) + info->type = NetworkInfo::Type::WIFI; + else if (network->Matches(NetworkTypePattern::Cellular())) + info->type = NetworkInfo::Type::CELLULAR; + if (prohibited_by_policy) { + info->tooltip = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED); + } + if (!animating && network->IsConnectingState()) + animating = true; + } + if (animating) + network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); + else + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); +} + +void NetworkListView::UpdateNetworkListInternal() { + SCOPED_NET_LOG_IF_SLOW(); + // Get the updated list entries + network_map_.clear(); + std::set<std::string> new_guids; + bool needs_relayout = UpdateNetworkListEntries(&new_guids); + + // Remove old children + std::set<std::string> remove_guids; + for (NetworkGuidMap::const_iterator it = network_guid_map_.begin(); + it != network_guid_map_.end(); ++it) { + if (new_guids.find(it->first) == new_guids.end()) { + remove_guids.insert(it->first); + network_map_.erase(it->second); + delete it->second; + needs_relayout = true; + } + } + + for (std::set<std::string>::const_iterator remove_it = remove_guids.begin(); + remove_it != remove_guids.end(); ++remove_it) { + network_guid_map_.erase(*remove_it); + } + + if (needs_relayout) + HandleRelayout(); +} + +void NetworkListView::HandleRelayout() { + views::View* selected_view = nullptr; + for (auto& iter : network_guid_map_) { + if (delegate_->IsViewHovered(iter.second)) { + selected_view = iter.second; + break; + } + } + container()->SizeToPreferredSize(); + delegate_->RelayoutScrollList(); + if (selected_view) + container()->ScrollRectToVisible(selected_view->bounds()); +} + +bool NetworkListView::UpdateNetworkListEntries( + std::set<std::string>* new_guids) { + bool needs_relayout = false; + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + // Insert child views + int index = 0; + + // Highlighted networks + needs_relayout |= + UpdateNetworkChildren(new_guids, &index, true /* highlighted */); + + const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); + if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) { + // Cellular initializing + int message_id = network_icon::GetCellularUninitializedMsg(); + if (!message_id && + handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) && + !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) { + message_id = IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS; + } + needs_relayout |= + UpdateInfoLabel(message_id, index, &no_cellular_networks_view_); + + if (message_id) + ++index; + } + + if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) { + // "Wifi Enabled / Disabled" + int message_id = 0; + if (network_list_.empty()) { + message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()) + ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED + : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; + } + needs_relayout |= + UpdateInfoLabel(message_id, index, &no_wifi_networks_view_); + if (message_id) + ++index; + } + + // Un-highlighted networks + needs_relayout |= + UpdateNetworkChildren(new_guids, &index, false /* not highlighted */); + + // No networks or other messages (fallback) + if (index == 0) { + needs_relayout |= UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, index, + &no_wifi_networks_view_); + } + + return needs_relayout; +} + +bool NetworkListView::UpdateNetworkChildren(std::set<std::string>* new_guids, + int* child_index, + bool highlighted) { + bool needs_relayout = false; + int index = *child_index; + for (auto& info : network_list_) { + if (info->highlight != highlighted) + continue; + needs_relayout |= UpdateNetworkChild(index++, info.get()); + new_guids->insert(info->guid); + } + *child_index = index; + return needs_relayout; +} + +bool NetworkListView::UpdateNetworkChild(int index, const NetworkInfo* info) { + bool needs_relayout = false; + views::View* network_view = nullptr; + NetworkGuidMap::const_iterator found = network_guid_map_.find(info->guid); + if (found == network_guid_map_.end()) { + network_view = delegate_->CreateViewForNetwork(*info); + container()->AddChildViewAt(network_view, index); + needs_relayout = true; + } else { + network_view = found->second; + network_view->RemoveAllChildViews(true); + delegate_->UpdateViewForNetwork(network_view, *info); + network_view->Layout(); + network_view->SchedulePaint(); + needs_relayout = PlaceViewAtIndex(network_view, index); + } + if (info->disable) + network_view->SetEnabled(false); + network_map_[network_view] = info->guid; + network_guid_map_[info->guid] = network_view; + return needs_relayout; +} + +bool NetworkListView::PlaceViewAtIndex(views::View* view, int index) { + if (container()->child_at(index) == view) + return false; + container()->ReorderChildView(view, index); + return true; +} + +bool NetworkListView::UpdateInfoLabel(int message_id, + int index, + views::Label** label) { + CHECK(label); + bool needs_relayout = false; + if (message_id) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + base::string16 text = rb.GetLocalizedString(message_id); + if (!*label) { + *label = delegate_->CreateInfoLabel(); + (*label)->SetText(text); + container()->AddChildViewAt(*label, index); + needs_relayout = true; + } else { + (*label)->SetText(text); + needs_relayout = PlaceViewAtIndex(*label, index); + } + } else if (*label) { + delete *label; + *label = nullptr; + needs_relayout = true; + } + return needs_relayout; +} + +void NetworkListView::NetworkIconChanged() { + Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_list.h b/ash/common/system/chromeos/network/network_list.h new file mode 100644 index 0000000..2e4090b --- /dev/null +++ b/ash/common/system/chromeos/network/network_list.h
@@ -0,0 +1,79 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_H_ + +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" +#include "ash/common/system/chromeos/network/network_list_view_base.h" +#include "base/macros.h" +#include "chromeos/network/network_state_handler.h" +#include "ui/gfx/image/image_skia.h" + +namespace views { +class Label; +class View; +} + +namespace ash { + +struct NetworkInfo; +class NetworkListDelegate; + +// A list of available networks of a given type. This class is used for all +// network types except VPNs. For VPNs, see the |VPNList| class. +class NetworkListView : public NetworkListViewBase, + public network_icon::AnimationObserver { + public: + explicit NetworkListView(NetworkListDelegate* delegate); + ~NetworkListView() override; + + // NetworkListViewBase: + void Update() override; + bool IsNetworkEntry(views::View* view, std::string* guid) const override; + + private: + void UpdateNetworks( + const chromeos::NetworkStateHandler::NetworkStateList& networks); + void UpdateNetworkIcons(); + void UpdateNetworkListInternal(); + void HandleRelayout(); + bool UpdateNetworkListEntries(std::set<std::string>* new_guids); + bool UpdateNetworkChildren(std::set<std::string>* new_guids, + int* child_index, + bool highlighted); + bool UpdateNetworkChild(int index, const NetworkInfo* info); + bool PlaceViewAtIndex(views::View* view, int index); + bool UpdateInfoLabel(int message_id, int index, views::Label** label); + + // network_icon::AnimationObserver: + void NetworkIconChanged() override; + + NetworkListDelegate* delegate_; + + views::Label* no_wifi_networks_view_; + views::Label* no_cellular_networks_view_; + + // An owned list of network info. + std::vector<std::unique_ptr<NetworkInfo>> network_list_; + + typedef std::map<views::View*, std::string> NetworkMap; + NetworkMap network_map_; + + // A map of network guids to their view. + typedef std::map<std::string, views::View*> NetworkGuidMap; + NetworkGuidMap network_guid_map_; + + DISALLOW_COPY_AND_ASSIGN(NetworkListView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_H_
diff --git a/ash/common/system/chromeos/network/network_list_delegate.h b/ash/common/system/chromeos/network/network_list_delegate.h new file mode 100644 index 0000000..aaf3c42 --- /dev/null +++ b/ash/common/system/chromeos/network/network_list_delegate.h
@@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_DELEGATE_H_ + +namespace chromeos { +class NetworkTypePattern; +} + +namespace views { +class Label; +class View; +} + +namespace ash { + +struct NetworkInfo; + +class NetworkListDelegate { + public: + virtual ~NetworkListDelegate() {} + + // Creates and returns a View with the information in |info|. + virtual views::View* CreateViewForNetwork(const NetworkInfo& info) = 0; + + // Returns true if |view| is currently under the cursor. Note that |view| is + // guaranteed to be a View returned from |CreateViewForNetwork()|. + virtual bool IsViewHovered(views::View* view) = 0; + + // Returns the type of network this list should use. + virtual chromeos::NetworkTypePattern GetNetworkTypePattern() const = 0; + + // Updates |view| with the information in |info|. Note that |view| is + // guaranteed to be a View returned from |CreateViewForNetwork()|. + virtual void UpdateViewForNetwork(views::View* view, + const NetworkInfo& info) = 0; + + // Creates a Label to be displayed in the list to present some information + // (e.g. unavailability of network etc.). + virtual views::Label* CreateInfoLabel() = 0; + + // Called when the user clicks on an entry representing a network in the list. + virtual void OnNetworkEntryClicked(views::View* sender) = 0; + + // Called when the user clicks on a "Join Other" button. + virtual void OnOtherWifiClicked() = 0; + + virtual void RelayoutScrollList() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_DELEGATE_H_
diff --git a/ash/common/system/chromeos/network/network_list_md.cc b/ash/common/system/chromeos/network/network_list_md.cc new file mode 100644 index 0000000..4fb4674 --- /dev/null +++ b/ash/common/system/chromeos/network/network_list_md.cc
@@ -0,0 +1,653 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_list_md.h" + +#include <stddef.h> + +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_list_delegate.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/ptr_util.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" +#include "chromeos/dbus/power_manager_client.h" +#include "chromeos/login/login_state.h" +#include "chromeos/network/managed_network_configuration_handler.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_state_handler_observer.h" +#include "components/device_event_log/device_event_log.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/font.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/views/controls/button/toggle_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" +#include "ui/views/view.h" + +using chromeos::LoginState; +using chromeos::NetworkHandler; +using chromeos::NetworkStateHandler; +using chromeos::ManagedNetworkConfigurationHandler; +using chromeos::NetworkTypePattern; + +namespace ash { + +namespace { + +bool IsProhibitedByPolicy(const chromeos::NetworkState* network) { + if (!NetworkTypePattern::WiFi().MatchesType(network->type())) + return false; + if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn()) + return false; + ManagedNetworkConfigurationHandler* managed_configuration_handler = + NetworkHandler::Get()->managed_network_configuration_handler(); + const base::DictionaryValue* global_network_config = + managed_configuration_handler->GetGlobalConfigFromPolicy( + std::string() /* no username hash, device policy */); + bool policy_prohibites_unmanaged = false; + if (global_network_config) { + global_network_config->GetBooleanWithoutPathExpansion( + ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect, + &policy_prohibites_unmanaged); + } + if (!policy_prohibites_unmanaged) + return false; + return !managed_configuration_handler->FindPolicyByGuidAndProfile( + network->guid(), network->profile_path()); +} + +} // namespace + +// A header row for sections in network detailed view which contains a title and +// a toggle button to turn on/off the section. Subclasses are given the +// opportunity to add extra buttons before the toggle button is added. +class NetworkListViewMd::SectionHeaderRowView : public views::View, + public views::ButtonListener { + public: + explicit SectionHeaderRowView(int title_id) + : title_id_(title_id), + container_(nullptr), + toggle_(nullptr), + style_( + new TrayPopupItemStyle(TrayPopupItemStyle::FontStyle::SUB_HEADER)) { + } + + ~SectionHeaderRowView() override {} + + void Init(bool enabled) { + InitializeLayout(); + AddExtraButtons(enabled); + AddToggleButton(enabled); + } + + virtual void SetEnabled(bool enabled) { toggle_->SetIsOn(enabled, true); } + + protected: + // This is called before the toggle button is added to give subclasses an + // opportunity to add more buttons before the toggle button. Subclasses can + // add buttons to container() using AddChildView(). + virtual void AddExtraButtons(bool enabled) {} + + // Called when |toggle_| is clicked and toggled. Subclasses can override to + // enabled/disable their respective technology, for example. + virtual void OnToggleToggled(bool is_on) = 0; + + TriView* container() const { return container_; } + TrayPopupItemStyle* style() const { return style_.get(); } + + int GetHeightForWidth(int w) const override { + // Make row height fixed avoiding layout manager adjustments. + return GetPreferredSize().height(); + } + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + DCHECK_EQ(toggle_, sender); + OnToggleToggled(toggle_->is_on()); + } + + private: + void InitializeLayout() { + // TODO(mohsen): Consider using TriView class and adding a utility function + // to TrayPopupUtils to simplify creation of the following layout. See + // https://crbug.com/614453. + TrayPopupUtils::ConfigureAsStickyHeader(this); + SetLayoutManager(new views::FillLayout); + container_ = TrayPopupUtils::CreateSubHeaderRowView(); + AddChildView(container_); + + views::Label* label = TrayPopupUtils::CreateDefaultLabel(); + style()->SetupLabel(label); + label->SetText(l10n_util::GetStringUTF16(title_id_)); + container_->AddView(TriView::Container::CENTER, label); + } + + void AddToggleButton(bool enabled) { + toggle_ = TrayPopupUtils::CreateToggleButton(this, title_id_); + toggle_->SetIsOn(enabled, false); + container_->AddView(TriView::Container::END, toggle_); + } + + // Resource ID for the string to use as the title of the section and for the + // accessible text on the section header toggle button. + const int title_id_; + + // View containing header row views, including title, toggle, and extra + // buttons. + TriView* container_; + + // ToggleButton to toggle section on or off. + views::ToggleButton* toggle_; + + // TrayPopupItemStyle used to configure labels and buttons. + std::unique_ptr<TrayPopupItemStyle> style_; + + DISALLOW_COPY_AND_ASSIGN(SectionHeaderRowView); +}; + +namespace { + +class CellularHeaderRowView : public NetworkListViewMd::SectionHeaderRowView { + public: + CellularHeaderRowView() + : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_MOBILE) {} + + ~CellularHeaderRowView() override {} + + const char* GetClassName() const override { return "CellularHeaderRowView"; } + + protected: + void OnToggleToggled(bool is_on) override { + NetworkStateHandler* handler = + NetworkHandler::Get()->network_state_handler(); + handler->SetTechnologyEnabled(NetworkTypePattern::Cellular(), is_on, + chromeos::network_handler::ErrorCallback()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(CellularHeaderRowView); +}; + +class TetherHeaderRowView : public NetworkListViewMd::SectionHeaderRowView { + public: + TetherHeaderRowView() + : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_TETHER) {} + + ~TetherHeaderRowView() override {} + + const char* GetClassName() const override { return "TetherHeaderRowView"; } + + protected: + void OnToggleToggled(bool is_on) override { + // TODO (hansberry): Persist toggle to settings/preferences. + } + + private: + DISALLOW_COPY_AND_ASSIGN(TetherHeaderRowView); +}; + +class WifiHeaderRowView : public NetworkListViewMd::SectionHeaderRowView { + public: + explicit WifiHeaderRowView(NetworkListDelegate* network_list_delegate) + : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_WIFI), + network_list_delegate_(network_list_delegate), + join_(nullptr) {} + + ~WifiHeaderRowView() override {} + + void SetEnabled(bool enabled) override { + join_->SetEnabled(enabled); + SectionHeaderRowView::SetEnabled(enabled); + } + + const char* GetClassName() const override { return "WifiHeaderRowView"; } + + protected: + // SectionHeaderRowView: + void OnToggleToggled(bool is_on) override { + NetworkStateHandler* handler = + NetworkHandler::Get()->network_state_handler(); + handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), is_on, + chromeos::network_handler::ErrorCallback()); + } + + void AddExtraButtons(bool enabled) override { + const SkColor prominent_color = GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ProminentButtonColor); + gfx::ImageSkia normal_image = network_icon::GetImageForNewWifiNetwork( + SkColorSetA(prominent_color, kJoinIconAlpha), + SkColorSetA(prominent_color, kJoinBadgeAlpha)); + gfx::ImageSkia disabled_image = network_icon::GetImageForNewWifiNetwork( + SkColorSetA(prominent_color, kDisabledJoinIconAlpha), + SkColorSetA(prominent_color, kDisabledJoinBadgeAlpha)); + join_ = new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + normal_image, disabled_image, + IDS_ASH_STATUS_TRAY_OTHER_WIFI); + join_->SetInkDropColor(prominent_color); + join_->SetEnabled(enabled); + container()->AddView(TriView::Container::END, join_); + } + + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + if (sender == join_) { + network_list_delegate_->OnOtherWifiClicked(); + return; + } + SectionHeaderRowView::ButtonPressed(sender, event); + } + + private: + // Full opacity for badge. + static constexpr int kJoinBadgeAlpha = 0xFF; + + // .30 opacity for icon. + static constexpr int kJoinIconAlpha = 0x4D; + + // .38 opacity for disabled badge. + static constexpr int kDisabledJoinBadgeAlpha = 0x61; + + // .30 * .38 opacity for disabled icon. + static constexpr int kDisabledJoinIconAlpha = 0x1D; + + NetworkListDelegate* network_list_delegate_; + + // A button to invoke "Join Wi-Fi network" dialog. + SystemMenuButton* join_; + + DISALLOW_COPY_AND_ASSIGN(WifiHeaderRowView); +}; + +} // namespace + +// NetworkListViewMd: + +NetworkListViewMd::NetworkListViewMd(NetworkListDelegate* delegate) + : needs_relayout_(false), + delegate_(delegate), + no_wifi_networks_view_(nullptr), + no_cellular_networks_view_(nullptr), + cellular_header_view_(nullptr), + tether_header_view_(nullptr), + wifi_header_view_(nullptr), + cellular_separator_view_(nullptr), + tether_separator_view_(nullptr), + wifi_separator_view_(nullptr) { + CHECK(delegate_); +} + +NetworkListViewMd::~NetworkListViewMd() { + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); +} + +void NetworkListViewMd::Update() { + CHECK(container()); + + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + NetworkStateHandler::NetworkStateList network_list; + handler->GetVisibleNetworkList(&network_list); + UpdateNetworks(network_list); + + NetworkStateHandler::NetworkStateList tether_network_list; + handler->GetTetherNetworkList(0 /* no limit */, &tether_network_list); + for (const auto* tether_network : tether_network_list) { + network_list_.push_back( + base::MakeUnique<NetworkInfo>(tether_network->guid())); + } + + UpdateNetworkIcons(); + OrderNetworks(); + UpdateNetworkListInternal(); +} + +bool NetworkListViewMd::IsNetworkEntry(views::View* view, + std::string* guid) const { + std::map<views::View*, std::string>::const_iterator found = + network_map_.find(view); + if (found == network_map_.end()) + return false; + *guid = found->second; + return true; +} + +void NetworkListViewMd::UpdateNetworks( + const NetworkStateHandler::NetworkStateList& networks) { + SCOPED_NET_LOG_IF_SLOW(); + network_list_.clear(); + const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); + for (const auto* network : networks) { + if (pattern.MatchesType(network->type())) + network_list_.push_back(base::MakeUnique<NetworkInfo>(network->guid())); + } +} + +void NetworkListViewMd::OrderNetworks() { + struct CompareNetwork { + explicit CompareNetwork(NetworkStateHandler* handler) : handler_(handler) {} + + // Returns true if |network1| is less than (i.e. is ordered before) + // |network2|. + bool operator()(const std::unique_ptr<NetworkInfo>& network1, + const std::unique_ptr<NetworkInfo>& network2) { + const int order1 = + GetOrder(handler_->GetNetworkStateFromGuid(network1->guid)); + const int order2 = + GetOrder(handler_->GetNetworkStateFromGuid(network2->guid)); + if (order1 != order2) + return order1 < order2; + if (network1->connected != network2->connected) + return network1->connected; + if (network1->connecting != network2->connecting) + return network1->connecting; + if (network1->highlight != network2->highlight) + return network1->highlight; + return network1->guid.compare(network2->guid) < 0; + } + + private: + static int GetOrder(const chromeos::NetworkState* network) { + if (!network) + return 999; + if (network->Matches(NetworkTypePattern::Ethernet())) + return 0; + if (network->Matches(NetworkTypePattern::Cellular())) + return 1; + if (network->Matches(NetworkTypePattern::Mobile())) + return 2; + if (network->Matches(NetworkTypePattern::WiFi())) + return 3; + return 4; + } + + NetworkStateHandler* handler_; + }; + std::sort(network_list_.begin(), network_list_.end(), + CompareNetwork(NetworkHandler::Get()->network_state_handler())); +} + +void NetworkListViewMd::UpdateNetworkIcons() { + SCOPED_NET_LOG_IF_SLOW(); + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + // First, update state for all networks. + bool animating = false; + + for (auto& info : network_list_) { + const chromeos::NetworkState* network = + handler->GetNetworkStateFromGuid(info->guid); + if (!network) + continue; + bool prohibited_by_policy = IsProhibitedByPolicy(network); + info->label = network_icon::GetLabelForNetwork( + network, network_icon::ICON_TYPE_MENU_LIST); + info->image = + network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); + info->disable = + (network->activation_state() == shill::kActivationStateActivating) || + prohibited_by_policy; + info->connected = network->IsConnectedState(); + info->connecting = network->IsConnectingState(); + info->highlight = info->connected || info->connecting; + if (network->Matches(NetworkTypePattern::WiFi())) + info->type = NetworkInfo::Type::WIFI; + else if (network->Matches(NetworkTypePattern::Cellular())) + info->type = NetworkInfo::Type::CELLULAR; + else if (network->Matches(NetworkTypePattern::Tether())) + info->type = NetworkInfo::Type::TETHER; + if (prohibited_by_policy) { + info->tooltip = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED); + } + if (!animating && network->IsConnectingState()) + animating = true; + } + if (animating) + network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); + else + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); +} + +void NetworkListViewMd::UpdateNetworkListInternal() { + SCOPED_NET_LOG_IF_SLOW(); + // Get the updated list entries. + needs_relayout_ = false; + network_map_.clear(); + std::unique_ptr<std::set<std::string>> new_guids = UpdateNetworkListEntries(); + + // Remove old children. + std::set<std::string> remove_guids; + for (const auto& iter : network_guid_map_) { + if (new_guids->find(iter.first) == new_guids->end()) { + remove_guids.insert(iter.first); + network_map_.erase(iter.second); + delete iter.second; + needs_relayout_ = true; + } + } + + for (const auto& remove_iter : remove_guids) + network_guid_map_.erase(remove_iter); + + if (!needs_relayout_) + return; + + views::View* selected_view = nullptr; + for (const auto& iter : network_guid_map_) { + if (delegate_->IsViewHovered(iter.second)) { + selected_view = iter.second; + break; + } + } + container()->SizeToPreferredSize(); + delegate_->RelayoutScrollList(); + if (selected_view) + container()->ScrollRectToVisible(selected_view->bounds()); +} + +std::unique_ptr<std::set<std::string>> +NetworkListViewMd::UpdateNetworkListEntries() { + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + // First add high-priority networks (not Wi-Fi nor cellular). + std::unique_ptr<std::set<std::string>> new_guids = + UpdateNetworkChildren(NetworkInfo::Type::UNKNOWN, 0); + + // Keep an index where the next child should be inserted. + int index = new_guids->size(); + + const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); + if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) { + if (handler->IsTechnologyAvailable(NetworkTypePattern::Cellular())) { + index = UpdateSectionHeaderRow( + NetworkTypePattern::Cellular(), + handler->IsTechnologyEnabled(NetworkTypePattern::Cellular()), index, + &cellular_header_view_, &cellular_separator_view_); + } + + // Cellular initializing. + int message_id = network_icon::GetCellularUninitializedMsg(); + if (!message_id && + handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) && + !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) { + message_id = IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS; + } + UpdateInfoLabel(message_id, index, &no_cellular_networks_view_); + if (message_id) + ++index; + + // Add cellular networks. + std::unique_ptr<std::set<std::string>> new_cellular_guids = + UpdateNetworkChildren(NetworkInfo::Type::CELLULAR, index); + index += new_cellular_guids->size(); + new_guids->insert(new_cellular_guids->begin(), new_cellular_guids->end()); + } + + // TODO (hansberry): Audit existing usage of NonVirtual and consider changing + // it to include Tether. See crbug.com/693647. + if (handler->IsTechnologyAvailable(NetworkTypePattern::Tether())) { + index = UpdateSectionHeaderRow( + NetworkTypePattern::Tether(), + handler->IsTechnologyEnabled(NetworkTypePattern::Tether()), index, + &tether_header_view_, &tether_separator_view_); + + // TODO (hansberry): Should a message similar to + // IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS be shown if Tether technology + // is enabled but no networks are around? + + // Add Tether networks. + std::unique_ptr<std::set<std::string>> new_tether_guids = + UpdateNetworkChildren(NetworkInfo::Type::TETHER, index); + index += new_tether_guids->size(); + new_guids->insert(new_tether_guids->begin(), new_tether_guids->end()); + } + + if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) { + index = UpdateSectionHeaderRow( + NetworkTypePattern::WiFi(), + handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index, + &wifi_header_view_, &wifi_separator_view_); + + // "Wifi Enabled / Disabled". + int message_id = 0; + if (network_list_.empty()) { + message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()) + ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED + : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; + } + UpdateInfoLabel(message_id, index, &no_wifi_networks_view_); + if (message_id) + ++index; + + // Add Wi-Fi networks. + std::unique_ptr<std::set<std::string>> new_wifi_guids = + UpdateNetworkChildren(NetworkInfo::Type::WIFI, index); + index += new_wifi_guids->size(); + new_guids->insert(new_wifi_guids->begin(), new_wifi_guids->end()); + } + + // No networks or other messages (fallback). + if (index == 0) { + UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, index, + &no_wifi_networks_view_); + } + + return new_guids; +} + +std::unique_ptr<std::set<std::string>> NetworkListViewMd::UpdateNetworkChildren( + NetworkInfo::Type type, + int index) { + std::unique_ptr<std::set<std::string>> new_guids(new std::set<std::string>); + for (const auto& info : network_list_) { + if (info->type != type) + continue; + UpdateNetworkChild(index++, info.get()); + new_guids->insert(info->guid); + } + return new_guids; +} + +void NetworkListViewMd::UpdateNetworkChild(int index, const NetworkInfo* info) { + views::View* network_view = nullptr; + NetworkGuidMap::const_iterator found = network_guid_map_.find(info->guid); + if (found == network_guid_map_.end()) { + network_view = delegate_->CreateViewForNetwork(*info); + } else { + network_view = found->second; + network_view->RemoveAllChildViews(true); + delegate_->UpdateViewForNetwork(network_view, *info); + network_view->Layout(); + network_view->SchedulePaint(); + } + PlaceViewAtIndex(network_view, index); + if (info->disable) + network_view->SetEnabled(false); + network_map_[network_view] = info->guid; + network_guid_map_[info->guid] = network_view; +} + +void NetworkListViewMd::PlaceViewAtIndex(views::View* view, int index) { + if (view->parent() != container()) { + container()->AddChildViewAt(view, index); + } else { + if (container()->child_at(index) == view) + return; + container()->ReorderChildView(view, index); + } + needs_relayout_ = true; +} + +void NetworkListViewMd::UpdateInfoLabel(int message_id, + int insertion_index, + views::Label** label_ptr) { + views::Label* label = *label_ptr; + if (!message_id) { + if (label) { + needs_relayout_ = true; + delete label; + *label_ptr = nullptr; + } + return; + } + base::string16 text = + ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id); + if (!label) + label = delegate_->CreateInfoLabel(); + label->SetText(text); + PlaceViewAtIndex(label, insertion_index); + *label_ptr = label; +} + +int NetworkListViewMd::UpdateSectionHeaderRow( + NetworkTypePattern pattern, + bool enabled, + int child_index, + SectionHeaderRowView** view, + views::Separator** separator_view) { + if (!*view) { + if (pattern.Equals(NetworkTypePattern::Cellular())) + *view = new CellularHeaderRowView(); + else if (pattern.Equals(NetworkTypePattern::Tether())) + *view = new TetherHeaderRowView(); + else if (pattern.Equals(NetworkTypePattern::WiFi())) + *view = new WifiHeaderRowView(delegate_); + else + NOTREACHED(); + (*view)->Init(enabled); + } + // Show or hide a separator above the header. The separator should only be + // visible when the header row is not at the top of the list. + if (child_index > 0) { + if (!*separator_view) + *separator_view = TrayPopupUtils::CreateListSubHeaderSeparator(); + PlaceViewAtIndex(*separator_view, child_index++); + } else { + if (*separator_view) + delete *separator_view; + *separator_view = nullptr; + } + + (*view)->SetEnabled(enabled); + PlaceViewAtIndex(*view, child_index++); + return child_index; +} + +void NetworkListViewMd::NetworkIconChanged() { + Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_list_md.h b/ash/common/system/chromeos/network/network_list_md.h new file mode 100644 index 0000000..fea2365 --- /dev/null +++ b/ash/common/system/chromeos/network/network_list_md.h
@@ -0,0 +1,132 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_MD_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_MD_H_ + +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" +#include "ash/common/system/chromeos/network/network_info.h" +#include "ash/common/system/chromeos/network/network_list_view_base.h" +#include "base/macros.h" +#include "chromeos/network/network_state_handler.h" +#include "chromeos/network/network_type_pattern.h" +#include "ui/gfx/image/image_skia.h" + +namespace views { +class Label; +class Separator; +class View; +} + +namespace ash { + +struct NetworkInfo; +class NetworkListDelegate; + +// A list of available networks of a given type. This class is used for all +// network types except VPNs. For VPNs, see the |VPNList| class. +class NetworkListViewMd : public NetworkListViewBase, + public network_icon::AnimationObserver { + public: + class SectionHeaderRowView; + + explicit NetworkListViewMd(NetworkListDelegate* delegate); + ~NetworkListViewMd() override; + + // NetworkListViewBase: + void Update() override; + bool IsNetworkEntry(views::View* view, std::string* guid) const override; + + private: + // Clears |network_list_| and adds to it |networks| that match |delegate_|'s + // network type pattern. + void UpdateNetworks( + const chromeos::NetworkStateHandler::NetworkStateList& networks); + + // Updates |network_list_| entries and sets |this| to observe network icon + // animations when any of the networks are in connecting state. + void UpdateNetworkIcons(); + + // Orders entries in |network_list_| such that higher priority network types + // are at the top of the list. + void OrderNetworks(); + + // Refreshes a list of child views, updates |network_map_| and + // |network_guid_map_| and performs layout making sure selected view if any is + // scrolled into view. + void UpdateNetworkListInternal(); + + // Adds new or updates existing child views including header row and messages. + // Returns a set of guids for the added network connections. + std::unique_ptr<std::set<std::string>> UpdateNetworkListEntries(); + + // Adds or updates child views representing the network connections when + // |is_wifi| is matching the attribute of a network connection starting at + // |child_index|. Returns a set of guids for the added network + // connections. + std::unique_ptr<std::set<std::string>> UpdateNetworkChildren( + NetworkInfo::Type type, + int child_index); + void UpdateNetworkChild(int index, const NetworkInfo* info); + + // Reorders children of |container()| as necessary placing |view| at |index|. + void PlaceViewAtIndex(views::View* view, int index); + + // Creates a Label with text specified by |message_id| and adds it to + // |container()| if necessary or updates the text and reorders the + // |container()| placing the label at |insertion_index|. When |message_id| is + // zero removes the |*label_ptr| from the |container()| and destroys it. + // |label_ptr| is an in / out parameter and is only modified if the Label is + // created or destroyed. + void UpdateInfoLabel(int message_id, + int insertion_index, + views::Label** label_ptr); + + // Creates a cellular/Wi-Fi header row |view| and adds it to |container()| if + // necessary and reorders the |container()| placing the |view| at + // |child_index|. Returns the index where the next child should be inserted, + // i.e., the index directly after the last inserted child. + int UpdateSectionHeaderRow(chromeos::NetworkTypePattern pattern, + bool enabled, + int child_index, + SectionHeaderRowView** view, + views::Separator** separator_view); + + // network_icon::AnimationObserver: + void NetworkIconChanged() override; + + bool needs_relayout_; + NetworkListDelegate* delegate_; + + views::Label* no_wifi_networks_view_; + views::Label* no_cellular_networks_view_; + SectionHeaderRowView* cellular_header_view_; + SectionHeaderRowView* tether_header_view_; + SectionHeaderRowView* wifi_header_view_; + views::Separator* cellular_separator_view_; + views::Separator* tether_separator_view_; + views::Separator* wifi_separator_view_; + + // An owned list of network info. + std::vector<std::unique_ptr<NetworkInfo>> network_list_; + + using NetworkMap = std::map<views::View*, std::string>; + NetworkMap network_map_; + + // A map of network guids to their view. + typedef std::map<std::string, views::View*> NetworkGuidMap; + NetworkGuidMap network_guid_map_; + + DISALLOW_COPY_AND_ASSIGN(NetworkListViewMd); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_MD_H_
diff --git a/ash/common/system/chromeos/network/network_list_view_base.cc b/ash/common/system/chromeos/network/network_list_view_base.cc new file mode 100644 index 0000000..8a16243 --- /dev/null +++ b/ash/common/system/chromeos/network/network_list_view_base.cc
@@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_list_view_base.h" + +namespace ash { + +NetworkListViewBase::NetworkListViewBase() {} + +NetworkListViewBase::~NetworkListViewBase() {} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_list_view_base.h b/ash/common/system/chromeos/network/network_list_view_base.h new file mode 100644 index 0000000..d47eb78 --- /dev/null +++ b/ash/common/system/chromeos/network/network_list_view_base.h
@@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_VIEW_BASE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_VIEW_BASE_H_ + +#include <string> + +#include "base/macros.h" + +namespace views { +class View; +} + +namespace ash { + +// Base class for a list of available networks (and, in the case of VPNs, the +// list of available VPN providers). +class NetworkListViewBase { + public: + NetworkListViewBase(); + virtual ~NetworkListViewBase(); + + void set_container(views::View* container) { container_ = container; } + + // Refreshes the network list. + virtual void Update() = 0; + + // Checks whether |view| represents a network in the list. If yes, sets + // |guid| to the network's guid and returns |true|. Otherwise, + // leaves |guid| unchanged and returns |false|. + virtual bool IsNetworkEntry(views::View* view, std::string* guid) const = 0; + + protected: + views::View* container() { return container_; } + + private: + // The container that holds the actual list entries. + views::View* container_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(NetworkListViewBase); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_LIST_VIEW_BASE_H_
diff --git a/ash/common/system/chromeos/network/network_observer.h b/ash/common/system/chromeos/network/network_observer.h new file mode 100644 index 0000000..3cf668f --- /dev/null +++ b/ash/common/system/chromeos/network/network_observer.h
@@ -0,0 +1,22 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_OBSERVER_H_ + +namespace ash { + +class NetworkObserver { + public: + virtual ~NetworkObserver() {} + + // Called to request toggling Wi-Fi enable/disable, e.g. from an accelerator. + // NOTE: Toggling is asynchronous and subsequent calls to query the current + // state may return the old value. + virtual void RequestToggleWifi() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_OBSERVER_H_
diff --git a/ash/common/system/chromeos/network/network_portal_detector_observer.h b/ash/common/system/chromeos/network/network_portal_detector_observer.h new file mode 100644 index 0000000..9bc743bf --- /dev/null +++ b/ash/common/system/chromeos/network/network_portal_detector_observer.h
@@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_PORTAL_DETECTOR_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_PORTAL_DETECTOR_OBSERVER_H_ + +#include <string> + +namespace ash { + +class NetworkPortalDetectorObserver { + public: + virtual ~NetworkPortalDetectorObserver() {} + + // Called when captive portal is detected for the network associated with + // |guid|. + virtual void OnCaptivePortalDetected(const std::string& guid) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_PORTAL_DETECTOR_OBSERVER_H_
diff --git a/ash/common/system/chromeos/network/network_state_list_detailed_view.cc b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc new file mode 100644 index 0000000..99332ef --- /dev/null +++ b/ash/common/system/chromeos/network/network_state_list_detailed_view.cc
@@ -0,0 +1,758 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/network_state_list_detailed_view.h" + +#include <algorithm> +#include <vector> + +#include "ash/common/ash_constants.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_info.h" +#include "ash/common/system/chromeos/network/network_list.h" +#include "ash/common/system/chromeos/network/network_list_md.h" +#include "ash/common/system/chromeos/network/network_list_view_base.h" +#include "ash/common/system/chromeos/network/tray_network_state_observer.h" +#include "ash/common/system/chromeos/network/vpn_list_view.h" +#include "ash/common/system/networking_config_delegate.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/throbber_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_popup_header_button.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "chromeos/chromeos_switches.h" +#include "chromeos/login/login_state.h" +#include "chromeos/network/device_state.h" +#include "chromeos/network/managed_network_configuration_handler.h" +#include "chromeos/network/network_connect.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/text_constants.h" +#include "ui/views/bubble/bubble_dialog_delegate.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/layout/layout_manager.h" +#include "ui/views/painter.h" +#include "ui/views/widget/widget.h" + +using chromeos::DeviceState; +using chromeos::LoginState; +using chromeos::NetworkHandler; +using chromeos::NetworkState; +using chromeos::NetworkStateHandler; +using chromeos::NetworkTypePattern; + +namespace ash { +namespace tray { +namespace { + +bool UseMd() { + return MaterialDesignController::IsSystemTrayMenuMaterial(); +} + +// Delay between scan requests. +const int kRequestScanDelaySeconds = 10; + +// Create a label with the font size and color used in the network info bubble. +views::Label* CreateInfoBubbleLabel(const base::string16& text) { + views::Label* label = new views::Label(text); + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + label->SetFontList(rb.GetFontList(ui::ResourceBundle::SmallFont)); + label->SetEnabledColor(SkColorSetARGB(127, 0, 0, 0)); + return label; +} + +// Create a row of labels for the network info bubble. +views::View* CreateInfoBubbleLine(const base::string16& text_label, + const std::string& text_string) { + views::View* view = new views::View; + view->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 1)); + view->AddChildView(CreateInfoBubbleLabel(text_label)); + view->AddChildView(CreateInfoBubbleLabel(base::UTF8ToUTF16(": "))); + view->AddChildView(CreateInfoBubbleLabel(base::UTF8ToUTF16(text_string))); + return view; +} + +// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. +void SetupConnectedItemMd(HoverHighlightView* container, + const base::string16& text, + const gfx::ImageSkia& image) { + container->AddIconAndLabels( + image, text, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); + style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); + style.SetupLabel(container->sub_text_label()); +} + +// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. +void SetupConnectingItemMd(HoverHighlightView* container, + const base::string16& text, + const gfx::ImageSkia& image) { + container->AddIconAndLabels( + image, text, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); + ThrobberView* throbber = new ThrobberView; + throbber->Start(); + container->AddRightView(throbber); +} + +} // namespace + +//------------------------------------------------------------------------------ + +// A bubble which displays network info. +class NetworkStateListDetailedView::InfoBubble + : public views::BubbleDialogDelegateView { + public: + InfoBubble(views::View* anchor, + views::View* content, + NetworkStateListDetailedView* detailed_view) + : views::BubbleDialogDelegateView(anchor, views::BubbleBorder::TOP_RIGHT), + detailed_view_(detailed_view) { + set_can_activate(false); + SetLayoutManager(new views::FillLayout()); + AddChildView(content); + } + + ~InfoBubble() override { detailed_view_->OnInfoBubbleDestroyed(); } + + private: + // BubbleDialogDelegateView: + int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; } + + void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, + views::Widget* widget) const override { + DCHECK(anchor_widget()); + // Place the bubble in the anchor widget's root window. + WmWindow::Get(anchor_widget()->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + widget, kShellWindowId_SettingBubbleContainer, params); + params->name = "NetworkStateListDetailedView::InfoBubble"; + } + + // Not owned. + NetworkStateListDetailedView* detailed_view_; + + DISALLOW_COPY_AND_ASSIGN(InfoBubble); +}; + +//------------------------------------------------------------------------------ + +const int kFadeIconMs = 500; + +// A throbber view that fades in/out when shown/hidden. +class ScanningThrobber : public ThrobberView { + public: + ScanningThrobber() { + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + layer()->SetOpacity(1.0); + accessible_name_ = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE); + } + ~ScanningThrobber() override {} + + // views::View + void SetVisible(bool visible) override { + layer()->GetAnimator()->StopAnimating(); // Stop any previous animation. + ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); + animation.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kFadeIconMs)); + layer()->SetOpacity(visible ? 1.0 : 0.0); + } + + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->SetName(accessible_name_); + node_data->role = ui::AX_ROLE_BUSY_INDICATOR; + } + + private: + base::string16 accessible_name_; + + DISALLOW_COPY_AND_ASSIGN(ScanningThrobber); +}; + +//------------------------------------------------------------------------------ + +// An image button showing the info icon similar to TrayPopupHeaderButton, +// but without the toggle properties, that fades in/out when shown/hidden. +class InfoIcon : public views::ImageButton { + public: + explicit InfoIcon(views::ButtonListener* listener) + : views::ImageButton(listener) { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + SetImage( + STATE_NORMAL, + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_NETWORK_INFO).ToImageSkia()); + SetImage(STATE_HOVERED, + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER) + .ToImageSkia()); + SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE); + SetAccessibleName( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_INFO)); + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + layer()->SetOpacity(1.0); + } + + ~InfoIcon() override {} + + // views::View + gfx::Size GetPreferredSize() const override { + return gfx::Size(kTrayPopupItemMinHeight, kTrayPopupItemMinHeight); + } + + void SetVisible(bool visible) override { + layer()->GetAnimator()->StopAnimating(); // Stop any previous animation. + ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); + animation.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kFadeIconMs)); + layer()->SetOpacity(visible ? 1.0 : 0.0); + } + + // views::CustomButton + void StateChanged(ButtonState old_state) override { + if (state() == STATE_HOVERED || state() == STATE_PRESSED) { + set_background(views::Background::CreateSolidBackground( + kTrayPopupHoverBackgroundColor)); + } else { + set_background(nullptr); + } + SchedulePaint(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(InfoIcon); +}; + +//------------------------------------------------------------------------------ + +// Special layout to overlap the scanning throbber and the info button. +class InfoThrobberLayout : public views::LayoutManager { + public: + InfoThrobberLayout() {} + ~InfoThrobberLayout() override {} + + // views::LayoutManager + void Layout(views::View* host) override { + gfx::Size max_size(GetMaxChildSize(host)); + // Center each child view within |max_size|. + for (int i = 0; i < host->child_count(); ++i) { + views::View* child = host->child_at(i); + if (!child->visible()) + continue; + gfx::Size child_size = child->GetPreferredSize(); + gfx::Point origin; + origin.set_x((max_size.width() - child_size.width()) / 2); + origin.set_y((max_size.height() - child_size.height()) / 2); + gfx::Rect bounds(origin, child_size); + bounds.Inset(-host->GetInsets()); + child->SetBoundsRect(bounds); + } + } + + gfx::Size GetPreferredSize(const views::View* host) const override { + gfx::Point origin; + gfx::Rect rect(origin, GetMaxChildSize(host)); + rect.Inset(-host->GetInsets()); + return rect.size(); + } + + private: + gfx::Size GetMaxChildSize(const views::View* host) const { + int width = 0, height = 0; + for (int i = 0; i < host->child_count(); ++i) { + const views::View* child = host->child_at(i); + if (!child->visible()) + continue; + gfx::Size child_size = child->GetPreferredSize(); + width = std::max(width, child_size.width()); + height = std::max(height, child_size.width()); + } + return gfx::Size(width, height); + } + + DISALLOW_COPY_AND_ASSIGN(InfoThrobberLayout); +}; + +//------------------------------------------------------------------------------ +// NetworkStateListDetailedView + +NetworkStateListDetailedView::NetworkStateListDetailedView( + SystemTrayItem* owner, + ListType list_type, + LoginStatus login) + : NetworkDetailedView(owner), + list_type_(list_type), + login_(login), + prev_wifi_scanning_state_(false), + info_icon_(nullptr), + info_button_md_(nullptr), + settings_button_md_(nullptr), + proxy_settings_button_md_(nullptr), + info_bubble_(nullptr), + scanning_throbber_(nullptr) { + if (list_type == LIST_TYPE_VPN) { + // Use a specialized class to list VPNs. + network_list_view_.reset(new VPNListView(this)); + } else { + // Use a common class to list any other network types. + // TODO(varkha): NetworkListViewMd is a temporary fork of NetworkListView. + // NetworkListView will go away when Material Design becomes default. + // See crbug.com/614453. + if (UseMd()) + network_list_view_.reset(new NetworkListViewMd(this)); + else + network_list_view_.reset(new NetworkListView(this)); + } +} + +NetworkStateListDetailedView::~NetworkStateListDetailedView() { + if (info_bubble_) + info_bubble_->GetWidget()->CloseNow(); +} + +void NetworkStateListDetailedView::Update() { + UpdateNetworkList(); + UpdateHeaderButtons(); + Layout(); +} + +// Overridden from NetworkDetailedView: + +void NetworkStateListDetailedView::Init() { + Reset(); + info_icon_ = nullptr; + info_button_md_ = nullptr; + settings_button_md_ = nullptr; + proxy_settings_button_md_ = nullptr; + scanning_throbber_ = nullptr; + + CreateScrollableList(); + if (!UseMd()) + CreateNetworkExtra(); + CreateTitleRow(list_type_ == ListType::LIST_TYPE_NETWORK + ? IDS_ASH_STATUS_TRAY_NETWORK + : IDS_ASH_STATUS_TRAY_VPN); + + network_list_view_->set_container(scroll_content()); + Update(); + + if (list_type_ != LIST_TYPE_VPN) + CallRequestScan(); +} + +NetworkDetailedView::DetailedViewType +NetworkStateListDetailedView::GetViewType() const { + return STATE_LIST_VIEW; +} + +void NetworkStateListDetailedView::HandleButtonPressed(views::Button* sender, + const ui::Event& event) { + if (sender == info_button_md_) { + ToggleInfoBubble(); + return; + } else if (sender == settings_button_md_) { + ShowSettings(); + } else if (sender == proxy_settings_button_md_) { + WmShell::Get()->system_tray_controller()->ShowProxySettings(); + } + + if (owner()->system_tray()) + owner()->system_tray()->CloseSystemBubble(); +} + +void NetworkStateListDetailedView::HandleViewClicked(views::View* view) { + // If the info bubble was visible, close it when some other item is clicked. + ResetInfoBubble(); + + if (login_ == LoginStatus::LOCKED) + return; + + std::string guid; + if (!network_list_view_->IsNetworkEntry(view, &guid)) + return; + + const NetworkState* network = + NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( + guid); + if (!network || network->IsConnectedState() || network->IsConnectingState()) { + WmShell::Get()->RecordUserMetricsAction( + list_type_ == LIST_TYPE_VPN + ? UMA_STATUS_AREA_SHOW_VPN_CONNECTION_DETAILS + : UMA_STATUS_AREA_SHOW_NETWORK_CONNECTION_DETAILS); + WmShell::Get()->system_tray_controller()->ShowNetworkSettings( + network ? network->guid() : std::string()); + } else { + WmShell::Get()->RecordUserMetricsAction( + list_type_ == LIST_TYPE_VPN + ? UMA_STATUS_AREA_CONNECT_TO_VPN + : UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK); + chromeos::NetworkConnect::Get()->ConnectToNetworkId(network->guid()); + } +} + +void NetworkStateListDetailedView::CreateExtraTitleRowButtons() { + if (login_ == LoginStatus::LOCKED) + return; + + DCHECK(!info_button_md_); + tri_view()->SetContainerVisible(TriView::Container::END, true); + + info_button_md_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuInfoIcon, + IDS_ASH_STATUS_TRAY_NETWORK_INFO); + tri_view()->AddView(TriView::Container::END, info_button_md_); + + if (login_ != LoginStatus::NOT_LOGGED_IN) { + DCHECK(!settings_button_md_); + settings_button_md_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, + IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS); + + // Allow the user to access settings only if user is logged in + // and showing settings is allowed. There are situations (supervised user + // creation flow) when session is started but UI flow continues within + // login UI, i.e., no browser window is yet avaialable. + if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings()) + settings_button_md_->SetEnabled(false); + + tri_view()->AddView(TriView::Container::END, settings_button_md_); + } else { + proxy_settings_button_md_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, + IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS); + tri_view()->AddView(TriView::Container::END, proxy_settings_button_md_); + } +} + +void NetworkStateListDetailedView::ShowSettings() { + WmShell::Get()->RecordUserMetricsAction( + list_type_ == LIST_TYPE_VPN ? UMA_STATUS_AREA_VPN_SETTINGS_OPENED + : UMA_STATUS_AREA_NETWORK_SETTINGS_OPENED); + WmShell::Get()->system_tray_controller()->ShowNetworkSettings(std::string()); +} + +void NetworkStateListDetailedView::CreateNetworkExtra() { + DCHECK(!UseMd()); +} + +void NetworkStateListDetailedView::SetScanningStateForThrobberView( + bool is_scanning) { + if (UseMd()) + return; + + // Hide the network info button if the device is scanning for Wi-Fi networks + // and display the WiFi scanning indicator. + info_icon_->SetVisible(!is_scanning); + scanning_throbber_->SetVisible(is_scanning); + // Set the element, network info button or the wifi scanning indicator, as + // focusable based on which one is active/visible. + // NOTE: As we do not want to lose focus from the network info throbber view, + // the order of below operation is important. + if (is_scanning) { + scanning_throbber_->SetFocusBehavior(FocusBehavior::ALWAYS); + info_icon_->SetFocusBehavior(FocusBehavior::NEVER); + } else { + info_icon_->SetFocusBehavior(FocusBehavior::ALWAYS); + scanning_throbber_->SetFocusBehavior(FocusBehavior::NEVER); + } + // If the Network Info view was in focus while this toggle operation was + // being performed then the focus should remain on this view. + if (info_icon_->HasFocus() && is_scanning) + scanning_throbber_->RequestFocus(); + else if (scanning_throbber_->HasFocus() && !is_scanning) + info_icon_->RequestFocus(); +} + +void NetworkStateListDetailedView::UpdateTechnologyButton( + TrayPopupHeaderButton* button, + const NetworkTypePattern& technology) { + NetworkStateHandler::TechnologyState state = + NetworkHandler::Get()->network_state_handler()->GetTechnologyState( + technology); + if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) { + button->SetVisible(false); + return; + } + button->SetVisible(true); + if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) { + button->SetEnabled(true); + button->SetToggled(true); + } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) { + button->SetEnabled(true); + button->SetToggled(false); + } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLING) { + button->SetEnabled(false); + button->SetToggled(false); + } else { // Initializing + button->SetEnabled(false); + button->SetToggled(true); + } +} + +void NetworkStateListDetailedView::UpdateNetworkList() { + network_list_view_->Update(); +} + +void NetworkStateListDetailedView::UpdateHeaderButtons() { + if (proxy_settings_button_md_) { + proxy_settings_button_md_->SetEnabled( + NetworkHandler::Get()->network_state_handler()->DefaultNetwork() != + nullptr); + } +} + +bool NetworkStateListDetailedView::OrderChild(views::View* view, int index) { + if (scroll_content()->child_at(index) != view) { + scroll_content()->ReorderChildView(view, index); + return true; + } + return false; +} + +void NetworkStateListDetailedView::CreateSettingsEntry() { + DCHECK(!UseMd()); +} + +void NetworkStateListDetailedView::ToggleInfoBubble() { + if (ResetInfoBubble()) + return; + + info_bubble_ = new InfoBubble(UseMd() ? info_button_md_ : info_icon_, + CreateNetworkInfoView(), this); + views::BubbleDialogDelegateView::CreateBubble(info_bubble_)->Show(); + info_bubble_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false); +} + +bool NetworkStateListDetailedView::ResetInfoBubble() { + if (!info_bubble_) + return false; + info_bubble_->GetWidget()->Close(); + info_bubble_ = nullptr; + return true; +} + +void NetworkStateListDetailedView::OnInfoBubbleDestroyed() { + info_bubble_ = nullptr; +} + +views::View* NetworkStateListDetailedView::CreateNetworkInfoView() { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + + std::string ip_address, ipv6_address; + const NetworkState* network = handler->DefaultNetwork(); + if (network) { + const DeviceState* device = handler->GetDeviceState(network->device_path()); + if (device) { + ip_address = device->GetIpAddressByType(shill::kTypeIPv4); + ipv6_address = device->GetIpAddressByType(shill::kTypeIPv6); + } + } + + views::View* container = new views::View; + container->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); + container->SetBorder(views::CreateEmptyBorder(0, 5, 0, 5)); + + std::string ethernet_address, wifi_address, vpn_address; + if (list_type_ != LIST_TYPE_VPN) { + ethernet_address = handler->FormattedHardwareAddressForType( + NetworkTypePattern::Ethernet()); + wifi_address = + handler->FormattedHardwareAddressForType(NetworkTypePattern::WiFi()); + } else { + vpn_address = + handler->FormattedHardwareAddressForType(NetworkTypePattern::VPN()); + } + + if (!ip_address.empty()) { + container->AddChildView(CreateInfoBubbleLine( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_IP), ip_address)); + } + if (!ipv6_address.empty()) { + container->AddChildView(CreateInfoBubbleLine( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_IPV6), ipv6_address)); + } + if (!ethernet_address.empty()) { + container->AddChildView(CreateInfoBubbleLine( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_ETHERNET), + ethernet_address)); + } + if (!wifi_address.empty()) { + container->AddChildView(CreateInfoBubbleLine( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_WIFI), wifi_address)); + } + if (!vpn_address.empty()) { + container->AddChildView(CreateInfoBubbleLine( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_VPN), vpn_address)); + } + + // Avoid an empty bubble in the unlikely event that there is no network + // information at all. + if (!container->has_children()) { + container->AddChildView(CreateInfoBubbleLabel( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_NO_NETWORKS))); + } + + return container; +} + +const gfx::ImageSkia* +NetworkStateListDetailedView::GetControlledByExtensionIcon() { + // Lazily load the icon from the resource bundle. + if (controlled_by_extension_icon_.IsEmpty()) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + controlled_by_extension_icon_ = + rb.GetImageNamed(IDR_AURA_UBER_TRAY_NETWORK_CONTROLLED); + } + DCHECK(!controlled_by_extension_icon_.IsEmpty()); + return controlled_by_extension_icon_.ToImageSkia(); +} + +views::View* NetworkStateListDetailedView::CreateControlledByExtensionView( + const NetworkInfo& info) { + NetworkingConfigDelegate* networking_config_delegate = + WmShell::Get()->system_tray_delegate()->GetNetworkingConfigDelegate(); + if (!networking_config_delegate) + return nullptr; + std::unique_ptr<const NetworkingConfigDelegate::ExtensionInfo> + extension_info = + networking_config_delegate->LookUpExtensionForNetwork(info.guid); + if (!extension_info) + return nullptr; + + // Get the tooltip text. + base::string16 tooltip_text = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI, + base::UTF8ToUTF16(extension_info->extension_name)); + + views::ImageView* controlled_icon = + new FixedSizedImageView(kTrayPopupDetailsIconWidth, 0); + + controlled_icon->SetImage(GetControlledByExtensionIcon()); + controlled_icon->SetTooltipText(tooltip_text); + return controlled_icon; +} + +void NetworkStateListDetailedView::CallRequestScan() { + VLOG(1) << "Requesting Network Scan."; + NetworkHandler::Get()->network_state_handler()->RequestScan(); + // Periodically request a scan while this UI is open. + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::Bind(&NetworkStateListDetailedView::CallRequestScan, AsWeakPtr()), + base::TimeDelta::FromSeconds(kRequestScanDelaySeconds)); +} + +void NetworkStateListDetailedView::ToggleMobile() { + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()); + chromeos::NetworkConnect::Get()->SetTechnologyEnabled( + NetworkTypePattern::Mobile(), !enabled); +} + +views::View* NetworkStateListDetailedView::CreateViewForNetwork( + const NetworkInfo& info) { + HoverHighlightView* container = new HoverHighlightView(this); + if (info.connected) + SetupConnectedItemMd(container, info.label, info.image); + else if (info.connecting) + SetupConnectingItemMd(container, info.label, info.image); + else + container->AddIconAndLabel(info.image, info.label, info.highlight); + container->set_tooltip(info.tooltip); + if (!UseMd()) { + container->SetBorder( + views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); + } + views::View* controlled_icon = CreateControlledByExtensionView(info); + if (controlled_icon) + container->AddChildView(controlled_icon); + return container; +} + +bool NetworkStateListDetailedView::IsViewHovered(views::View* view) { + return static_cast<HoverHighlightView*>(view)->hover(); +} + +NetworkTypePattern NetworkStateListDetailedView::GetNetworkTypePattern() const { + return list_type_ == LIST_TYPE_VPN ? NetworkTypePattern::VPN() + : NetworkTypePattern::NonVirtual(); +} + +void NetworkStateListDetailedView::UpdateViewForNetwork( + views::View* view, + const NetworkInfo& info) { + HoverHighlightView* container = static_cast<HoverHighlightView*>(view); + DCHECK(!container->has_children()); + if (info.connected) + SetupConnectedItemMd(container, info.label, info.image); + else if (info.connecting) + SetupConnectingItemMd(container, info.label, info.image); + else + container->AddIconAndLabel(info.image, info.label, info.highlight); + views::View* controlled_icon = CreateControlledByExtensionView(info); + container->set_tooltip(info.tooltip); + if (controlled_icon) + view->AddChildView(controlled_icon); +} + +views::Label* NetworkStateListDetailedView::CreateInfoLabel() { + views::Label* label = new views::Label(); + label->SetBorder(views::CreateEmptyBorder(kTrayPopupPaddingBetweenItems, + kTrayPopupPaddingHorizontal, + kTrayPopupPaddingBetweenItems, 0)); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0)); + return label; +} + +void NetworkStateListDetailedView::OnNetworkEntryClicked(views::View* sender) { + HandleViewClicked(sender); +} + +void NetworkStateListDetailedView::OnOtherWifiClicked() { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED); + WmShell::Get()->system_tray_controller()->ShowNetworkCreate(shill::kTypeWifi); +} + +void NetworkStateListDetailedView::RelayoutScrollList() { + scroller()->Layout(); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/chromeos/network/network_state_list_detailed_view.h b/ash/common/system/chromeos/network/network_state_list_detailed_view.h new file mode 100644 index 0000000..a3801c3 --- /dev/null +++ b/ash/common/system/chromeos/network/network_state_list_detailed_view.h
@@ -0,0 +1,154 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_STATE_LIST_DETAILED_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_STATE_LIST_DETAILED_VIEW_H_ + +#include <memory> +#include <string> + +#include "ash/common/login_status.h" +#include "ash/common/system/chromeos/network/network_detailed_view.h" +#include "ash/common/system/chromeos/network/network_list_delegate.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "ui/gfx/image/image.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/custom_button.h" + +namespace chromeos { +class NetworkTypePattern; +} + +namespace ash { +class NetworkListViewBase; +} + +namespace views { +class BubbleDialogDelegateView; +class ImageButton; +} + +namespace ash { +class SystemTrayItem; +class ThrobberView; +class TrayPopupHeaderButton; + +namespace tray { + +class NetworkStateListDetailedView + : public NetworkDetailedView, + public NetworkListDelegate, + public base::SupportsWeakPtr<NetworkStateListDetailedView> { + public: + enum ListType { LIST_TYPE_NETWORK, LIST_TYPE_VPN }; + + NetworkStateListDetailedView(SystemTrayItem* owner, + ListType list_type, + LoginStatus login); + ~NetworkStateListDetailedView() override; + + // Overridden from NetworkDetailedView: + void Init() override; + DetailedViewType GetViewType() const override; + void Update() override; + + private: + class InfoBubble; + + // TrayDetailsView: + void HandleViewClicked(views::View* view) override; + void HandleButtonPressed(views::Button* sender, + const ui::Event& event) override; + void CreateExtraTitleRowButtons() override; + + // Launches the WebUI settings in a browser and closes the system menu. + void ShowSettings(); + + // Create UI components. + void CreateHeaderEntry(); + void CreateNetworkExtra(); + + // Update UI components. + void UpdateTechnologyButton(TrayPopupHeaderButton* button, + const chromeos::NetworkTypePattern& technology); + void UpdateNetworkList(); + void UpdateHeaderButtons(); + + bool OrderChild(views::View* view, int index); + + // Adds a settings entry when logged in, and an entry for changing proxy + // settings otherwise. + void CreateSettingsEntry(); + + // Sets the visibility and focusability of Network Info Button and + // WiFi scanning indicator. This will hide Network info button and display + // the scanning indicator when |is_scanning| is true. + void SetScanningStateForThrobberView(bool is_scanning); + + // Create and manage the network info bubble. + void ToggleInfoBubble(); + bool ResetInfoBubble(); + void OnInfoBubbleDestroyed(); + views::View* CreateNetworkInfoView(); + const gfx::ImageSkia* GetControlledByExtensionIcon(); + + // Creates the view of an extra icon appearing next to the network name + // indicating that the network is controlled by an extension. If no extension + // is registered for this network, returns |nullptr|. + views::View* CreateControlledByExtensionView(const NetworkInfo& info); + + // Periodically request a network scan. + void CallRequestScan(); + + // Handle toggile mobile action + void ToggleMobile(); + + // NetworkListDelegate: + views::View* CreateViewForNetwork(const NetworkInfo& info) override; + bool IsViewHovered(views::View* view) override; + chromeos::NetworkTypePattern GetNetworkTypePattern() const override; + void UpdateViewForNetwork(views::View* view, + const NetworkInfo& info) override; + views::Label* CreateInfoLabel() override; + void OnNetworkEntryClicked(views::View* sender) override; + void OnOtherWifiClicked() override; + void RelayoutScrollList() override; + + // Type of list (all networks or vpn) + ListType list_type_; + + // Track login state. + LoginStatus login_; + + // Tracks the WiFi scanning state to help detect if the state has changed. Use + // NetworkHandler::GetScanningByType() if you require the current wifi + // scanning state. + bool prev_wifi_scanning_state_; + + // Not used for material design. + views::ImageButton* info_icon_; + + // Only used in material design. + views::CustomButton* info_button_md_; + views::CustomButton* settings_button_md_; + views::CustomButton* proxy_settings_button_md_; + + // A small bubble for displaying network info. + views::BubbleDialogDelegateView* info_bubble_; + + // WiFi scanning throbber. + ThrobberView* scanning_throbber_; + + gfx::Image controlled_by_extension_icon_; + + std::unique_ptr<NetworkListViewBase> network_list_view_; + + DISALLOW_COPY_AND_ASSIGN(NetworkStateListDetailedView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_NETWORK_STATE_LIST_DETAILED_VIEW_H_
diff --git a/ash/common/system/chromeos/network/sms_observer.cc b/ash/common/system/chromeos/network/sms_observer.cc new file mode 100644 index 0000000..b6cb0f5 --- /dev/null +++ b/ash/common/system/chromeos/network/sms_observer.cc
@@ -0,0 +1,93 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/sms_observer.h" + +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "chromeos/network/network_event_log.h" +#include "chromeos/network/network_handler.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/message_center/message_center.h" + +using chromeos::NetworkHandler; + +namespace ash { + +namespace { + +// Send the |message| to notification center to display to users. Note that each +// notification will be assigned with different |message_id| as notification id. +void ShowNotification(const base::DictionaryValue* message, + const std::string& message_text, + const std::string& message_number, + int message_id) { + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + if (!message_center) + return; + + const char kNotificationId[] = "chrome://network/sms"; + std::unique_ptr<message_center::Notification> notification; + + notification = base::MakeUnique<message_center::Notification>( + message_center::NOTIFICATION_TYPE_SIMPLE, + kNotificationId + std::to_string(message_id), + base::ASCIIToUTF16(message_number), base::ASCIIToUTF16(message_text), + gfx::Image(gfx::CreateVectorIcon( + ash::kSystemMenuSmsIcon, ash::kMenuIconSize, ash::kMenuIconColor)), + base::string16(), GURL(), + message_center::NotifierId(message_center::NotifierId::APPLICATION, + ash::system_notifier::kNotifierSms), + message_center::RichNotificationData(), nullptr); + message_center->AddNotification(std::move(notification)); +} + +} // namespace + +SmsObserver::SmsObserver() { + // TODO(armansito): SMS could be a special case for cellular that requires a + // user (perhaps the owner) to be logged in. If that is the case, then an + // additional check should be done before subscribing for SMS notifications. + if (NetworkHandler::IsInitialized()) + NetworkHandler::Get()->network_sms_handler()->AddObserver(this); +} + +SmsObserver::~SmsObserver() { + if (NetworkHandler::IsInitialized()) { + NetworkHandler::Get()->network_sms_handler()->RemoveObserver(this); + } +} + +void SmsObserver::MessageReceived(const base::DictionaryValue& message) { + std::string message_text; + if (!message.GetStringWithoutPathExpansion( + chromeos::NetworkSmsHandler::kTextKey, &message_text)) { + NET_LOG(ERROR) << "SMS message contains no content."; + return; + } + // TODO(armansito): A message might be due to a special "Message Waiting" + // state that the message is in. Once SMS handling moves to shill, such + // messages should be filtered there so that this check becomes unnecessary. + if (message_text.empty()) { + NET_LOG(DEBUG) << "SMS has empty content text. Ignoring."; + return; + } + std::string message_number; + if (!message.GetStringWithoutPathExpansion( + chromeos::NetworkSmsHandler::kNumberKey, &message_number)) { + NET_LOG(DEBUG) << "SMS contains no number. Ignoring."; + return; + } + + NET_LOG(DEBUG) << "Received SMS from: " << message_number + << " with text: " << message_text; + message_id_++; + ShowNotification(&message, message_text, message_number, message_id_); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/sms_observer.h b/ash/common/system/chromeos/network/sms_observer.h new file mode 100644 index 0000000..72a2e0cb --- /dev/null +++ b/ash/common/system/chromeos/network/sms_observer.h
@@ -0,0 +1,35 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_SMS_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_SMS_OBSERVER_H_ + +#include "chromeos/network/network_sms_handler.h" + +namespace base { +class DictionaryValue; +} + +namespace ash { + +// SmsObserver is called when a new sms message is received. Then it shows the +// sms message to the user in the notification center. +class SmsObserver : public chromeos::NetworkSmsHandler::Observer { + public: + SmsObserver(); + ~SmsObserver() override; + + // chromeos::NetworkSmsHandler::Observer: + void MessageReceived(const base::DictionaryValue& message) override; + + private: + // Used to create notification identifier. + uint32_t message_id_ = 0; + + DISALLOW_COPY_AND_ASSIGN(SmsObserver); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_SMS_OBSERVER_H_
diff --git a/ash/common/system/chromeos/network/sms_observer_unittest.cc b/ash/common/system/chromeos/network/sms_observer_unittest.cc new file mode 100644 index 0000000..4aea419 --- /dev/null +++ b/ash/common/system/chromeos/network/sms_observer_unittest.cc
@@ -0,0 +1,136 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/sms_observer.h" + +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/public/interfaces/vpn_list.mojom.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "base/macros.h" +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_list.h" + +using message_center::MessageCenter; + +namespace ash { + +namespace { + +std::unique_ptr<base::DictionaryValue> CreateMessage( + const char* kDefaultMessage = "FakeSMSClient: Test Message.", + const char* kDefaultNumber = "000-000-0000", + const char* kDefaultTimestamp = "Fri Jun 8 13:26:04 EDT 2016") { + std::unique_ptr<base::DictionaryValue> sms = + base::MakeUnique<base::DictionaryValue>(); + if (kDefaultNumber) + sms->SetString("number", kDefaultNumber); + if (kDefaultMessage) + sms->SetString("text", kDefaultMessage); + if (kDefaultTimestamp) + sms->SetString("timestamp", kDefaultMessage); + return sms; +} + +} // namespace + +class SmsObserverTest : public test::AshTestBase { + public: + SmsObserverTest() {} + ~SmsObserverTest() override {} + + SmsObserver* GetSmsObserver() { + return Shell::GetInstance()->sms_observer_.get(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(SmsObserverTest); +}; + +// Verify if notification is received after receiving a sms message with +// number and content. +TEST_F(SmsObserverTest, SendTextMessage) { + SmsObserver* sms_observer = GetSmsObserver(); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); + + std::unique_ptr<base::DictionaryValue> sms(CreateMessage()); + sms_observer->MessageReceived(*sms); + + const message_center::NotificationList::Notifications notifications = + MessageCenter::Get()->GetVisibleNotifications(); + EXPECT_EQ(1u, notifications.size()); + + EXPECT_EQ(base::ASCIIToUTF16("000-000-0000"), + (*notifications.begin())->title()); + EXPECT_EQ(base::ASCIIToUTF16("FakeSMSClient: Test Message."), + (*notifications.begin())->message()); + MessageCenter::Get()->RemoveAllNotifications(false /* by_user */, + MessageCenter::RemoveType::ALL); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); +} + +// Verify if no notification is received if phone number is missing in sms +// message. +TEST_F(SmsObserverTest, TextMessageMissingNumber) { + SmsObserver* sms_observer = GetSmsObserver(); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); + + std::unique_ptr<base::DictionaryValue> sms( + CreateMessage("FakeSMSClient: Test Message.", nullptr)); + sms_observer->MessageReceived(*sms); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); +} + +// Verify if no notification is received if text body is empty in sms message. +TEST_F(SmsObserverTest, TextMessageEmptyText) { + SmsObserver* sms_observer = GetSmsObserver(); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); + + std::unique_ptr<base::DictionaryValue> sms(CreateMessage("")); + sms_observer->MessageReceived(*sms); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); +} + +// Verify if no notification is received if the text is missing in sms message. +TEST_F(SmsObserverTest, TextMessageMissingText) { + SmsObserver* sms_observer = GetSmsObserver(); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); + std::unique_ptr<base::DictionaryValue> sms(CreateMessage(nullptr)); + sms_observer->MessageReceived(*sms); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); +} + +// Verify if 2 notification received after receiving 2 sms messages from the +// same number. +TEST_F(SmsObserverTest, MultipleTextMessages) { + SmsObserver* sms_observer = GetSmsObserver(); + EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); + + std::unique_ptr<base::DictionaryValue> sms(CreateMessage("first message")); + sms_observer->MessageReceived(*sms); + std::unique_ptr<base::DictionaryValue> sms2(CreateMessage("second message")); + sms_observer->MessageReceived(*sms2); + const message_center::NotificationList::Notifications notifications = + MessageCenter::Get()->GetVisibleNotifications(); + EXPECT_EQ(2u, notifications.size()); + + for (message_center::Notification* iter : notifications) { + if (iter->id().find("chrome://network/sms1") != std::string::npos) { + EXPECT_EQ(base::ASCIIToUTF16("000-000-0000"), iter->title()); + EXPECT_EQ(base::ASCIIToUTF16("first message"), iter->message()); + } else if (iter->id().find("chrome://network/sms2") != std::string::npos) { + EXPECT_EQ(base::ASCIIToUTF16("000-000-0000"), iter->title()); + EXPECT_EQ(base::ASCIIToUTF16("second message"), iter->message()); + } else { + ASSERT_TRUE(false); + } + } +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/tray_network.cc b/ash/common/system/chromeos/network/tray_network.cc new file mode 100644 index 0000000..decfc5a --- /dev/null +++ b/ash/common/system/chromeos/network/tray_network.cc
@@ -0,0 +1,341 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/tray_network.h" + +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" +#include "ash/common/system/chromeos/network/network_state_list_detailed_view.h" +#include "ash/common/system/chromeos/network/tray_network_state_observer.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/command_line.h" +#include "base/strings/utf_string_conversions.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/link.h" +#include "ui/views/controls/link_listener.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/widget/widget.h" + +using chromeos::NetworkHandler; +using chromeos::NetworkState; +using chromeos::NetworkStateHandler; +using chromeos::NetworkTypePattern; + +namespace ash { +namespace tray { + +namespace { + +// Returns the connected, non-virtual (aka VPN), network. +const NetworkState* GetConnectedNetwork() { + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + return handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); +} + +} // namespace + +class NetworkTrayView : public TrayItemView, + public network_icon::AnimationObserver { + public: + explicit NetworkTrayView(TrayNetwork* network_tray) + : TrayItemView(network_tray) { + CreateImageView(); + UpdateNetworkStateHandlerIcon(); + } + + ~NetworkTrayView() override { + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + } + + const char* GetClassName() const override { return "NetworkTrayView"; } + + void UpdateNetworkStateHandlerIcon() { + gfx::ImageSkia image; + base::string16 name; + bool animating = false; + network_icon::GetDefaultNetworkImageAndLabel(network_icon::ICON_TYPE_TRAY, + &image, &name, &animating); + bool show_in_tray = !image.isNull(); + UpdateIcon(show_in_tray, image); + if (animating) + network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); + else + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + // Update accessibility. + const NetworkState* connected_network = GetConnectedNetwork(); + if (connected_network) { + UpdateConnectionStatus(base::UTF8ToUTF16(connected_network->name()), + true); + } else { + UpdateConnectionStatus(base::string16(), false); + } + } + + // views::View: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->SetName(connection_status_string_); + node_data->role = ui::AX_ROLE_BUTTON; + } + + // network_icon::AnimationObserver: + void NetworkIconChanged() override { UpdateNetworkStateHandlerIcon(); } + + private: + // Updates connection status and notifies accessibility event when necessary. + void UpdateConnectionStatus(const base::string16& network_name, + bool connected) { + base::string16 new_connection_status_string; + if (connected) { + new_connection_status_string = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, network_name); + } + if (new_connection_status_string != connection_status_string_) { + connection_status_string_ = new_connection_status_string; + if (!connection_status_string_.empty()) + NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + } + } + + void UpdateIcon(bool tray_icon_visible, const gfx::ImageSkia& image) { + image_view()->SetImage(image); + SetVisible(tray_icon_visible); + SchedulePaint(); + } + + base::string16 connection_status_string_; + + DISALLOW_COPY_AND_ASSIGN(NetworkTrayView); +}; + +class NetworkDefaultView : public TrayItemMore, + public network_icon::AnimationObserver { + public: + explicit NetworkDefaultView(TrayNetwork* network_tray) + : TrayItemMore(network_tray) { + Update(); + } + + ~NetworkDefaultView() override { + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + } + + void Update() { + gfx::ImageSkia image; + base::string16 label; + bool animating = false; + // TODO(bruthig): Update the image to use the proper color. See + // https://crbug.com/632027. + network_icon::GetDefaultNetworkImageAndLabel( + network_icon::ICON_TYPE_DEFAULT_VIEW, &image, &label, &animating); + if (animating) + network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); + else + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + SetImage(image); + SetLabel(label); + SetAccessibleName(label); + UpdateStyle(); + } + + // network_icon::AnimationObserver + void NetworkIconChanged() override { Update(); } + + protected: + // TrayItemMore: + std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const override { + std::unique_ptr<TrayPopupItemStyle> style = + TrayItemMore::HandleCreateStyle(); + style->set_color_style(GetConnectedNetwork() != nullptr + ? TrayPopupItemStyle::ColorStyle::ACTIVE + : TrayPopupItemStyle::ColorStyle::INACTIVE); + return style; + } + + private: + DISALLOW_COPY_AND_ASSIGN(NetworkDefaultView); +}; + +class NetworkWifiDetailedView : public NetworkDetailedView { + public: + explicit NetworkWifiDetailedView(SystemTrayItem* owner) + : NetworkDetailedView(owner) { + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, + kTrayPopupPaddingHorizontal, 10, + kTrayPopupPaddingBetweenItems)); + image_view_ = new views::ImageView; + AddChildView(image_view_); + + label_view_ = new views::Label(); + label_view_->SetMultiLine(true); + label_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + AddChildView(label_view_); + + Update(); + } + + ~NetworkWifiDetailedView() override {} + + // Overridden from NetworkDetailedView: + + void Init() override {} + + NetworkDetailedView::DetailedViewType GetViewType() const override { + return NetworkDetailedView::WIFI_VIEW; + } + + void Layout() override { + // Center both views vertically. + views::View::Layout(); + image_view_->SetY((height() - image_view_->GetPreferredSize().height()) / + 2); + label_view_->SetY((height() - label_view_->GetPreferredSize().height()) / + 2); + } + + void Update() override { + bool wifi_enabled = + NetworkHandler::Get()->network_state_handler()->IsTechnologyEnabled( + NetworkTypePattern::WiFi()); + const int image_id = wifi_enabled ? IDR_AURA_UBER_TRAY_WIFI_ENABLED + : IDR_AURA_UBER_TRAY_WIFI_DISABLED; + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + image_view_->SetImage(bundle.GetImageNamed(image_id).ToImageSkia()); + + const int string_id = wifi_enabled + ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED + : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; + label_view_->SetText(bundle.GetLocalizedString(string_id)); + label_view_->SizeToFit( + kTrayPopupMinWidth - kTrayPopupPaddingHorizontal * 2 - + kTrayPopupPaddingBetweenItems - kTrayPopupDetailsIconWidth); + } + + private: + views::ImageView* image_view_; + views::Label* label_view_; + + DISALLOW_COPY_AND_ASSIGN(NetworkWifiDetailedView); +}; + +} // namespace tray + +TrayNetwork::TrayNetwork(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_NETWORK), + tray_(NULL), + default_(NULL), + detailed_(NULL), + request_wifi_view_(false) { + network_state_observer_.reset(new TrayNetworkStateObserver(this)); + SystemTrayNotifier* notifier = WmShell::Get()->system_tray_notifier(); + notifier->AddNetworkObserver(this); + notifier->AddNetworkPortalDetectorObserver(this); +} + +TrayNetwork::~TrayNetwork() { + SystemTrayNotifier* notifier = WmShell::Get()->system_tray_notifier(); + notifier->RemoveNetworkObserver(this); + notifier->RemoveNetworkPortalDetectorObserver(this); +} + +views::View* TrayNetwork::CreateTrayView(LoginStatus status) { + CHECK(tray_ == NULL); + if (!chromeos::NetworkHandler::IsInitialized()) + return NULL; + tray_ = new tray::NetworkTrayView(this); + return tray_; +} + +views::View* TrayNetwork::CreateDefaultView(LoginStatus status) { + CHECK(default_ == NULL); + if (!chromeos::NetworkHandler::IsInitialized()) + return NULL; + CHECK(tray_ != NULL); + default_ = new tray::NetworkDefaultView(this); + default_->SetEnabled(status != LoginStatus::LOCKED); + return default_; +} + +views::View* TrayNetwork::CreateDetailedView(LoginStatus status) { + CHECK(detailed_ == NULL); + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DETAILED_NETWORK_VIEW); + if (!chromeos::NetworkHandler::IsInitialized()) + return NULL; + if (request_wifi_view_) { + detailed_ = new tray::NetworkWifiDetailedView(this); + request_wifi_view_ = false; + } else { + detailed_ = new tray::NetworkStateListDetailedView( + this, tray::NetworkStateListDetailedView::LIST_TYPE_NETWORK, status); + detailed_->Init(); + } + return detailed_; +} + +void TrayNetwork::DestroyTrayView() { + tray_ = NULL; +} + +void TrayNetwork::DestroyDefaultView() { + default_ = NULL; +} + +void TrayNetwork::DestroyDetailedView() { + detailed_ = NULL; +} + +void TrayNetwork::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + if (tray_) + SetTrayImageItemBorder(tray_, alignment); +} + +void TrayNetwork::RequestToggleWifi() { + // This will always be triggered by a user action (e.g. keyboard shortcut) + if (!detailed_ || + detailed_->GetViewType() == tray::NetworkDetailedView::WIFI_VIEW) { + request_wifi_view_ = true; + PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); + } + NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); + bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()); + WmShell::Get()->RecordUserMetricsAction( + enabled ? UMA_STATUS_AREA_DISABLE_WIFI : UMA_STATUS_AREA_ENABLE_WIFI); + handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), !enabled, + chromeos::network_handler::ErrorCallback()); +} + +void TrayNetwork::OnCaptivePortalDetected(const std::string& /* guid */) { + NetworkStateChanged(); +} + +void TrayNetwork::NetworkStateChanged() { + if (tray_) + tray_->UpdateNetworkStateHandlerIcon(); + if (default_) + default_->Update(); + if (detailed_) + detailed_->Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/tray_network.h b/ash/common/system/chromeos/network/tray_network.h new file mode 100644 index 0000000..34a4284 --- /dev/null +++ b/ash/common/system/chromeos/network/tray_network.h
@@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_NETWORK_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_NETWORK_H_ + +#include <memory> +#include <set> + +#include "ash/common/system/chromeos/network/network_observer.h" +#include "ash/common/system/chromeos/network/network_portal_detector_observer.h" +#include "ash/common/system/chromeos/network/tray_network_state_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" +#include "base/time/time.h" + +namespace ash { +namespace tray { +class NetworkDefaultView; +class NetworkDetailedView; +class NetworkTrayView; +} + +class TrayNetwork : public SystemTrayItem, + public NetworkObserver, + public NetworkPortalDetectorObserver, + public TrayNetworkStateObserver::Delegate { + public: + explicit TrayNetwork(SystemTray* system_tray); + ~TrayNetwork() override; + + tray::NetworkDetailedView* detailed() { return detailed_; } + + // SystemTrayItem + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // NetworkObserver + void RequestToggleWifi() override; + + // NetworkPortalDetectorObserver + void OnCaptivePortalDetected(const std::string& guid) override; + + // TrayNetworkStateObserver::Delegate + void NetworkStateChanged() override; + + private: + tray::NetworkTrayView* tray_; + tray::NetworkDefaultView* default_; + tray::NetworkDetailedView* detailed_; + bool request_wifi_view_; + std::unique_ptr<TrayNetworkStateObserver> network_state_observer_; + + DISALLOW_COPY_AND_ASSIGN(TrayNetwork); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_NETWORK_H_
diff --git a/ash/common/system/chromeos/network/tray_network_state_observer.cc b/ash/common/system/chromeos/network/tray_network_state_observer.cc new file mode 100644 index 0000000..b1d990b --- /dev/null +++ b/ash/common/system/chromeos/network/tray_network_state_observer.cc
@@ -0,0 +1,96 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/tray_network_state_observer.h" + +#include <set> +#include <string> + +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/tray/system_tray.h" +#include "base/location.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" + +using chromeos::NetworkHandler; + +namespace { + +const int kUpdateFrequencyMs = 1000; + +} // namespace + +namespace ash { + +TrayNetworkStateObserver::TrayNetworkStateObserver(Delegate* delegate) + : delegate_(delegate), + purge_icons_(false), + update_frequency_(kUpdateFrequencyMs) { + if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() != + ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION) { + update_frequency_ = 0; // Send updates immediately for tests. + } + if (NetworkHandler::IsInitialized()) { + NetworkHandler::Get()->network_state_handler()->AddObserver(this, + FROM_HERE); + } +} + +TrayNetworkStateObserver::~TrayNetworkStateObserver() { + if (NetworkHandler::IsInitialized()) { + NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, + FROM_HERE); + } +} + +void TrayNetworkStateObserver::NetworkListChanged() { + purge_icons_ = true; + SignalUpdate(); +} + +void TrayNetworkStateObserver::DeviceListChanged() { + SignalUpdate(); +} + +// Any change to the Default (primary connected) network, including Strength +// changes, should trigger a NetworkStateChanged update. +void TrayNetworkStateObserver::DefaultNetworkChanged( + const chromeos::NetworkState* network) { + SignalUpdate(); +} + +// Any change to the Connection State should trigger a NetworkStateChanged +// update. This is important when both a VPN and a physical network are +// connected. +void TrayNetworkStateObserver::NetworkConnectionStateChanged( + const chromeos::NetworkState* network) { + SignalUpdate(); +} + +// This tracks Strength and other property changes for all networks. It will +// be called in addition to NetworkConnectionStateChanged for connection state +// changes. +void TrayNetworkStateObserver::NetworkPropertiesUpdated( + const chromeos::NetworkState* network) { + SignalUpdate(); +} + +void TrayNetworkStateObserver::SignalUpdate() { + if (timer_.IsRunning()) + return; + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(update_frequency_), + this, &TrayNetworkStateObserver::SendNetworkStateChanged); +} + +void TrayNetworkStateObserver::SendNetworkStateChanged() { + delegate_->NetworkStateChanged(); + if (purge_icons_) { + network_icon::PurgeNetworkIconCache(); + purge_icons_ = false; + } +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/tray_network_state_observer.h b/ash/common/system/chromeos/network/tray_network_state_observer.h new file mode 100644 index 0000000..178a680 --- /dev/null +++ b/ash/common/system/chromeos/network/tray_network_state_observer.h
@@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_NETWORK_STATE_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_NETWORK_STATE_OBSERVER_H_ + +#include "base/macros.h" +#include "base/timer/timer.h" +#include "chromeos/network/network_state_handler_observer.h" + +namespace ash { + +class TrayNetworkStateObserver : public chromeos::NetworkStateHandlerObserver { + public: + class Delegate { + public: + // Called when any interesting network changes occur. The frequency of this + // event is limited to kUpdateFrequencyMs. + virtual void NetworkStateChanged() = 0; + + protected: + virtual ~Delegate() {} + }; + + explicit TrayNetworkStateObserver(Delegate* delegate); + + ~TrayNetworkStateObserver() override; + + // NetworkStateHandlerObserver overrides. + void NetworkListChanged() override; + void DeviceListChanged() override; + void DefaultNetworkChanged(const chromeos::NetworkState* network) override; + void NetworkConnectionStateChanged( + const chromeos::NetworkState* network) override; + void NetworkPropertiesUpdated(const chromeos::NetworkState* network) override; + + private: + void SignalUpdate(); + void SendNetworkStateChanged(); + + // Unowned Delegate pointer (must outlive this instance). + Delegate* delegate_; + + // Set to true when we should purge stale icons in the cache. + bool purge_icons_; + + // Frequency at which to push NetworkStateChanged updates. This avoids + // unnecessarily frequent UI updates (which can be expensive). We set this + // to 0 for tests to eliminate timing variance. + int update_frequency_; + + // Timer used to limit the frequency of NetworkStateChanged updates. + base::OneShotTimer timer_; + + DISALLOW_COPY_AND_ASSIGN(TrayNetworkStateObserver); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_NETWORK_STATE_OBSERVER_H_
diff --git a/ash/common/system/chromeos/network/tray_vpn.cc b/ash/common/system/chromeos/network/tray_vpn.cc new file mode 100644 index 0000000..a2d254a --- /dev/null +++ b/ash/common/system/chromeos/network/tray_vpn.cc
@@ -0,0 +1,206 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/tray_vpn.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" +#include "ash/common/system/chromeos/network/network_state_list_detailed_view.h" +#include "ash/common/system/chromeos/network/vpn_list.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" + +using chromeos::NetworkHandler; +using chromeos::NetworkState; +using chromeos::NetworkStateHandler; +using chromeos::NetworkTypePattern; + +namespace ash { +namespace tray { + +class VpnDefaultView : public TrayItemMore, + public network_icon::AnimationObserver { + public: + explicit VpnDefaultView(SystemTrayItem* owner) : TrayItemMore(owner) {} + + ~VpnDefaultView() override { + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + } + + static bool ShouldShow() { + // Show the VPN entry in the ash tray bubble if at least one third-party VPN + // provider is installed. + if (WmShell::Get()->vpn_list()->HaveThirdPartyVPNProviders()) + return true; + + // Also show the VPN entry if at least one VPN network is configured. + NetworkStateHandler* const handler = + NetworkHandler::Get()->network_state_handler(); + if (handler->FirstNetworkByType(NetworkTypePattern::VPN())) + return true; + return false; + } + + void Update() { + gfx::ImageSkia image; + base::string16 label; + bool animating = false; + GetNetworkStateHandlerImageAndLabel(&image, &label, &animating); + if (animating) + network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); + else + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + SetImage(image); + SetLabel(label); + SetAccessibleName(label); + } + + // network_icon::AnimationObserver + void NetworkIconChanged() override { Update(); } + + protected: + // TrayItemMore: + std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const override { + std::unique_ptr<TrayPopupItemStyle> style = + TrayItemMore::HandleCreateStyle(); + style->set_color_style( + !IsVpnEnabled() + ? TrayPopupItemStyle::ColorStyle::DISABLED + : IsVpnConnected() ? TrayPopupItemStyle::ColorStyle::ACTIVE + : TrayPopupItemStyle::ColorStyle::INACTIVE); + return style; + } + + void UpdateStyle() override { + TrayItemMore::UpdateStyle(); + Update(); + } + + private: + bool IsVpnEnabled() const { + NetworkStateHandler* handler = + NetworkHandler::Get()->network_state_handler(); + return handler->FirstNetworkByType(NetworkTypePattern::VPN()); + } + + bool IsVpnConnected() const { + NetworkStateHandler* handler = + NetworkHandler::Get()->network_state_handler(); + const NetworkState* vpn = + handler->FirstNetworkByType(NetworkTypePattern::VPN()); + return IsVpnEnabled() && + (vpn->IsConnectedState() || vpn->IsConnectingState()); + } + + void GetNetworkStateHandlerImageAndLabel(gfx::ImageSkia* image, + base::string16* label, + bool* animating) { + NetworkStateHandler* handler = + NetworkHandler::Get()->network_state_handler(); + const NetworkState* vpn = + handler->FirstNetworkByType(NetworkTypePattern::VPN()); + *image = gfx::CreateVectorIcon( + kNetworkVpnIcon, TrayPopupItemStyle::GetIconColor( + vpn && vpn->IsConnectedState() + ? TrayPopupItemStyle::ColorStyle::ACTIVE + : TrayPopupItemStyle::ColorStyle::INACTIVE)); + if (!IsVpnConnected()) { + if (label) { + *label = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECTED); + } + *animating = false; + return; + } + *animating = vpn->IsConnectingState(); + if (label) { + *label = network_icon::GetLabelForNetwork( + vpn, network_icon::ICON_TYPE_DEFAULT_VIEW); + } + } + + DISALLOW_COPY_AND_ASSIGN(VpnDefaultView); +}; + +} // namespace tray + +TrayVPN::TrayVPN(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_VPN), + default_(nullptr), + detailed_(nullptr) { + network_state_observer_.reset(new TrayNetworkStateObserver(this)); +} + +TrayVPN::~TrayVPN() {} + +views::View* TrayVPN::CreateTrayView(LoginStatus status) { + return NULL; +} + +views::View* TrayVPN::CreateDefaultView(LoginStatus status) { + CHECK(default_ == NULL); + if (!chromeos::NetworkHandler::IsInitialized()) + return NULL; + if (status == LoginStatus::NOT_LOGGED_IN) + return NULL; + if (!tray::VpnDefaultView::ShouldShow()) + return NULL; + + const bool is_in_secondary_login_screen = + WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); + + default_ = new tray::VpnDefaultView(this); + default_->SetEnabled(status != LoginStatus::LOCKED && + !is_in_secondary_login_screen); + + return default_; +} + +views::View* TrayVPN::CreateDetailedView(LoginStatus status) { + CHECK(detailed_ == NULL); + if (!chromeos::NetworkHandler::IsInitialized()) + return NULL; + + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_DETAILED_VPN_VIEW); + detailed_ = new tray::NetworkStateListDetailedView( + this, tray::NetworkStateListDetailedView::LIST_TYPE_VPN, status); + detailed_->Init(); + return detailed_; +} + +void TrayVPN::DestroyTrayView() {} + +void TrayVPN::DestroyDefaultView() { + default_ = NULL; +} + +void TrayVPN::DestroyDetailedView() { + detailed_ = NULL; +} + +void TrayVPN::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayVPN::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {} + +void TrayVPN::NetworkStateChanged() { + if (default_) + default_->Update(); + if (detailed_) + detailed_->Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/tray_vpn.h b/ash/common/system/chromeos/network/tray_vpn.h new file mode 100644 index 0000000..29bf35e --- /dev/null +++ b/ash/common/system/chromeos/network/tray_vpn.h
@@ -0,0 +1,51 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_VPN_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_VPN_H_ + +#include <memory> + +#include "ash/common/system/chromeos/network/tray_network_state_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { +class TrayNetworkStateObserver; + +namespace tray { +class NetworkDetailedView; +class VpnDefaultView; +} + +class TrayVPN : public SystemTrayItem, + public TrayNetworkStateObserver::Delegate { + public: + explicit TrayVPN(SystemTray* system_tray); + ~TrayVPN() override; + + // SystemTrayItem + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // TrayNetworkStateObserver::Delegate + void NetworkStateChanged() override; + + private: + tray::VpnDefaultView* default_; + tray::NetworkDetailedView* detailed_; + std::unique_ptr<TrayNetworkStateObserver> network_state_observer_; + + DISALLOW_COPY_AND_ASSIGN(TrayVPN); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_TRAY_VPN_H_
diff --git a/ash/common/system/chromeos/network/vpn_list.cc b/ash/common/system/chromeos/network/vpn_list.cc new file mode 100644 index 0000000..b163371 --- /dev/null +++ b/ash/common/system/chromeos/network/vpn_list.cc
@@ -0,0 +1,83 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/vpn_list.h" + +#include <utility> + +#include "base/logging.h" + +namespace ash { + +VPNProvider::VPNProvider() : third_party(false) {} + +VPNProvider::VPNProvider(const std::string& extension_id, + const std::string& third_party_provider_name) + : third_party(true), + extension_id(extension_id), + third_party_provider_name(third_party_provider_name) { + DCHECK(!extension_id.empty()); + DCHECK(!third_party_provider_name.empty()); +} + +bool VPNProvider::operator==(const VPNProvider& other) const { + return third_party == other.third_party && + extension_id == other.extension_id && + third_party_provider_name == other.third_party_provider_name; +} + +VpnList::Observer::~Observer() {} + +VpnList::VpnList() { + AddBuiltInProvider(); +} + +VpnList::~VpnList() {} + +bool VpnList::HaveThirdPartyVPNProviders() const { + for (const VPNProvider& provider : vpn_providers_) { + if (provider.third_party) + return true; + } + return false; +} + +void VpnList::AddObserver(Observer* observer) { + observer_list_.AddObserver(observer); +} + +void VpnList::RemoveObserver(Observer* observer) { + observer_list_.RemoveObserver(observer); +} + +void VpnList::BindRequest(mojom::VpnListRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void VpnList::SetThirdPartyVpnProviders( + std::vector<mojom::ThirdPartyVpnProviderPtr> providers) { + vpn_providers_.clear(); + vpn_providers_.reserve(providers.size() + 1); + // Add the OpenVPN provider. + AddBuiltInProvider(); + // Append the extension-backed providers. + for (const auto& provider : providers) { + vpn_providers_.push_back( + VPNProvider(provider->extension_id, provider->name)); + } + NotifyObservers(); +} + +void VpnList::NotifyObservers() { + for (auto& observer : observer_list_) + observer.OnVPNProvidersChanged(); +} + +void VpnList::AddBuiltInProvider() { + // The VPNProvider() constructor generates the built-in provider and has no + // extension ID. + vpn_providers_.push_back(VPNProvider()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/vpn_list.h b/ash/common/system/chromeos/network/vpn_list.h new file mode 100644 index 0000000..6c7b0383 --- /dev/null +++ b/ash/common/system/chromeos/network/vpn_list.h
@@ -0,0 +1,101 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_VPN_LIST_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_VPN_LIST_H_ + +#include <string> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/public/interfaces/vpn_list.mojom.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "mojo/public/cpp/bindings/binding_set.h" + +namespace ash { + +// Describes a VPN provider. +struct ASH_EXPORT VPNProvider { + // Constructs the built-in VPN provider. + VPNProvider(); + + // Constructs a third-party VPN provider. + VPNProvider(const std::string& extension_id, + const std::string& third_party_provider_name); + + bool operator==(const VPNProvider& other) const; + + // Whether this key represents a built-in or third-party VPN provider. + bool third_party; + + // ID of the extension that implements this provider. Used for third-party + // VPN providers only. + std::string extension_id; + + // Human-readable name if |third_party| is true, otherwise empty. + std::string third_party_provider_name; +}; + +// This delegate provides UI code in ash, e.g. |VPNListView|, with access to the +// list of VPN providers enabled in the primary user's profile. The delegate +// furthermore allows the UI code to request that a VPN provider show its "add +// network" dialog. +class ASH_EXPORT VpnList : public mojom::VpnList { + public: + // An observer that is notified whenever the list of VPN providers enabled in + // the primary user's profile changes. + class Observer { + public: + virtual void OnVPNProvidersChanged() = 0; + + protected: + virtual ~Observer(); + + private: + DISALLOW_ASSIGN(Observer); + }; + + VpnList(); + ~VpnList() override; + + const std::vector<VPNProvider>& vpn_providers() { return vpn_providers_; } + + // Returns |true| if at least one third-party VPN provider is enabled in the + // primary user's profile, in addition to the built-in OpenVPN/L2TP provider. + bool HaveThirdPartyVPNProviders() const; + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Binds the mojom::VpnList interface to this object. + void BindRequest(mojom::VpnListRequest request); + + // mojom::VpnList: + void SetThirdPartyVpnProviders( + std::vector<mojom::ThirdPartyVpnProviderPtr> providers) override; + + private: + // Notify observers that the list of VPN providers enabled in the primary + // user's profile has changed. + void NotifyObservers(); + + // Adds the built-in OpenVPN/L2TP provider to |vpn_providers_|. + void AddBuiltInProvider(); + + // Bindings for the mojom::VpnList interface. + mojo::BindingSet<mojom::VpnList> bindings_; + + // Cache of VPN providers, including the built-in OpenVPN/L2TP provider and + // other providers added by extensions in the primary user's profile. + std::vector<VPNProvider> vpn_providers_; + + base::ObserverList<Observer> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(VpnList); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_VPN_LIST_H_
diff --git a/ash/common/system/chromeos/network/vpn_list_unittest.cc b/ash/common/system/chromeos/network/vpn_list_unittest.cc new file mode 100644 index 0000000..1da3722 --- /dev/null +++ b/ash/common/system/chromeos/network/vpn_list_unittest.cc
@@ -0,0 +1,99 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/vpn_list.h" + +#include <algorithm> +#include <vector> + +#include "ash/public/interfaces/vpn_list.mojom.h" +#include "base/macros.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ash::mojom::ThirdPartyVpnProvider; +using ash::mojom::ThirdPartyVpnProviderPtr; + +namespace ash { + +namespace { + +class TestVpnListObserver : public VpnList::Observer { + public: + TestVpnListObserver() {} + ~TestVpnListObserver() override {} + + // VpnList::Observer: + void OnVPNProvidersChanged() override { change_count_++; } + + int change_count_ = 0; +}; + +} // namespace + +using VpnListTest = testing::Test; + +TEST_F(VpnListTest, BuiltInProvider) { + VpnList vpn_list; + + // The VPN list should only contain the built-in provider. + ASSERT_EQ(1u, vpn_list.vpn_providers().size()); + VPNProvider provider = vpn_list.vpn_providers()[0]; + EXPECT_FALSE(provider.third_party); + EXPECT_TRUE(provider.extension_id.empty()); +} + +TEST_F(VpnListTest, ThirdPartyProviders) { + VpnList vpn_list; + + // The VPN list should only contain the built-in provider. + EXPECT_EQ(1u, vpn_list.vpn_providers().size()); + + // Add some third party (extension-backed) providers. + std::vector<ThirdPartyVpnProviderPtr> third_party_providers; + ThirdPartyVpnProviderPtr third_party1 = ThirdPartyVpnProvider::New(); + third_party1->name = "name1"; + third_party1->extension_id = "extension_id1"; + third_party_providers.push_back(std::move(third_party1)); + + ThirdPartyVpnProviderPtr third_party2 = ThirdPartyVpnProvider::New(); + third_party2->name = "name2"; + third_party2->extension_id = "extension_id2"; + third_party_providers.push_back(std::move(third_party2)); + + vpn_list.SetThirdPartyVpnProviders(std::move(third_party_providers)); + + // Mojo types will be converted to internal ash types. + VPNProvider provider1("extension_id1", "name1"); + VPNProvider provider2("extension_id2", "name2"); + + // List contains the extension-backed providers. Order doesn't matter. + std::vector<VPNProvider> providers = vpn_list.vpn_providers(); + EXPECT_EQ(3u, providers.size()); + EXPECT_EQ(1u, std::count(providers.begin(), providers.end(), provider1)); + EXPECT_EQ(1u, std::count(providers.begin(), providers.end(), provider2)); +} + +TEST_F(VpnListTest, Observers) { + VpnList vpn_list; + + // Observers are not notified when they are added. + TestVpnListObserver observer; + vpn_list.AddObserver(&observer); + EXPECT_EQ(0, observer.change_count_); + + // Add a third party (extension-backed) provider. + std::vector<ThirdPartyVpnProviderPtr> third_party_providers; + ThirdPartyVpnProviderPtr third_party1 = ThirdPartyVpnProvider::New(); + third_party1->name = "name1"; + third_party1->extension_id = "extension_id1"; + third_party_providers.push_back(std::move(third_party1)); + vpn_list.SetThirdPartyVpnProviders(std::move(third_party_providers)); + + // Observer was notified. + EXPECT_EQ(1, observer.change_count_); + + vpn_list.RemoveObserver(&observer); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/vpn_list_view.cc b/ash/common/system/chromeos/network/vpn_list_view.cc new file mode 100644 index 0000000..c1c1c6e7 --- /dev/null +++ b/ash/common/system/chromeos/network/vpn_list_view.cc
@@ -0,0 +1,440 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/network/vpn_list_view.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "ash/common/ash_view_ids.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" +#include "ash/common/system/chromeos/network/network_list_delegate.h" +#include "ash/common/system/chromeos/network/vpn_list.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/throbber_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "chromeos/network/network_connection_handler.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_type_pattern.h" +#include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/text_constants.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" + +namespace ash { + +namespace { + +bool UseMd() { + return MaterialDesignController::IsSystemTrayMenuMaterial(); +} + +// Indicates whether |network| belongs to this VPN provider. +bool VpnProviderMatchesNetwork(const VPNProvider& provider, + const chromeos::NetworkState& network) { + if (network.type() != shill::kTypeVPN) + return false; + const bool network_uses_third_party_provider = + network.vpn_provider_type() == shill::kProviderThirdPartyVpn; + if (!provider.third_party) + return !network_uses_third_party_provider; + return network_uses_third_party_provider && + network.third_party_vpn_provider_extension_id() == + provider.extension_id; +} + +// The base class of all list entries, a |HoverHighlightView| with no border. +class VPNListEntryBase : public HoverHighlightView { + public: + // When the user clicks the entry, the |parent|'s OnViewClicked() will be + // invoked. + explicit VPNListEntryBase(VPNListView* parent); + + private: + DISALLOW_COPY_AND_ASSIGN(VPNListEntryBase); +}; + +// A list entry that represents a VPN provider. +class VPNListProviderEntry : public VPNListEntryBase { + public: + VPNListProviderEntry(VPNListView* parent, const std::string& name) + : VPNListEntryBase(parent) { + views::Label* const label = AddLabel( + base::UTF8ToUTF16(name), gfx::ALIGN_LEFT, false /* highlight */); + label->SetBorder(views::CreateEmptyBorder(5, 0, 5, 0)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(VPNListProviderEntry); +}; + +// A list entry that represents a VPN provider with Material Design. +class VPNListProviderEntryMd : public views::ButtonListener, + public views::View { + public: + VPNListProviderEntryMd(ViewClickListener* parent, + bool top_item, + const std::string& name, + int button_accessible_name_id) + : parent_(parent) { + TrayPopupUtils::ConfigureAsStickyHeader(this); + SetLayoutManager(new views::FillLayout); + TriView* tri_view = TrayPopupUtils::CreateSubHeaderRowView(); + AddChildView(tri_view); + + views::Label* label = TrayPopupUtils::CreateDefaultLabel(); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); + style.SetupLabel(label); + label->SetText(base::ASCIIToUTF16(name)); + tri_view->AddView(TriView::Container::CENTER, label); + + const SkColor image_color = GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ProminentButtonColor); + gfx::ImageSkia icon = + gfx::CreateVectorIcon(kSystemMenuAddConnectionIcon, image_color); + SystemMenuButton* add_vpn_button = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, icon, + icon, button_accessible_name_id); + add_vpn_button->SetInkDropColor(image_color); + add_vpn_button->SetEnabled(true); + tri_view->AddView(TriView::Container::END, add_vpn_button); + } + + protected: + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + parent_->OnViewClicked(this); + } + + private: + // Our parent to handle events. + ViewClickListener* parent_; + + DISALLOW_COPY_AND_ASSIGN(VPNListProviderEntryMd); +}; + +// A list entry that represents a network. If the network is currently +// connecting, the icon shown by this list entry will be animated. If the +// network is currently connected, a disconnect button will be shown next to its +// name. +class VPNListNetworkEntry : public VPNListEntryBase, + public network_icon::AnimationObserver { + public: + VPNListNetworkEntry(VPNListView* parent, + const chromeos::NetworkState* network); + ~VPNListNetworkEntry() override; + + // network_icon::AnimationObserver: + void NetworkIconChanged() override; + + private: + void UpdateFromNetworkState(const chromeos::NetworkState* network); + void SetupConnectedItemMd(const base::string16& text, + const gfx::ImageSkia& image); + void SetupConnectingItemMd(const base::string16& text, + const gfx::ImageSkia& image); + + const std::string guid_; + + views::LabelButton* disconnect_button_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(VPNListNetworkEntry); +}; + +VPNListEntryBase::VPNListEntryBase(VPNListView* parent) + : HoverHighlightView(parent) { + if (!UseMd()) + SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); +} + +VPNListNetworkEntry::VPNListNetworkEntry(VPNListView* parent, + const chromeos::NetworkState* network) + : VPNListEntryBase(parent), guid_(network->guid()) { + UpdateFromNetworkState(network); +} + +VPNListNetworkEntry::~VPNListNetworkEntry() { + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); +} + +void VPNListNetworkEntry::NetworkIconChanged() { + UpdateFromNetworkState(chromeos::NetworkHandler::Get() + ->network_state_handler() + ->GetNetworkStateFromGuid(guid_)); +} + +void VPNListNetworkEntry::UpdateFromNetworkState( + const chromeos::NetworkState* network) { + if (network && network->IsConnectingState()) + network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); + else + network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); + + if (!network) { + // This is a transient state where the network has been removed already but + // the network list in the UI has not been updated yet. + return; + } + RemoveAllChildViews(true); + disconnect_button_ = nullptr; + + gfx::ImageSkia image = + network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); + base::string16 label = network_icon::GetLabelForNetwork( + network, UseMd() ? network_icon::ICON_TYPE_MENU_LIST + : network_icon::ICON_TYPE_LIST); + if (network->IsConnectedState()) + SetupConnectedItemMd(label, image); + else if (network->IsConnectingState()) + SetupConnectingItemMd(label, image); + else + AddIconAndLabel(image, label, false); + + if (network->IsConnectedState()) { + disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton( + this, l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)); + tri_view()->AddView(TriView::Container::END, disconnect_button_); + tri_view()->SetContainerVisible(TriView::Container::END, true); + tri_view()->SetContainerBorder( + TriView::Container::END, + views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); + } + Layout(); +} + +// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. +void VPNListNetworkEntry::SetupConnectedItemMd(const base::string16& text, + const gfx::ImageSkia& image) { + AddIconAndLabels( + image, text, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); + style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); + style.SetupLabel(sub_text_label()); +} + +// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. +void VPNListNetworkEntry::SetupConnectingItemMd(const base::string16& text, + const gfx::ImageSkia& image) { + AddIconAndLabels( + image, text, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); + ThrobberView* throbber = new ThrobberView; + throbber->Start(); + AddRightView(throbber); +} + +} // namespace + +VPNListView::VPNListView(NetworkListDelegate* delegate) : delegate_(delegate) { + WmShell::Get()->vpn_list()->AddObserver(this); +} + +VPNListView::~VPNListView() { + WmShell::Get()->vpn_list()->RemoveObserver(this); +} + +void VPNListView::Update() { + // Before updating the list, determine whether the user was hovering over one + // of the VPN provider or network entries. + std::unique_ptr<VPNProvider> hovered_provider; + std::string hovered_network_guid; + for (const std::pair<const views::View* const, VPNProvider>& provider : + provider_view_map_) { + if (static_cast<const HoverHighlightView*>(provider.first)->hover()) { + hovered_provider.reset(new VPNProvider(provider.second)); + break; + } + } + if (!hovered_provider) { + for (const std::pair<const views::View*, std::string>& entry : + network_view_guid_map_) { + if (static_cast<const HoverHighlightView*>(entry.first)->hover()) { + hovered_network_guid = entry.second; + break; + } + } + } + + // Clear the list. + container()->RemoveAllChildViews(true); + provider_view_map_.clear(); + network_view_guid_map_.clear(); + list_empty_ = true; + if (!UseMd()) { + container()->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); + } + + // Get the list of available VPN networks, in shill's priority order. + chromeos::NetworkStateHandler::NetworkStateList networks; + chromeos::NetworkHandler::Get() + ->network_state_handler() + ->GetVisibleNetworkListByType(chromeos::NetworkTypePattern::VPN(), + &networks); + + // Show all VPN providers and all networks that are currently disconnected. + AddProvidersAndNetworks(networks); + + // Determine whether one of the new list entries corresponds to the entry that + // the user was previously hovering over. If such an entry is found, the list + // will be scrolled to ensure the entry is visible. + const views::View* scroll_to_show_view = nullptr; + if (hovered_provider) { + for (const std::pair<const views::View* const, VPNProvider>& provider : + provider_view_map_) { + if (provider.second == *hovered_provider) { + scroll_to_show_view = provider.first; + break; + } + } + } else if (!hovered_network_guid.empty()) { + for (const std::pair<const views::View*, std::string>& entry : + network_view_guid_map_) { + if (entry.second == hovered_network_guid) { + scroll_to_show_view = entry.first; + break; + } + } + } + + // Layout the updated list. + container()->SizeToPreferredSize(); + delegate_->RelayoutScrollList(); + + if (scroll_to_show_view) { + // Scroll the list so that |scroll_to_show_view| is in view. + container()->ScrollRectToVisible(scroll_to_show_view->bounds()); + } +} + +bool VPNListView::IsNetworkEntry(views::View* view, std::string* guid) const { + const auto& entry = network_view_guid_map_.find(view); + if (entry == network_view_guid_map_.end()) + return false; + *guid = entry->second; + return true; +} + +void VPNListView::OnVPNProvidersChanged() { + Update(); +} + +void VPNListView::OnViewClicked(views::View* sender) { + const auto& provider_iter = provider_view_map_.find(sender); + if (provider_iter != provider_view_map_.end()) { + // If the user clicks on a provider entry, request that the "add network" + // dialog for this provider be shown. + const VPNProvider& provider = provider_iter->second; + WmShell* shell = WmShell::Get(); + if (provider.third_party) { + shell->RecordUserMetricsAction( + UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED); + shell->system_tray_controller()->ShowThirdPartyVpnCreate( + provider.extension_id); + } else { + shell->RecordUserMetricsAction(UMA_STATUS_AREA_VPN_ADD_BUILT_IN_CLICKED); + shell->system_tray_controller()->ShowNetworkCreate(shill::kTypeVPN); + } + return; + } + + // If the user clicked on a network entry, let the |delegate_| trigger a + // connection attempt (if the network is currently disconnected) or show a + // configuration dialog (if the network is currently connected or connecting). + delegate_->OnNetworkEntryClicked(sender); +} + +void VPNListView::AddNetwork(const chromeos::NetworkState* network) { + views::View* entry(new VPNListNetworkEntry(this, network)); + container()->AddChildView(entry); + network_view_guid_map_[entry] = network->guid(); + list_empty_ = false; +} + +void VPNListView::AddProviderAndNetworks( + const VPNProvider& vpn_provider, + const chromeos::NetworkStateHandler::NetworkStateList& networks) { + // Add a visual separator, unless this is the topmost entry in the list. + if (!list_empty_) + container()->AddChildView(TrayPopupUtils::CreateListSubHeaderSeparator()); + std::string vpn_name = + vpn_provider.third_party + ? vpn_provider.third_party_provider_name + : l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_VPN_BUILT_IN_PROVIDER); + + // Add a list entry for the VPN provider. + views::View* provider_view = nullptr; + if (UseMd()) { + provider_view = new VPNListProviderEntryMd( + this, list_empty_, vpn_name, IDS_ASH_STATUS_TRAY_ADD_CONNECTION); + } else { + provider_view = new VPNListProviderEntry(this, vpn_name); + } + container()->AddChildView(provider_view); + provider_view_map_[provider_view] = vpn_provider; + list_empty_ = false; + // Add the networks belonging to this provider, in the priority order returned + // by shill. + for (const chromeos::NetworkState* const& network : networks) { + if (VpnProviderMatchesNetwork(vpn_provider, *network)) + AddNetwork(network); + } +} + +void VPNListView::AddProvidersAndNetworks( + const chromeos::NetworkStateHandler::NetworkStateList& networks) { + // Get the list of VPN providers enabled in the primary user's profile. + std::vector<VPNProvider> providers = + WmShell::Get()->vpn_list()->vpn_providers(); + + // Add providers with at least one configured network along with their + // networks. Providers are added in the order of their highest priority + // network. + for (const chromeos::NetworkState* const& network : networks) { + for (auto provider = providers.begin(); provider != providers.end(); + ++provider) { + if (!VpnProviderMatchesNetwork(*provider, *network)) + continue; + AddProviderAndNetworks(*provider, networks); + providers.erase(provider); + break; + } + } + + // Add providers without any configured networks, in the order that the + // providers were returned by the extensions system. + for (const VPNProvider& provider : providers) + AddProviderAndNetworks(provider, networks); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/network/vpn_list_view.h b/ash/common/system/chromeos/network/vpn_list_view.h new file mode 100644 index 0000000..6b9c3a8 --- /dev/null +++ b/ash/common/system/chromeos/network/vpn_list_view.h
@@ -0,0 +1,92 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_VPN_LIST_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_VPN_LIST_VIEW_H_ + +#include <map> +#include <string> + +#include "ash/common/system/chromeos/network/network_list_view_base.h" +#include "ash/common/system/chromeos/network/vpn_list.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "base/macros.h" +#include "chromeos/network/network_state_handler.h" + +namespace chromeos { +class NetworkState; +} + +namespace ash { +class NetworkListDelegate; +} + +namespace views { +class View; +} + +namespace ash { + +// A list of VPN providers and networks that shows VPN providers and networks in +// a hierarchical layout, allowing the user to see at a glance which provider a +// network belongs to. The only exception is the currently connected or +// connecting network, which is detached from its provider and moved to the top. +// If there is a connected network, a disconnect button is shown next to its +// name. +// +// Disconnected networks are arranged in shill's priority order within each +// provider and the providers are arranged in the order of their highest +// priority network. Clicking on a disconnected network triggers a connection +// attempt. Clicking on the currently connected or connecting network shows its +// configuration dialog. Clicking on a provider shows the provider's "add +// network" dialog. +class VPNListView : public NetworkListViewBase, + public VpnList::Observer, + public ViewClickListener { + public: + explicit VPNListView(NetworkListDelegate* delegate); + ~VPNListView() override; + + // NetworkListViewBase: + void Update() override; + bool IsNetworkEntry(views::View* view, std::string* guid) const override; + + // VpnList::Observer: + void OnVPNProvidersChanged() override; + + // ViewClickListener: + void OnViewClicked(views::View* sender) override; + + private: + // Adds a network to the list. + void AddNetwork(const chromeos::NetworkState* network); + + // Adds the VPN provider identified by |vpn_provider| to the list, along with + // any networks that belong to this provider. + void AddProviderAndNetworks( + const VPNProvider& vpn_provider, + const chromeos::NetworkStateHandler::NetworkStateList& networks); + + // Adds all available VPN providers and networks to the list. + void AddProvidersAndNetworks( + const chromeos::NetworkStateHandler::NetworkStateList& networks); + + NetworkListDelegate* const delegate_; + + // A mapping from each VPN provider's list entry to the provider. + std::map<const views::View* const, VPNProvider> provider_view_map_; + + // A mapping from each network's list entry to the network's guid. + std::map<const views::View* const, std::string> network_view_guid_map_; + + // Whether the list is currently empty (i.e., the next entry added will become + // the topmost entry). + bool list_empty_ = true; + + DISALLOW_COPY_AND_ASSIGN(VPNListView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_NETWORK_VPN_LIST_VIEW_H_
diff --git a/ash/common/system/chromeos/palette/common_palette_tool.cc b/ash/common/system/chromeos/palette/common_palette_tool.cc new file mode 100644 index 0000000..23d59ad --- /dev/null +++ b/ash/common/system/chromeos/palette/common_palette_tool.cc
@@ -0,0 +1,112 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/common_palette_tool.h" + +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/system/chromeos/palette/palette_tool_manager.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "ash/resources/grit/ash_resources.h" +#include "base/logging.h" +#include "base/metrics/histogram_macros.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" + +namespace ash { +namespace { + +void AddHistogramTimes(PaletteToolId id, base::TimeDelta duration) { + if (id == PaletteToolId::LASER_POINTER) { + UMA_HISTOGRAM_CUSTOM_TIMES("Ash.Shelf.Palette.InLaserPointerMode", duration, + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromHours(1), 50); + } else if (id == PaletteToolId::MAGNIFY) { + UMA_HISTOGRAM_CUSTOM_TIMES("Ash.Shelf.Palette.InMagnifyMode", duration, + base::TimeDelta::FromMilliseconds(100), + base::TimeDelta::FromHours(1), 50); + } +} + +} // namespace + +CommonPaletteTool::CommonPaletteTool(Delegate* delegate) + : PaletteTool(delegate) {} + +CommonPaletteTool::~CommonPaletteTool() {} + +void CommonPaletteTool::OnViewDestroyed() { + highlight_view_ = nullptr; +} + +void CommonPaletteTool::OnEnable() { + PaletteTool::OnEnable(); + start_time_ = base::TimeTicks::Now(); + + if (highlight_view_) { + highlight_view_->SetRightViewVisible(true); + highlight_view_->SetAccessiblityState( + HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); + } +} + +void CommonPaletteTool::OnDisable() { + PaletteTool::OnDisable(); + AddHistogramTimes(GetToolId(), base::TimeTicks::Now() - start_time_); + + if (highlight_view_) { + highlight_view_->SetRightViewVisible(false); + highlight_view_->SetAccessiblityState( + HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); + } +} + +void CommonPaletteTool::OnViewClicked(views::View* sender) { + delegate()->RecordPaletteOptionsUsage( + PaletteToolIdToPaletteTrayOptions(GetToolId())); + if (enabled()) { + delegate()->DisableTool(GetToolId()); + delegate()->RecordPaletteModeCancellation( + PaletteToolIdToPaletteModeCancelType(GetToolId(), + false /*is_switched*/)); + } else { + delegate()->EnableTool(GetToolId()); + } +} + +views::View* CommonPaletteTool::CreateDefaultView(const base::string16& name) { + gfx::ImageSkia icon = + CreateVectorIcon(GetPaletteIcon(), kMenuIconSize, gfx::kChromeIconGrey); + gfx::ImageSkia check = CreateVectorIcon(gfx::VectorIconId::CHECK_CIRCLE, + kMenuIconSize, gfx::kGoogleGreen700); + + highlight_view_ = new HoverHighlightView(this); + highlight_view_->SetBorder(views::CreateEmptyBorder(0, 0, 0, 0)); + const int interior_button_padding = (kMenuButtonSize - kMenuIconSize) / 2; + highlight_view_->AddIconAndLabelCustomSize(icon, name, false, kMenuIconSize, + interior_button_padding, + kTrayPopupPaddingHorizontal); + highlight_view_->AddRightIcon(check, kMenuIconSize); + highlight_view_->set_custom_height(kMenuButtonSize); + + if (enabled()) { + highlight_view_->SetAccessiblityState( + HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); + } else { + highlight_view_->SetRightViewVisible(false); + highlight_view_->SetAccessiblityState( + HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); + } + + return highlight_view_; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/common_palette_tool.h b/ash/common/system/chromeos/palette/common_palette_tool.h new file mode 100644 index 0000000..1c9d59a6 --- /dev/null +++ b/ash/common/system/chromeos/palette/common_palette_tool.h
@@ -0,0 +1,54 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_COMMON_PALETTE_TOOL_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_COMMON_PALETTE_TOOL_H_ + +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "base/strings/string16.h" +#include "base/time/time.h" + +namespace gfx { +struct VectorIcon; +} + +namespace ash { + +class HoverHighlightView; + +// A PaletteTool implementation with a standard view support. +class CommonPaletteTool : public PaletteTool, public ash::ViewClickListener { + protected: + explicit CommonPaletteTool(Delegate* delegate); + ~CommonPaletteTool() override; + + // PaletteTool: + void OnViewDestroyed() override; + void OnEnable() override; + void OnDisable() override; + + // ViewClickListener: + void OnViewClicked(views::View* sender) override; + + // Returns the icon used in the palette tray on the left-most edge of the + // tool. + virtual const gfx::VectorIcon& GetPaletteIcon() const = 0; + + // Creates a default view implementation to be returned by CreateView. + views::View* CreateDefaultView(const base::string16& name); + + private: + HoverHighlightView* highlight_view_ = nullptr; + + // start_time_ is initialized when the tool becomes active. + // Used for recording UMA metrics. + base::TimeTicks start_time_; + + DISALLOW_COPY_AND_ASSIGN(CommonPaletteTool); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_COMMON_PALETTE_TOOL_H_
diff --git a/ash/common/system/chromeos/palette/mock_palette_tool_delegate.cc b/ash/common/system/chromeos/palette/mock_palette_tool_delegate.cc new file mode 100644 index 0000000..07f716d82 --- /dev/null +++ b/ash/common/system/chromeos/palette/mock_palette_tool_delegate.cc
@@ -0,0 +1,13 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/mock_palette_tool_delegate.h" + +namespace ash { + +MockPaletteToolDelegate::MockPaletteToolDelegate() {} + +MockPaletteToolDelegate::~MockPaletteToolDelegate() {} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/mock_palette_tool_delegate.h b/ash/common/system/chromeos/palette/mock_palette_tool_delegate.h new file mode 100644 index 0000000..c734a06 --- /dev/null +++ b/ash/common/system/chromeos/palette/mock_palette_tool_delegate.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_MOCK_PALETTE_TOOL_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_MOCK_PALETTE_TOOL_DELEGATE_H_ + +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace ash { + +// Mock PaletteTool::Delegate class. +class MockPaletteToolDelegate : public PaletteTool::Delegate { + public: + MockPaletteToolDelegate(); + ~MockPaletteToolDelegate() override; + + MOCK_METHOD1(EnableTool, void(PaletteToolId tool_id)); + MOCK_METHOD1(DisableTool, void(PaletteToolId tool_id)); + MOCK_METHOD0(HidePalette, void()); + MOCK_METHOD0(HidePaletteImmediately, void()); + MOCK_METHOD0(GetWindow, WmWindow*()); + MOCK_METHOD1(RecordPaletteOptionsUsage, void(PaletteTrayOptions option)); + MOCK_METHOD1(RecordPaletteModeCancellation, void(PaletteModeCancelType type)); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_MOCK_PALETTE_TOOL_DELEGATE_H_
diff --git a/ash/common/system/chromeos/palette/palette_ids.cc b/ash/common/system/chromeos/palette/palette_ids.cc new file mode 100644 index 0000000..fee896dd --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_ids.cc
@@ -0,0 +1,76 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "base/logging.h" + +namespace ash { + +std::string PaletteToolIdToString(PaletteToolId tool_id) { + switch (tool_id) { + case PaletteToolId::NONE: + return "NONE"; + case PaletteToolId::CREATE_NOTE: + return "CREATE_NOTE"; + case PaletteToolId::CAPTURE_REGION: + return "CAPTURE_REGION"; + case PaletteToolId::CAPTURE_SCREEN: + return "CAPTURE_SCREEN"; + case PaletteToolId::LASER_POINTER: + return "LASER_POINTER"; + case PaletteToolId::MAGNIFY: + return "MAGNIFY"; + } + + NOTREACHED(); + return std::string(); +} + +std::string PaletteGroupToString(PaletteGroup group) { + switch (group) { + case PaletteGroup::ACTION: + return "ACTION"; + case PaletteGroup::MODE: + return "MODE"; + } + + NOTREACHED(); + return std::string(); +} + +PaletteTrayOptions PaletteToolIdToPaletteTrayOptions(PaletteToolId tool_id) { + switch (tool_id) { + case PaletteToolId::NONE: + return PALETTE_OPTIONS_COUNT; + case PaletteToolId::CREATE_NOTE: + return PALETTE_NEW_NOTE; + case PaletteToolId::CAPTURE_REGION: + return PALETTE_CAPTURE_REGION; + case PaletteToolId::CAPTURE_SCREEN: + return PALETTE_CAPTURE_SCREEN; + case PaletteToolId::LASER_POINTER: + return PALETTE_LASER_POINTER; + case PaletteToolId::MAGNIFY: + return PALETTE_MAGNIFY; + } + + NOTREACHED(); + return PALETTE_OPTIONS_COUNT; +} + +PaletteModeCancelType PaletteToolIdToPaletteModeCancelType( + PaletteToolId tool_id, + bool is_switched) { + PaletteModeCancelType type = PALETTE_MODE_CANCEL_TYPE_COUNT; + if (tool_id == PaletteToolId::LASER_POINTER) { + return is_switched ? PALETTE_MODE_LASER_POINTER_SWITCHED + : PALETTE_MODE_LASER_POINTER_CANCELLED; + } else if (tool_id == PaletteToolId::MAGNIFY) { + return is_switched ? PALETTE_MODE_MAGNIFY_SWITCHED + : PALETTE_MODE_MAGNIFY_CANCELLED; + } + return type; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_ids.h b/ash/common/system/chromeos/palette/palette_ids.h new file mode 100644 index 0000000..a5693f70 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_ids.h
@@ -0,0 +1,68 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_IDS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_IDS_H_ + +#include <string> + +#include "ash/ash_export.h" + +namespace ash { + +// Palette tools are grouped into different categories. Each tool corresponds to +// exactly one group, and at most one tool can be active per group. Actions are +// actions the user wants to do, such as take a screenshot, and modes generally +// change OS behavior, like showing a laser pointer instead of a cursor. A mode +// is active until the user completes the action or disables it. +enum class PaletteGroup { ACTION, MODE }; + +enum class PaletteToolId { + NONE, + CREATE_NOTE, + CAPTURE_REGION, + CAPTURE_SCREEN, + LASER_POINTER, + MAGNIFY, +}; + +// Usage of each pen palette option. This enum is used to back an UMA histogram +// and should be treated as append-only. +enum PaletteTrayOptions { + PALETTE_CLOSED_NO_ACTION = 0, + PALETTE_SETTINGS_BUTTON, + PALETTE_HELP_BUTTON, + PALETTE_CAPTURE_REGION, + PALETTE_CAPTURE_SCREEN, + PALETTE_NEW_NOTE, + PALETTE_MAGNIFY, + PALETTE_LASER_POINTER, + PALETTE_OPTIONS_COUNT +}; + +// Type of palette mode cancellation. This enum is used to back an UMA histogram +// and should be treated as append-only. +enum PaletteModeCancelType { + PALETTE_MODE_LASER_POINTER_CANCELLED = 0, + PALETTE_MODE_LASER_POINTER_SWITCHED, + PALETTE_MODE_MAGNIFY_CANCELLED, + PALETTE_MODE_MAGNIFY_SWITCHED, + PALETTE_MODE_CANCEL_TYPE_COUNT +}; + +// Helper functions that convert PaletteToolIds and PaletteGroups to strings. +ASH_EXPORT std::string PaletteToolIdToString(PaletteToolId tool_id); +ASH_EXPORT std::string PaletteGroupToString(PaletteGroup group); + +// Helper functions that convert PaletteToolIds to PaletteTrayOptions. +ASH_EXPORT PaletteTrayOptions +PaletteToolIdToPaletteTrayOptions(PaletteToolId tool_id); + +// Helper functions that convert PaletteToolIds to PaletteModeCancelType. +ASH_EXPORT PaletteModeCancelType +PaletteToolIdToPaletteModeCancelType(PaletteToolId tool_id, bool is_switched); + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_IDS_H_
diff --git a/ash/common/system/chromeos/palette/palette_tool.cc b/ash/common/system/chromeos/palette/palette_tool.cc new file mode 100644 index 0000000..2ea40c1 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tool.cc
@@ -0,0 +1,44 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/palette_tool.h" + +#include "ash/common/system/chromeos/palette/palette_tool_manager.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" +#include "ash/common/system/chromeos/palette/tools/capture_region_mode.h" +#include "ash/common/system/chromeos/palette/tools/capture_screen_action.h" +#include "ash/common/system/chromeos/palette/tools/create_note_action.h" +#include "ash/common/system/chromeos/palette/tools/laser_pointer_mode.h" +#include "ash/common/system/chromeos/palette/tools/magnifier_mode.h" +#include "base/memory/ptr_util.h" +#include "ui/gfx/paint_vector_icon.h" + +namespace ash { + +// static +void PaletteTool::RegisterToolInstances(PaletteToolManager* tool_manager) { + tool_manager->AddTool(base::MakeUnique<CaptureRegionMode>(tool_manager)); + tool_manager->AddTool(base::MakeUnique<CaptureScreenAction>(tool_manager)); + tool_manager->AddTool(base::MakeUnique<CreateNoteAction>(tool_manager)); + tool_manager->AddTool(base::MakeUnique<LaserPointerMode>(tool_manager)); + tool_manager->AddTool(base::MakeUnique<MagnifierMode>(tool_manager)); +} + +PaletteTool::PaletteTool(Delegate* delegate) : delegate_(delegate) {} + +PaletteTool::~PaletteTool() {} + +void PaletteTool::OnEnable() { + enabled_ = true; +} + +void PaletteTool::OnDisable() { + enabled_ = false; +} + +const gfx::VectorIcon& PaletteTool::GetActiveTrayIcon() const { + return gfx::kNoneIcon; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_tool.h b/ash/common/system/chromeos/palette/palette_tool.h new file mode 100644 index 0000000..9b66f01 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tool.h
@@ -0,0 +1,120 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_TOOL_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_TOOL_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "base/callback.h" +#include "base/macros.h" +#include "ui/gfx/vector_icon_types.h" + +namespace gfx { +struct VectorIcon; +} + +namespace views { +class View; +} + +namespace ash { + +class WmWindow; + +enum class PaletteGroup; +enum class PaletteToolId; +class PaletteToolManager; + +// A PaletteTool is a generalized action inside of the palette menu in the +// shelf. Only one tool per group is active at any given time. When the tool is +// active, it should be showing some specializied UI. The tool is no longer +// active if it completes its action, if the user selects another tool with the +// same group, or if the user just cancels the action from the palette. +class ASH_EXPORT PaletteTool { + public: + class Delegate { + public: + Delegate() {} + virtual ~Delegate() {} + + // Enable or disable a specific tool. + virtual void EnableTool(PaletteToolId tool_id) = 0; + virtual void DisableTool(PaletteToolId tool_id) = 0; + + // Hide the entire palette. This should not change any tool state. + virtual void HidePalette() = 0; + + // Hide the entire palette without showing a hide animation. + virtual void HidePaletteImmediately() = 0; + + // Returns the root window. + virtual WmWindow* GetWindow() = 0; + + // Record usage of each pen palette option. + virtual void RecordPaletteOptionsUsage(PaletteTrayOptions option) = 0; + + // Record mode cancellation of pen palette. + virtual void RecordPaletteModeCancellation(PaletteModeCancelType type) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + // Adds all available PaletteTool instances to the tool_manager. + static void RegisterToolInstances(PaletteToolManager* tool_manager); + + // |delegate| must outlive this tool instance. + explicit PaletteTool(Delegate* delegate); + virtual ~PaletteTool(); + + // The group this tool belongs to. Only one tool per group can be active at + // any given time. + virtual PaletteGroup GetGroup() const = 0; + + // The unique identifier for this tool. This should be the only tool that ever + // has this ID. + virtual PaletteToolId GetToolId() const = 0; + + // Called when the user activates the tool. Only one tool per group can be + // active at any given time. + virtual void OnEnable(); + + // Disable the tool, either because this tool called DisableSelf(), the + // user cancelled the tool, or the user activated another tool within the + // same group. + virtual void OnDisable(); + + // Create a view that will be used in the palette, or nullptr if this tool + // should not be displayed. The view is owned by the caller. OnViewDestroyed + // is called when the view has been deallocated by its owner. + virtual views::View* CreateView() = 0; + virtual void OnViewDestroyed() = 0; + + // Returns an icon to use in the tray if this tool is active. Only one tool + // (per-group) should ever have an active icon at any given time. + virtual const gfx::VectorIcon& GetActiveTrayIcon() const; + + protected: + // Enables/disables the tool. + bool enabled() const { return enabled_; } + + Delegate* delegate() { return delegate_; } + + private: + bool enabled_ = false; + + // Unowned pointer to the delegate. The delegate should outlive this instance. + Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(PaletteTool); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_TOOL_H_
diff --git a/ash/common/system/chromeos/palette/palette_tool_manager.cc b/ash/common/system/chromeos/palette/palette_tool_manager.cc new file mode 100644 index 0000000..17da3c7 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tool_manager.cc
@@ -0,0 +1,153 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/palette_tool_manager.h" + +#include <algorithm> + +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/bind.h" +#include "base/metrics/histogram_macros.h" + +namespace ash { + +PaletteToolManager::PaletteToolManager(Delegate* delegate) + : delegate_(delegate) { + DCHECK(delegate_); +} + +PaletteToolManager::~PaletteToolManager() {} + +void PaletteToolManager::AddTool(std::unique_ptr<PaletteTool> tool) { + // The same PaletteToolId cannot be registered twice. + DCHECK_EQ(0, std::count_if(tools_.begin(), tools_.end(), + [&tool](const std::unique_ptr<PaletteTool>& t) { + return t->GetToolId() == tool->GetToolId(); + })); + + tools_.emplace_back(std::move(tool)); +} + +void PaletteToolManager::ActivateTool(PaletteToolId tool_id) { + PaletteTool* new_tool = FindToolById(tool_id); + DCHECK(new_tool); + + PaletteTool* previous_tool = active_tools_[new_tool->GetGroup()]; + + if (new_tool == previous_tool) + return; + + if (previous_tool) { + previous_tool->OnDisable(); + RecordPaletteModeCancellation(PaletteToolIdToPaletteModeCancelType( + previous_tool->GetToolId(), true /*is_switched*/)); + } + + active_tools_[new_tool->GetGroup()] = new_tool; + new_tool->OnEnable(); + + delegate_->OnActiveToolChanged(); +} + +void PaletteToolManager::DeactivateTool(PaletteToolId tool_id) { + PaletteTool* tool = FindToolById(tool_id); + DCHECK(tool); + + active_tools_[tool->GetGroup()] = nullptr; + tool->OnDisable(); + + delegate_->OnActiveToolChanged(); +} + +bool PaletteToolManager::IsToolActive(PaletteToolId tool_id) { + PaletteTool* tool = FindToolById(tool_id); + DCHECK(tool); + + return active_tools_[tool->GetGroup()] == tool; +} + +PaletteToolId PaletteToolManager::GetActiveTool(PaletteGroup group) { + PaletteTool* active_tool = active_tools_[group]; + return active_tool ? active_tool->GetToolId() : PaletteToolId::NONE; +} + +const gfx::VectorIcon& PaletteToolManager::GetActiveTrayIcon( + PaletteToolId tool_id) const { + PaletteTool* tool = FindToolById(tool_id); + if (!tool) + return kPaletteTrayIconDefaultIcon; + + return tool->GetActiveTrayIcon(); +} + +std::vector<PaletteToolView> PaletteToolManager::CreateViews() { + std::vector<PaletteToolView> views; + views.reserve(tools_.size()); + + for (size_t i = 0; i < tools_.size(); ++i) { + views::View* tool_view = tools_[i]->CreateView(); + if (!tool_view) + continue; + + PaletteToolView view; + view.group = tools_[i]->GetGroup(); + view.tool_id = tools_[i]->GetToolId(); + view.view = tool_view; + views.push_back(view); + } + + return views; +} + +void PaletteToolManager::NotifyViewsDestroyed() { + for (std::unique_ptr<PaletteTool>& tool : tools_) + tool->OnViewDestroyed(); +} + +void PaletteToolManager::DisableActiveTool(PaletteGroup group) { + PaletteToolId tool_id = GetActiveTool(group); + if (tool_id != PaletteToolId::NONE) + DeactivateTool(tool_id); +} + +void PaletteToolManager::EnableTool(PaletteToolId tool_id) { + ActivateTool(tool_id); +} + +void PaletteToolManager::DisableTool(PaletteToolId tool_id) { + DeactivateTool(tool_id); +} + +void PaletteToolManager::HidePalette() { + delegate_->HidePalette(); +} + +void PaletteToolManager::HidePaletteImmediately() { + delegate_->HidePaletteImmediately(); +} + +WmWindow* PaletteToolManager::GetWindow() { + return delegate_->GetWindow(); +} + +void PaletteToolManager::RecordPaletteOptionsUsage(PaletteTrayOptions option) { + return delegate_->RecordPaletteOptionsUsage(option); +} + +void PaletteToolManager::RecordPaletteModeCancellation( + PaletteModeCancelType type) { + return delegate_->RecordPaletteModeCancellation(type); +} + +PaletteTool* PaletteToolManager::FindToolById(PaletteToolId tool_id) const { + for (const std::unique_ptr<PaletteTool>& tool : tools_) { + if (tool->GetToolId() == tool_id) + return tool.get(); + } + + return nullptr; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_tool_manager.h b/ash/common/system/chromeos/palette/palette_tool_manager.h new file mode 100644 index 0000000..478b951 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tool_manager.h
@@ -0,0 +1,125 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_TOOL_MANAGER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_TOOL_MANAGER_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "base/callback.h" +#include "base/macros.h" + +namespace views { +class View; +} + +namespace ash { + +class PaletteTool; +enum class PaletteGroup; +enum class PaletteToolId; +class WmWindow; + +struct ASH_EXPORT PaletteToolView { + PaletteGroup group; + PaletteToolId tool_id; + views::View* view; +}; + +class ASH_EXPORT PaletteToolManager : public PaletteTool::Delegate { + public: + class Delegate { + public: + Delegate() {} + virtual ~Delegate() {} + + // Hide the palette (if shown). + virtual void HidePalette() = 0; + + // Hide the palette immediately, ie, do not display a hide animation. + virtual void HidePaletteImmediately() = 0; + + // Called when the active tool has changed. + virtual void OnActiveToolChanged() = 0; + + // Return the window associated with this palette. + virtual WmWindow* GetWindow() = 0; + + // Record usage of each pen palette option. + virtual void RecordPaletteOptionsUsage(ash::PaletteTrayOptions option) = 0; + + // Record mode cancellation of pen palette. + virtual void RecordPaletteModeCancellation(PaletteModeCancelType type) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + // Creates the tool manager. + PaletteToolManager(Delegate* delegate); + ~PaletteToolManager() override; + + // Adds the given |tool| to the tool manager. The tool is assumed to be in a + // deactivated state. This class takes ownership over |tool|. + void AddTool(std::unique_ptr<PaletteTool> tool); + + // Activates tool_id and deactivates any other active tool in the same + // group as tool_id. + void ActivateTool(PaletteToolId tool_id); + + // Deactivates the given tool. + void DeactivateTool(PaletteToolId tool_id); + + // Returns true if the given tool is active. + bool IsToolActive(PaletteToolId tool_id); + + // Returns the active tool for the given group. + PaletteToolId GetActiveTool(PaletteGroup group); + + // Fetch the active tray icon for the given tool. Returns + // gfx::VectorIconId::VECTOR_ICON_NONE if not available. + const gfx::VectorIcon& GetActiveTrayIcon(PaletteToolId tool_id) const; + + // Create views for all of the registered tools. + std::vector<PaletteToolView> CreateViews(); + + // Called when the views returned by CreateViews have been destroyed. This + // should clear any (now) stale references. + void NotifyViewsDestroyed(); + + // Helper method to disable any active tool in the given |group|. + void DisableActiveTool(PaletteGroup group); + + private: + // PaleteTool::Delegate overrides. + void EnableTool(PaletteToolId tool_id) override; + void DisableTool(PaletteToolId tool_id) override; + void HidePalette() override; + void HidePaletteImmediately() override; + WmWindow* GetWindow() override; + void RecordPaletteOptionsUsage(ash::PaletteTrayOptions option) override; + void RecordPaletteModeCancellation(PaletteModeCancelType type) override; + + PaletteTool* FindToolById(PaletteToolId tool_id) const; + + // Unowned pointer to the delegate to provide external functionality. + Delegate* delegate_; + + // Unowned pointer to the active tool / group. + std::map<PaletteGroup, PaletteTool*> active_tools_; + + // Owned list of all tools. + std::vector<std::unique_ptr<PaletteTool>> tools_; + + DISALLOW_COPY_AND_ASSIGN(PaletteToolManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_TOOL_MANAGER_H_
diff --git a/ash/common/system/chromeos/palette/palette_tool_manager_unittest.cc b/ash/common/system/chromeos/palette/palette_tool_manager_unittest.cc new file mode 100644 index 0000000..0a386203 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tool_manager_unittest.cc
@@ -0,0 +1,137 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "ash/common/system/chromeos/palette/palette_tool_manager.h" +#include "base/bind.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +using namespace ash; + +namespace { + +// A simple tool instance that exposes some additional data for testing. +class TestTool : public PaletteTool { + public: + TestTool(Delegate* delegate, PaletteGroup group, PaletteToolId tool_id) + : PaletteTool(delegate), group_(group), tool_id_(tool_id) {} + + // PaletteTool: + PaletteGroup GetGroup() const override { return group_; } + PaletteToolId GetToolId() const override { return tool_id_; } + + // Shadows the parent declaration since PaletteTool::enabled is not virtual. + bool enabled() const { return PaletteTool::enabled(); } + + private: + // PaletteTool: + views::View* CreateView() override { + NOTREACHED(); + return nullptr; + } + void OnViewDestroyed() override { FAIL(); } + + PaletteGroup group_; + PaletteToolId tool_id_; + + DISALLOW_COPY_AND_ASSIGN(TestTool); +}; + +// Base class for tool manager unittests. +class PaletteToolManagerTest : public ::testing::Test, + public PaletteToolManager::Delegate, + public PaletteTool::Delegate { + public: + PaletteToolManagerTest() + : palette_tool_manager_(new PaletteToolManager(this)) {} + ~PaletteToolManagerTest() override {} + + protected: + // PaletteToolManager::Delegate: + void HidePalette() override {} + void HidePaletteImmediately() override {} + void OnActiveToolChanged() override { ++tool_changed_count_; } + WmWindow* GetWindow() override { + NOTREACHED(); + return nullptr; + } + void RecordPaletteOptionsUsage(PaletteTrayOptions option) override {} + void RecordPaletteModeCancellation(PaletteModeCancelType type) override {} + + // PaletteTool::Delegate: + void EnableTool(PaletteToolId tool_id) override {} + void DisableTool(PaletteToolId tool_id) override {} + + // Helper method for returning an unowned pointer to the constructed tool + // while also adding it to the PaletteToolManager. + TestTool* BuildTool(PaletteGroup group, PaletteToolId tool_id) { + auto* tool = new TestTool(this, group, tool_id); + palette_tool_manager_->AddTool(base::WrapUnique(tool)); + return tool; + } + + int tool_changed_count_ = 0; + std::unique_ptr<PaletteToolManager> palette_tool_manager_; + + private: + DISALLOW_COPY_AND_ASSIGN(PaletteToolManagerTest); +}; + +} // namespace + +// Verifies that tools can be enabled/disabled and that enabling a tool disables +// only active tools in the same group. +TEST_F(PaletteToolManagerTest, MultipleToolsActivateDeactivate) { + // Register actions/modes. + TestTool* action_1 = + BuildTool(PaletteGroup::ACTION, PaletteToolId::CREATE_NOTE); + TestTool* action_2 = + BuildTool(PaletteGroup::ACTION, PaletteToolId::CAPTURE_REGION); + TestTool* mode_1 = BuildTool(PaletteGroup::MODE, PaletteToolId::MAGNIFY); + TestTool* mode_2 = + BuildTool(PaletteGroup::MODE, PaletteToolId::LASER_POINTER); + + // Enable mode 1. + EXPECT_EQ(0, tool_changed_count_); + palette_tool_manager_->ActivateTool(mode_1->GetToolId()); + EXPECT_FALSE(action_1->enabled()); + EXPECT_FALSE(action_2->enabled()); + EXPECT_TRUE(mode_1->enabled()); + EXPECT_FALSE(mode_2->enabled()); + + // Turn a single action on/off. Enabling/disabling the tool does not change + // any other group's state. + palette_tool_manager_->ActivateTool(action_1->GetToolId()); + EXPECT_TRUE(action_1->enabled()); + EXPECT_FALSE(action_2->enabled()); + EXPECT_TRUE(mode_1->enabled()); + EXPECT_FALSE(mode_2->enabled()); + palette_tool_manager_->DeactivateTool(action_1->GetToolId()); + EXPECT_FALSE(action_1->enabled()); + EXPECT_FALSE(action_2->enabled()); + EXPECT_TRUE(mode_1->enabled()); + EXPECT_FALSE(mode_2->enabled()); + + // Activating a tool on will deactivate any other active tools in the same + // group. + palette_tool_manager_->ActivateTool(action_1->GetToolId()); + EXPECT_TRUE(action_1->enabled()); + EXPECT_FALSE(action_2->enabled()); + palette_tool_manager_->ActivateTool(action_2->GetToolId()); + EXPECT_FALSE(action_1->enabled()); + EXPECT_TRUE(action_2->enabled()); + palette_tool_manager_->DeactivateTool(action_2->GetToolId()); + + // Activating an already active tool will not do anything. + palette_tool_manager_->ActivateTool(action_1->GetToolId()); + EXPECT_TRUE(action_1->enabled()); + EXPECT_FALSE(action_2->enabled()); + palette_tool_manager_->ActivateTool(action_1->GetToolId()); + EXPECT_TRUE(action_1->enabled()); + EXPECT_FALSE(action_2->enabled()); + palette_tool_manager_->DeactivateTool(action_1->GetToolId()); +}
diff --git a/ash/common/system/chromeos/palette/palette_tray.cc b/ash/common/system/chromeos/palette/palette_tray.cc new file mode 100644 index 0000000..b63ad7e --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tray.cc
@@ -0,0 +1,437 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/palette_tray.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/palette/palette_tool_manager.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_bubble_wrapper.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_header_button.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/metrics/histogram_macros.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/events/devices/input_device_manager.h" +#include "ui/events/devices/stylus_state.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +namespace { + +// Padding for tray icon (dp; the button that shows the palette menu). +constexpr int kTrayIconMainAxisInset = 8; +constexpr int kTrayIconCrossAxisInset = 0; + +// Width of the palette itself (dp). +constexpr int kPaletteWidth = 332; + +// Padding at the top/bottom of the palette (dp). +constexpr int kPalettePaddingOnTop = 4; +constexpr int kPalettePaddingOnBottom = 2; + +// Margins between the title view and the edges around it (dp). +constexpr int kPaddingBetweenTitleAndLeftEdge = 12; +constexpr int kPaddingBetweenTitleAndSeparator = 3; + +// Color of the separator. +const SkColor kPaletteSeparatorColor = SkColorSetARGB(0x1E, 0x00, 0x00, 0x00); + +// Returns true if we are in a user session that can show the stylus tools. +bool IsInUserSession() { + SessionStateDelegate* session_state_delegate = + WmShell::Get()->GetSessionStateDelegate(); + return !session_state_delegate->IsUserSessionBlocked() && + session_state_delegate->GetSessionState() == + session_manager::SessionState::ACTIVE && + WmShell::Get()->system_tray_delegate()->GetUserLoginStatus() != + LoginStatus::KIOSK_APP; +} + +class TitleView : public views::View, public views::ButtonListener { + public: + explicit TitleView(PaletteTray* palette_tray) : palette_tray_(palette_tray) { + // TODO(tdanderson|jdufault): Use TriView to handle the layout of the title. + // See crbug.com/614453. + auto* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + SetLayoutManager(box_layout); + + auto* title_label = + new views::Label(l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_TITLE)); + title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + AddChildView(title_label); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); + style.SetupLabel(title_label); + box_layout->SetFlexForView(title_label, 1); + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + help_button_ = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); + settings_button_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, + IDS_ASH_PALETTE_SETTINGS); + } else { + gfx::ImageSkia help_icon = + gfx::CreateVectorIcon(kSystemMenuHelpIcon, kMenuIconColor); + gfx::ImageSkia settings_icon = + gfx::CreateVectorIcon(kSystemMenuSettingsIcon, kMenuIconColor); + + auto* help_button = new ash::TrayPopupHeaderButton( + this, help_icon, IDS_ASH_STATUS_TRAY_HELP); + help_button->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HELP)); + help_button_ = help_button; + + auto* settings_button = new ash::TrayPopupHeaderButton( + this, settings_icon, IDS_ASH_STATUS_TRAY_SETTINGS); + settings_button->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SETTINGS)); + settings_button_ = settings_button; + } + + AddChildView(help_button_); + AddChildView(settings_button_); + } + + ~TitleView() override {} + + private: + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + if (sender == settings_button_) { + palette_tray_->RecordPaletteOptionsUsage( + PaletteTrayOptions::PALETTE_SETTINGS_BUTTON); + WmShell::Get()->system_tray_controller()->ShowPaletteSettings(); + palette_tray_->HidePalette(); + } else if (sender == help_button_) { + palette_tray_->RecordPaletteOptionsUsage( + PaletteTrayOptions::PALETTE_HELP_BUTTON); + WmShell::Get()->system_tray_controller()->ShowPaletteHelp(); + palette_tray_->HidePalette(); + } else { + NOTREACHED(); + } + } + + // Unowned pointers to button views so we can determine which button was + // clicked. + views::View* settings_button_; + views::View* help_button_; + PaletteTray* palette_tray_; + + DISALLOW_COPY_AND_ASSIGN(TitleView); +}; + +} // namespace + +PaletteTray::PaletteTray(WmShelf* wm_shelf) + : TrayBackgroundView(wm_shelf), + palette_tool_manager_(new PaletteToolManager(this)), + weak_factory_(this) { + PaletteTool::RegisterToolInstances(palette_tool_manager_.get()); + + if (MaterialDesignController::IsShelfMaterial()) { + SetInkDropMode(InkDropMode::ON); + SetContentsBackground(false); + } else { + SetContentsBackground(true); + } + + SetLayoutManager(new views::FillLayout()); + icon_ = new views::ImageView(); + UpdateTrayIcon(); + + tray_container()->SetMargin(kTrayIconMainAxisInset, kTrayIconCrossAxisInset); + tray_container()->AddChildView(icon_); + + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->GetSessionStateDelegate()->AddSessionStateObserver(this); + ui::InputDeviceManager::GetInstance()->AddObserver(this); +} + +PaletteTray::~PaletteTray() { + if (bubble_) + bubble_->bubble_view()->reset_delegate(); + + ui::InputDeviceManager::GetInstance()->RemoveObserver(this); + WmShell::Get()->RemoveShellObserver(this); + WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); +} + +bool PaletteTray::PerformAction(const ui::Event& event) { + if (bubble_) { + if (num_actions_in_bubble_ == 0) + RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION); + HidePalette(); + return true; + } + + return ShowPalette(); +} + +bool PaletteTray::ShowPalette() { + if (bubble_) + return false; + + DCHECK(tray_container()); + + views::TrayBubbleView::InitParams init_params(GetAnchorAlignment(), + kPaletteWidth, kPaletteWidth); + init_params.can_activate = true; + init_params.close_on_deactivate = true; + + DCHECK(tray_container()); + + // The views::TrayBubbleView ctor will cause a shelf auto hide update check. + // Make sure to block auto hiding before that check happens. + should_block_shelf_auto_hide_ = true; + + // TODO(tdanderson): Refactor into common row layout code. + // TODO(tdanderson|jdufault): Add material design ripple effects to the menu + // rows. + + // Create and customize bubble view. + views::TrayBubbleView* bubble_view = + views::TrayBubbleView::Create(GetBubbleAnchor(), this, &init_params); + bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets()); + bubble_view->set_margins( + gfx::Insets(kPalettePaddingOnTop, 0, kPalettePaddingOnBottom, 0)); + + // Add title. + auto* title_view = new TitleView(this); + title_view->SetBorder(views::CreateEmptyBorder( + gfx::Insets(0, kPaddingBetweenTitleAndLeftEdge, 0, 0))); + bubble_view->AddChildView(title_view); + + // Add horizontal separator. + views::Separator* separator = new views::Separator(); + separator->SetColor(kPaletteSeparatorColor); + separator->SetBorder(views::CreateEmptyBorder(gfx::Insets( + kPaddingBetweenTitleAndSeparator, 0, kMenuSeparatorVerticalPadding, 0))); + bubble_view->AddChildView(separator); + + // Add palette tools. + // TODO(tdanderson|jdufault): Use SystemMenuButton to get the material design + // ripples. + std::vector<PaletteToolView> views = palette_tool_manager_->CreateViews(); + for (const PaletteToolView& view : views) + bubble_view->AddChildView(view.view); + + // Show the bubble. + bubble_.reset(new ash::TrayBubbleWrapper(this, bubble_view)); + SetIsActive(true); + return true; +} + +bool PaletteTray::ContainsPointInScreen(const gfx::Point& point) { + if (icon_ && icon_->GetBoundsInScreen().Contains(point)) + return true; + + return bubble_ && bubble_->bubble_view()->GetBoundsInScreen().Contains(point); +} + +void PaletteTray::SessionStateChanged(session_manager::SessionState state) { + UpdateIconVisibility(); +} + +void PaletteTray::OnLockStateChanged(bool locked) { + UpdateIconVisibility(); + + // The user can eject the stylus during the lock screen transition, which will + // open the palette. Make sure to close it if that happens. + if (locked) + HidePalette(); +} + +void PaletteTray::ClickedOutsideBubble() { + if (num_actions_in_bubble_ == 0) + RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION); + HidePalette(); +} + +base::string16 PaletteTray::GetAccessibleNameForTray() { + return l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_TITLE); +} + +void PaletteTray::HideBubbleWithView(const views::TrayBubbleView* bubble_view) { + if (bubble_->bubble_view() == bubble_view) + HidePalette(); +} + +void PaletteTray::OnTouchscreenDeviceConfigurationChanged() { + UpdateIconVisibility(); +} + +void PaletteTray::OnStylusStateChanged(ui::StylusState stylus_state) { + PaletteDelegate* palette_delegate = WmShell::Get()->palette_delegate(); + + // Don't do anything if the palette should not be shown or if the user has + // disabled it all-together. + if (!IsInUserSession() || !palette_delegate->ShouldShowPalette()) + return; + + // Auto show/hide the palette if allowed by the user. + if (palette_delegate->ShouldAutoOpenPalette()) { + if (stylus_state == ui::StylusState::REMOVED && !bubble_) { + is_bubble_auto_opened_ = true; + ShowPalette(); + } else if (stylus_state == ui::StylusState::INSERTED && bubble_) { + HidePalette(); + } + } + + // Disable any active modes if the stylus has been inserted. + if (stylus_state == ui::StylusState::INSERTED) + palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); +} + +void PaletteTray::BubbleViewDestroyed() { + palette_tool_manager_->NotifyViewsDestroyed(); + SetIsActive(false); +} + +void PaletteTray::OnMouseEnteredView() {} + +void PaletteTray::OnMouseExitedView() {} + +base::string16 PaletteTray::GetAccessibleNameForBubble() { + return GetAccessibleNameForTray(); +} + +void PaletteTray::OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const { + // Place the bubble in the same root window as |anchor_widget|. + WmWindow::Get(anchor_widget->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + bubble_widget, kShellWindowId_SettingBubbleContainer, params); +} + +void PaletteTray::HideBubble(const views::TrayBubbleView* bubble_view) { + HideBubbleWithView(bubble_view); +} + +void PaletteTray::HidePalette() { + should_block_shelf_auto_hide_ = false; + is_bubble_auto_opened_ = false; + num_actions_in_bubble_ = 0; + bubble_.reset(); + + shelf()->UpdateAutoHideState(); +} + +void PaletteTray::HidePaletteImmediately() { + if (bubble_) + bubble_->bubble_widget()->SetVisibilityChangedAnimationsEnabled(false); + HidePalette(); +} + +void PaletteTray::RecordPaletteOptionsUsage(PaletteTrayOptions option) { + DCHECK_NE(option, PaletteTrayOptions::PALETTE_OPTIONS_COUNT); + + if (is_bubble_auto_opened_) { + UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Usage.AutoOpened", option, + PaletteTrayOptions::PALETTE_OPTIONS_COUNT); + } else { + UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Usage", option, + PaletteTrayOptions::PALETTE_OPTIONS_COUNT); + } +} + +void PaletteTray::RecordPaletteModeCancellation(PaletteModeCancelType type) { + if (type == PaletteModeCancelType::PALETTE_MODE_CANCEL_TYPE_COUNT) + return; + + UMA_HISTOGRAM_ENUMERATION( + "Ash.Shelf.Palette.ModeCancellation", type, + PaletteModeCancelType::PALETTE_MODE_CANCEL_TYPE_COUNT); +} + +bool PaletteTray::ShouldBlockShelfAutoHide() const { + return should_block_shelf_auto_hide_; +} + +void PaletteTray::OnActiveToolChanged() { + ++num_actions_in_bubble_; + UpdateTrayIcon(); +} + +WmWindow* PaletteTray::GetWindow() { + return shelf()->GetWindow(); +} + +void PaletteTray::SetShelfAlignment(ShelfAlignment alignment) { + if (alignment == shelf_alignment()) + return; + + TrayBackgroundView::SetShelfAlignment(alignment); +} + +void PaletteTray::AnchorUpdated() { + if (bubble_) + bubble_->bubble_view()->UpdateBubble(); +} + +void PaletteTray::Initialize() { + PaletteDelegate* delegate = WmShell::Get()->palette_delegate(); + // |delegate| can be null in tests. + if (!delegate) + return; + + // OnPaletteEnabledPrefChanged will get called with the initial pref value, + // which will take care of showing the palette. + palette_enabled_subscription_ = delegate->AddPaletteEnableListener(base::Bind( + &PaletteTray::OnPaletteEnabledPrefChanged, weak_factory_.GetWeakPtr())); +} + +void PaletteTray::UpdateTrayIcon() { + icon_->SetImage(CreateVectorIcon( + palette_tool_manager_->GetActiveTrayIcon( + palette_tool_manager_->GetActiveTool(ash::PaletteGroup::MODE)), + kTrayIconSize, kShelfIconColor)); +} + +void PaletteTray::OnPaletteEnabledPrefChanged(bool enabled) { + is_palette_enabled_ = enabled; + + if (!enabled) { + SetVisible(false); + palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); + } else { + UpdateIconVisibility(); + } +} + +void PaletteTray::UpdateIconVisibility() { + SetVisible(is_palette_enabled_ && palette_utils::HasStylusInput() && + IsInUserSession()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_tray.h b/ash/common/system/chromeos/palette/palette_tray.h new file mode 100644 index 0000000..b18c329 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_tray.h
@@ -0,0 +1,144 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_BUTTON_TRAY_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_BUTTON_TRAY_H_ + +#include <map> +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/palette_delegate.h" +#include "ash/common/session/session_state_observer.h" +#include "ash/common/shell_observer.h" +#include "ash/common/system/chromeos/palette/palette_tool_manager.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "ui/events/devices/input_device_event_observer.h" + +namespace gfx { +class Point; +} + +namespace views { +class ImageView; +class Widget; +} + +namespace ash { + +class TrayBubbleWrapper; +class PaletteToolManager; + +// The PaletteTray shows the palette in the bottom area of the screen. This +// class also controls the lifetime for all of the tools available in the +// palette. +class ASH_EXPORT PaletteTray : public TrayBackgroundView, + public SessionStateObserver, + public ShellObserver, + public PaletteToolManager::Delegate, + public ui::InputDeviceEventObserver, + public views::TrayBubbleView::Delegate { + public: + explicit PaletteTray(WmShelf* wm_shelf); + ~PaletteTray() override; + + // ActionableView: + bool PerformAction(const ui::Event& event) override; + + // SessionStateObserver: + void SessionStateChanged(session_manager::SessionState state) override; + + // ShellObserver: + void OnLockStateChanged(bool locked) override; + + // TrayBackgroundView: + void ClickedOutsideBubble() override; + base::string16 GetAccessibleNameForTray() override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void SetShelfAlignment(ShelfAlignment alignment) override; + void AnchorUpdated() override; + void Initialize() override; + + // PaletteToolManager::Delegate: + void HidePalette() override; + void HidePaletteImmediately() override; + void RecordPaletteOptionsUsage(PaletteTrayOptions option) override; + void RecordPaletteModeCancellation(PaletteModeCancelType type) override; + + // Returns true if the shelf should not autohide. + bool ShouldBlockShelfAutoHide() const; + + // Opens up the palette if it is not already open. Returns true if the palette + // was opened. + bool ShowPalette(); + + // Returns true if the palette tray contains the given point. This is useful + // for determining if an event should be propagated through to the palette. + bool ContainsPointInScreen(const gfx::Point& point); + + private: + // ui::InputDeviceObserver: + void OnTouchscreenDeviceConfigurationChanged() override; + void OnStylusStateChanged(ui::StylusState stylus_state) override; + + // views::TrayBubbleView::Delegate: + void BubbleViewDestroyed() override; + void OnMouseEnteredView() override; + void OnMouseExitedView() override; + base::string16 GetAccessibleNameForBubble() override; + void OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const override; + void HideBubble(const views::TrayBubbleView* bubble_view) override; + + // PaletteToolManager::Delegate: + void OnActiveToolChanged() override; + WmWindow* GetWindow() override; + + // Updates the tray icon from the palette tool manager. + void UpdateTrayIcon(); + + // Sets the icon to visible if the palette can be used. + void UpdateIconVisibility(); + + // Called when the palette enabled pref has changed. + void OnPaletteEnabledPrefChanged(bool enabled); + + std::unique_ptr<PaletteToolManager> palette_tool_manager_; + std::unique_ptr<TrayBubbleWrapper> bubble_; + + // Manages the callback OnPaletteEnabledPrefChanged callback registered to + // the PaletteDelegate instance. + std::unique_ptr<PaletteDelegate::EnableListenerSubscription> + palette_enabled_subscription_; + + // Weak pointer, will be parented by TrayContainer for its lifetime. + views::ImageView* icon_; + + // The shelf auto-hide state is checked during the tray constructor, so we + // have to use a helper variable instead of just checking if we have a tray + // instance. + bool should_block_shelf_auto_hide_ = false; + + // Cached palette enabled/disabled pref value. + bool is_palette_enabled_ = true; + + // Used to indicate whether the palette bubble is automatically opened by a + // stylus eject event. + bool is_bubble_auto_opened_ = false; + + // Number of actions in pen palette bubble. + int num_actions_in_bubble_ = 0; + + base::WeakPtrFactory<PaletteTray> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PaletteTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_BUTTON_TRAY_H_
diff --git a/ash/common/system/chromeos/palette/palette_utils.cc b/ash/common/system/chromeos/palette/palette_utils.cc new file mode 100644 index 0000000..f32e40c --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_utils.cc
@@ -0,0 +1,56 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/palette_utils.h" + +#include "ash/common/ash_switches.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/chromeos/palette/palette_tray.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/command_line.h" +#include "ui/events/devices/input_device_manager.h" +#include "ui/events/devices/touchscreen_device.h" +#include "ui/gfx/geometry/point.h" + +namespace ash { +namespace palette_utils { + +bool HasStylusInput() { + // Allow the user to force-enable by passing a switch. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshForceEnablePalette)) { + return true; + } + + for (const ui::TouchscreenDevice& device : + ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) { + if (device.is_stylus && + device.type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL) { + return true; + } + } + + return false; +} + +bool IsPaletteEnabledOnEveryDisplay() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshEnablePaletteOnAllDisplays); +} + +bool PaletteContainsPointInScreen(const gfx::Point& point) { + for (WmWindow* window : WmShell::Get()->GetAllRootWindows()) { + PaletteTray* palette_tray = + WmShelf::ForWindow(window)->GetStatusAreaWidget()->palette_tray(); + if (palette_tray && palette_tray->ContainsPointInScreen(point)) + return true; + } + + return false; +} + +} // namespace palette_utils +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/palette_utils.h b/ash/common/system/chromeos/palette/palette_utils.h new file mode 100644 index 0000000..5f254814 --- /dev/null +++ b/ash/common/system/chromeos/palette/palette_utils.h
@@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_UTILS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_UTILS_H_ + +#include "ash/ash_export.h" + +namespace gfx { +class Point; +} + +namespace ash { +namespace palette_utils { + +// Returns true if there is a stylus input device on the internal display. This +// will return false even if there is a stylus input device until hardware +// probing is complete (see ui::InputDeviceEventObserver). +ASH_EXPORT bool HasStylusInput(); + +// Returns true if the palette should be shown on every display. +ASH_EXPORT bool IsPaletteEnabledOnEveryDisplay(); + +// Returns true if either the palette icon or the palette widget contain the +// given point (in screen space). +ASH_EXPORT bool PaletteContainsPointInScreen(const gfx::Point& point); + +} // namespace palette_utils +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_PALETTE_UTILS_H_
diff --git a/ash/common/system/chromeos/palette/tools/capture_region_mode.cc b/ash/common/system/chromeos/palette/tools/capture_region_mode.cc new file mode 100644 index 0000000..bdcbb64 --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/capture_region_mode.cc
@@ -0,0 +1,78 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/tools/capture_region_mode.h" + +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/palette_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/system/toast/toast_data.h" +#include "ash/common/system/toast/toast_manager.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +namespace { + +const char kToastId[] = "palette_capture_region"; +const int kToastDurationMs = 2500; + +} // namespace + +CaptureRegionMode::CaptureRegionMode(Delegate* delegate) + : CommonPaletteTool(delegate), weak_factory_(this) {} + +CaptureRegionMode::~CaptureRegionMode() {} + +PaletteGroup CaptureRegionMode::GetGroup() const { + return PaletteGroup::MODE; +} + +PaletteToolId CaptureRegionMode::GetToolId() const { + return PaletteToolId::CAPTURE_REGION; +} + +const gfx::VectorIcon& CaptureRegionMode::GetActiveTrayIcon() const { + return kPaletteTrayIconCaptureRegionIcon; +} + +void CaptureRegionMode::OnEnable() { + CommonPaletteTool::OnEnable(); + + ToastData toast(kToastId, l10n_util::GetStringUTF16( + IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_TOAST), + kToastDurationMs, base::Optional<base::string16>()); + ash::WmShell::Get()->toast_manager()->Show(toast); + + WmShell::Get()->palette_delegate()->TakePartialScreenshot(base::Bind( + &CaptureRegionMode::OnScreenshotDone, weak_factory_.GetWeakPtr())); + delegate()->HidePalette(); +} + +void CaptureRegionMode::OnDisable() { + CommonPaletteTool::OnDisable(); + + // If the user manually cancelled the action we need to make sure to cancel + // the screenshot session as well. + WmShell::Get()->palette_delegate()->CancelPartialScreenshot(); +} + +views::View* CaptureRegionMode::CreateView() { + return CreateDefaultView( + l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_ACTION)); +} + +const gfx::VectorIcon& CaptureRegionMode::GetPaletteIcon() const { + return kPaletteActionCaptureRegionIcon; +} + +void CaptureRegionMode::OnScreenshotDone() { + // The screenshot finished, so disable the tool. + delegate()->DisableTool(GetToolId()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/tools/capture_region_mode.h b/ash/common/system/chromeos/palette/tools/capture_region_mode.h new file mode 100644 index 0000000..d2cdc6a --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/capture_region_mode.h
@@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CAPTURE_REGION_ACTION_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CAPTURE_REGION_ACTION_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/palette/common_palette_tool.h" +#include "base/memory/weak_ptr.h" + +namespace ash { + +class ASH_EXPORT CaptureRegionMode : public CommonPaletteTool { + public: + explicit CaptureRegionMode(Delegate* delegate); + ~CaptureRegionMode() override; + + private: + // PaletteTool: + PaletteGroup GetGroup() const override; + PaletteToolId GetToolId() const override; + const gfx::VectorIcon& GetActiveTrayIcon() const override; + void OnEnable() override; + void OnDisable() override; + views::View* CreateView() override; + + // CommonPaletteTool: + const gfx::VectorIcon& GetPaletteIcon() const override; + + void OnScreenshotDone(); + + base::WeakPtrFactory<CaptureRegionMode> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CaptureRegionMode); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CAPTURE_REGION_ACTION_H_
diff --git a/ash/common/system/chromeos/palette/tools/capture_screen_action.cc b/ash/common/system/chromeos/palette/tools/capture_screen_action.cc new file mode 100644 index 0000000..c23e19c --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/capture_screen_action.cc
@@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/tools/capture_screen_action.h" + +#include "ash/common/palette_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +CaptureScreenAction::CaptureScreenAction(Delegate* delegate) + : CommonPaletteTool(delegate) {} + +CaptureScreenAction::~CaptureScreenAction() {} + +PaletteGroup CaptureScreenAction::GetGroup() const { + return PaletteGroup::ACTION; +} + +PaletteToolId CaptureScreenAction::GetToolId() const { + return PaletteToolId::CAPTURE_SCREEN; +} + +void CaptureScreenAction::OnEnable() { + CommonPaletteTool::OnEnable(); + + delegate()->DisableTool(GetToolId()); + delegate()->HidePaletteImmediately(); + WmShell::Get()->palette_delegate()->TakeScreenshot(); +} + +views::View* CaptureScreenAction::CreateView() { + return CreateDefaultView( + l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_CAPTURE_SCREEN_ACTION)); +} + +const gfx::VectorIcon& CaptureScreenAction::GetPaletteIcon() const { + return kPaletteActionCaptureScreenIcon; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/tools/capture_screen_action.h b/ash/common/system/chromeos/palette/tools/capture_screen_action.h new file mode 100644 index 0000000..148b71d2 --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/capture_screen_action.h
@@ -0,0 +1,33 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CAPTURE_SCREEN_ACTION_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CAPTURE_SCREEN_ACTION_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/palette/common_palette_tool.h" + +namespace ash { + +class ASH_EXPORT CaptureScreenAction : public CommonPaletteTool { + public: + explicit CaptureScreenAction(Delegate* delegate); + ~CaptureScreenAction() override; + + private: + // PaletteTool overrides. + PaletteGroup GetGroup() const override; + PaletteToolId GetToolId() const override; + void OnEnable() override; + views::View* CreateView() override; + + // CommonPaletteTool overrides. + const gfx::VectorIcon& GetPaletteIcon() const override; + + DISALLOW_COPY_AND_ASSIGN(CaptureScreenAction); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CAPTURE_SCREEN_ACTION_H_
diff --git a/ash/common/system/chromeos/palette/tools/create_note_action.cc b/ash/common/system/chromeos/palette/tools/create_note_action.cc new file mode 100644 index 0000000..7cb25335 --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/create_note_action.cc
@@ -0,0 +1,50 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/tools/create_note_action.h" + +#include "ash/common/palette_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +CreateNoteAction::CreateNoteAction(Delegate* delegate) + : CommonPaletteTool(delegate) {} + +CreateNoteAction::~CreateNoteAction() {} + +PaletteGroup CreateNoteAction::GetGroup() const { + return PaletteGroup::ACTION; +} + +PaletteToolId CreateNoteAction::GetToolId() const { + return PaletteToolId::CREATE_NOTE; +} + +void CreateNoteAction::OnEnable() { + CommonPaletteTool::OnEnable(); + + WmShell::Get()->palette_delegate()->CreateNote(); + + delegate()->DisableTool(GetToolId()); + delegate()->HidePalette(); +} + +views::View* CreateNoteAction::CreateView() { + if (!WmShell::Get()->palette_delegate()->HasNoteApp()) + return nullptr; + + return CreateDefaultView( + l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_CREATE_NOTE_ACTION)); +} + +const gfx::VectorIcon& CreateNoteAction::GetPaletteIcon() const { + return kPaletteActionCreateNoteIcon; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/tools/create_note_action.h b/ash/common/system/chromeos/palette/tools/create_note_action.h new file mode 100644 index 0000000..0621331 --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/create_note_action.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CREATE_NOTE_ACTION_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CREATE_NOTE_ACTION_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/palette/common_palette_tool.h" +#include "base/macros.h" + +namespace ash { + +// A button in the ash palette that launches the selected note-taking app when +// clicked. This action dynamically hides itself if it is not available. +class ASH_EXPORT CreateNoteAction : public CommonPaletteTool { + public: + explicit CreateNoteAction(Delegate* delegate); + ~CreateNoteAction() override; + + private: + // PaletteTool overrides. + PaletteGroup GetGroup() const override; + PaletteToolId GetToolId() const override; + void OnEnable() override; + views::View* CreateView() override; + + // CommonPaletteTool overrides. + const gfx::VectorIcon& GetPaletteIcon() const override; + + DISALLOW_COPY_AND_ASSIGN(CreateNoteAction); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_CREATE_NOTE_ACTION_H_
diff --git a/ash/common/system/chromeos/palette/tools/create_note_unittest.cc b/ash/common/system/chromeos/palette/tools/create_note_unittest.cc new file mode 100644 index 0000000..3ff21b29 --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/create_note_unittest.cc
@@ -0,0 +1,77 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/mock_palette_tool_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "ash/common/system/chromeos/palette/tools/create_note_action.h" +#include "ash/common/test/test_palette_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "ui/views/view.h" + +namespace ash { + +namespace { + +// Base class for all create note ash tests. +class CreateNoteTest : public test::AshTestBase { + public: + CreateNoteTest() {} + ~CreateNoteTest() override {} + + void SetUp() override { + test::AshTestBase::SetUp(); + + WmShell::Get()->SetPaletteDelegateForTesting( + base::MakeUnique<TestPaletteDelegate>()); + + palette_tool_delegate_ = base::MakeUnique<MockPaletteToolDelegate>(); + tool_ = base::MakeUnique<CreateNoteAction>(palette_tool_delegate_.get()); + } + + TestPaletteDelegate* test_palette_delegate() { + return static_cast<TestPaletteDelegate*>( + WmShell::Get()->palette_delegate()); + } + + protected: + std::unique_ptr<MockPaletteToolDelegate> palette_tool_delegate_; + std::unique_ptr<PaletteTool> tool_; + + private: + DISALLOW_COPY_AND_ASSIGN(CreateNoteTest); +}; + +} // namespace + +// The note tool is only visible when there is a note-taking app available. +TEST_F(CreateNoteTest, ViewOnlyCreatedWhenNoteAppIsAvailable) { + test_palette_delegate()->set_has_note_app(false); + EXPECT_FALSE(tool_->CreateView()); + tool_->OnViewDestroyed(); + + test_palette_delegate()->set_has_note_app(true); + std::unique_ptr<views::View> view = base::WrapUnique(tool_->CreateView()); + EXPECT_TRUE(view); + tool_->OnViewDestroyed(); +} + +// Activating the note tool both creates a note via the delegate and also +// disables the tool and hides the palette. +TEST_F(CreateNoteTest, EnablingToolCreatesNewNoteAndDisablesTool) { + test_palette_delegate()->set_has_note_app(true); + std::unique_ptr<views::View> view = base::WrapUnique(tool_->CreateView()); + + EXPECT_CALL(*palette_tool_delegate_.get(), + DisableTool(PaletteToolId::CREATE_NOTE)); + EXPECT_CALL(*palette_tool_delegate_.get(), HidePalette()); + + tool_->OnEnable(); + EXPECT_EQ(1, test_palette_delegate()->create_note_count()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/tools/laser_pointer_mode.cc b/ash/common/system/chromeos/palette/tools/laser_pointer_mode.cc new file mode 100644 index 0000000..6dae85d --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/laser_pointer_mode.cc
@@ -0,0 +1,55 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/tools/laser_pointer_mode.h" + +#include "ash/common/palette_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +LaserPointerMode::LaserPointerMode(Delegate* delegate) + : CommonPaletteTool(delegate) { +} + +LaserPointerMode::~LaserPointerMode() {} + +PaletteGroup LaserPointerMode::GetGroup() const { + return PaletteGroup::MODE; +} + +PaletteToolId LaserPointerMode::GetToolId() const { + return PaletteToolId::LASER_POINTER; +} + +void LaserPointerMode::OnEnable() { + CommonPaletteTool::OnEnable(); + + WmShell::Get()->SetLaserPointerEnabled(true); + delegate()->HidePalette(); +} + +void LaserPointerMode::OnDisable() { + CommonPaletteTool::OnDisable(); + + WmShell::Get()->SetLaserPointerEnabled(false); +} + +const gfx::VectorIcon& LaserPointerMode::GetActiveTrayIcon() const { + return kPaletteTrayIconLaserPointerIcon; +} + +const gfx::VectorIcon& LaserPointerMode::GetPaletteIcon() const { + return kPaletteModeLaserPointerIcon; +} + +views::View* LaserPointerMode::CreateView() { + return CreateDefaultView( + l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_LASER_POINTER_MODE)); +} +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/tools/laser_pointer_mode.h b/ash/common/system/chromeos/palette/tools/laser_pointer_mode.h new file mode 100644 index 0000000..62c59ef --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/laser_pointer_mode.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_TOOLS_LASER_POINTER_MODE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_TOOLS_LASER_POINTER_MODE_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/palette/common_palette_tool.h" + +namespace ash { + +// Controller for the laser pointer functionality. +class ASH_EXPORT LaserPointerMode : public CommonPaletteTool { + public: + explicit LaserPointerMode(Delegate* delegate); + ~LaserPointerMode() override; + + private: + // PaletteTool: + PaletteGroup GetGroup() const override; + PaletteToolId GetToolId() const override; + void OnEnable() override; + void OnDisable() override; + const gfx::VectorIcon& GetActiveTrayIcon() const override; + views::View* CreateView() override; + + // CommonPaletteTool: + const gfx::VectorIcon& GetPaletteIcon() const override; + + DISALLOW_COPY_AND_ASSIGN(LaserPointerMode); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_TOOLS_LASER_POINTER_MODE_H_
diff --git a/ash/common/system/chromeos/palette/tools/magnifier_mode.cc b/ash/common/system/chromeos/palette/tools/magnifier_mode.cc new file mode 100644 index 0000000..65c750d --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/magnifier_mode.cc
@@ -0,0 +1,53 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/tools/magnifier_mode.h" + +#include "ash/common/palette_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +MagnifierMode::MagnifierMode(Delegate* delegate) + : CommonPaletteTool(delegate) {} + +MagnifierMode::~MagnifierMode() {} + +PaletteGroup MagnifierMode::GetGroup() const { + return PaletteGroup::MODE; +} + +PaletteToolId MagnifierMode::GetToolId() const { + return PaletteToolId::MAGNIFY; +} + +const gfx::VectorIcon& MagnifierMode::GetActiveTrayIcon() const { + return kPaletteTrayIconMagnifyIcon; +} + +void MagnifierMode::OnEnable() { + CommonPaletteTool::OnEnable(); + WmShell::Get()->SetPartialMagnifierEnabled(true); + delegate()->HidePalette(); +} + +void MagnifierMode::OnDisable() { + CommonPaletteTool::OnDisable(); + WmShell::Get()->SetPartialMagnifierEnabled(false); +} + +views::View* MagnifierMode::CreateView() { + return CreateDefaultView( + l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_MAGNIFIER_MODE)); +} + +const gfx::VectorIcon& MagnifierMode::GetPaletteIcon() const { + return kPaletteModeMagnifyIcon; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/palette/tools/magnifier_mode.h b/ash/common/system/chromeos/palette/tools/magnifier_mode.h new file mode 100644 index 0000000..334f8289 --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/magnifier_mode.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_MAGNIFIER_MODE_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_MAGNIFIER_MODE_H_ + +#include "ash/common/system/chromeos/palette/common_palette_tool.h" + +namespace ash { + +// Exposes a palette tool that lets the user enable a partial screen magnifier +// (ie, a spyglass) that dynamically appears when pressing the screen. +class MagnifierMode : public CommonPaletteTool { + public: + explicit MagnifierMode(Delegate* delegate); + ~MagnifierMode() override; + + private: + // PaletteTool overrides. + PaletteGroup GetGroup() const override; + PaletteToolId GetToolId() const override; + const gfx::VectorIcon& GetActiveTrayIcon() const override; + void OnEnable() override; + void OnDisable() override; + views::View* CreateView() override; + + // CommonPaletteTool overrides. + const gfx::VectorIcon& GetPaletteIcon() const override; + + DISALLOW_COPY_AND_ASSIGN(MagnifierMode); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_PALETTE_MAGNIFIER_MODE_H_
diff --git a/ash/common/system/chromeos/palette/tools/screenshot_unittest.cc b/ash/common/system/chromeos/palette/tools/screenshot_unittest.cc new file mode 100644 index 0000000..faf7eae --- /dev/null +++ b/ash/common/system/chromeos/palette/tools/screenshot_unittest.cc
@@ -0,0 +1,81 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/palette/mock_palette_tool_delegate.h" +#include "ash/common/system/chromeos/palette/palette_ids.h" +#include "ash/common/system/chromeos/palette/palette_tool.h" +#include "ash/common/system/chromeos/palette/tools/capture_region_mode.h" +#include "ash/common/system/chromeos/palette/tools/capture_screen_action.h" +#include "ash/common/test/test_palette_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" + +namespace ash { + +namespace { + +// Base class for all create note ash tests. +class ScreenshotToolTest : public test::AshTestBase { + public: + ScreenshotToolTest() {} + ~ScreenshotToolTest() override {} + + void SetUp() override { + test::AshTestBase::SetUp(); + + WmShell::Get()->SetPaletteDelegateForTesting( + base::MakeUnique<TestPaletteDelegate>()); + + palette_tool_delegate_ = base::MakeUnique<MockPaletteToolDelegate>(); + } + + TestPaletteDelegate* test_palette_delegate() { + return static_cast<TestPaletteDelegate*>( + WmShell::Get()->palette_delegate()); + } + + protected: + std::unique_ptr<MockPaletteToolDelegate> palette_tool_delegate_; + + private: + DISALLOW_COPY_AND_ASSIGN(ScreenshotToolTest); +}; + +} // namespace + +// Verifies that capturing a region triggers the partial screenshot delegate +// method. Invoking the callback passed to the delegate disables the tool. +TEST_F(ScreenshotToolTest, EnablingCaptureRegionCallsDelegateAndDisablesTool) { + std::unique_ptr<PaletteTool> tool = + base::MakeUnique<CaptureRegionMode>(palette_tool_delegate_.get()); + + // Starting a partial screenshot calls the calls the palette delegate to start + // a screenshot session and hides the palette. + EXPECT_CALL(*palette_tool_delegate_.get(), HidePalette()); + tool->OnEnable(); + EXPECT_EQ(1, test_palette_delegate()->take_partial_screenshot_count()); + testing::Mock::VerifyAndClearExpectations(palette_tool_delegate_.get()); + + // Calling the associated callback (partial screenshot finished) will disable + // the tool. + EXPECT_CALL(*palette_tool_delegate_.get(), + DisableTool(PaletteToolId::CAPTURE_REGION)); + test_palette_delegate()->partial_screenshot_done().Run(); +} + +// Verifies that capturing the screen triggers the screenshot delegate method, +// disables the tool, and hides the palette. +TEST_F(ScreenshotToolTest, EnablingCaptureScreenCallsDelegateAndDisablesTool) { + std::unique_ptr<PaletteTool> tool = + base::MakeUnique<CaptureScreenAction>(palette_tool_delegate_.get()); + EXPECT_CALL(*palette_tool_delegate_.get(), + DisableTool(PaletteToolId::CAPTURE_SCREEN)); + EXPECT_CALL(*palette_tool_delegate_.get(), HidePaletteImmediately()); + tool->OnEnable(); + EXPECT_EQ(1, test_palette_delegate()->take_screenshot_count()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/battery_notification.cc b/ash/common/system/chromeos/power/battery_notification.cc new file mode 100644 index 0000000..23395ff --- /dev/null +++ b/ash/common/system/chromeos/power/battery_notification.cc
@@ -0,0 +1,111 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/battery_notification.h" + +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/system_notifier.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/i18n/message_formatter.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" + +using message_center::MessageCenter; +using message_center::Notification; + +namespace ash { + +namespace { + +const char kBatteryNotificationId[] = "battery"; + +gfx::Image& GetBatteryImage(TrayPower::NotificationState notification_state) { + int resource_id; + if (PowerStatus::Get()->IsUsbChargerConnected()) { + resource_id = IDR_AURA_NOTIFICATION_BATTERY_FLUCTUATING; + } else if (notification_state == TrayPower::NOTIFICATION_LOW_POWER) { + resource_id = IDR_AURA_NOTIFICATION_BATTERY_LOW; + } else if (notification_state == TrayPower::NOTIFICATION_CRITICAL) { + resource_id = IDR_AURA_NOTIFICATION_BATTERY_CRITICAL; + } else { + NOTREACHED(); + resource_id = 0; + } + + return ui::ResourceBundle::GetSharedInstance().GetImageNamed(resource_id); +} + +std::unique_ptr<Notification> CreateNotification( + TrayPower::NotificationState notification_state) { + const PowerStatus& status = *PowerStatus::Get(); + + base::string16 message = base::i18n::MessageFormatter::FormatWithNumberedArgs( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_PERCENT), + static_cast<double>(status.GetRoundedBatteryPercent()) / 100.0); + + const base::TimeDelta time = status.IsBatteryCharging() + ? status.GetBatteryTimeToFull() + : status.GetBatteryTimeToEmpty(); + base::string16 time_message; + if (status.IsUsbChargerConnected()) { + time_message = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE); + } else if (PowerStatus::ShouldDisplayBatteryTime(time) && + !status.IsBatteryDischargingOnLinePower()) { + if (status.IsBatteryCharging()) { + time_message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL, + TimeDurationFormat(time, base::DURATION_WIDTH_NARROW)); + } else { + // This is a low battery warning prompting the user in minutes. + time_message = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING, + ui::TimeFormat::LENGTH_LONG, time); + } + } + + if (!time_message.empty()) + message = message + base::ASCIIToUTF16("\n") + time_message; + + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kBatteryNotificationId, + base::string16(), message, GetBatteryImage(notification_state), + base::string16(), GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierBattery), + message_center::RichNotificationData(), NULL)); + notification->SetSystemPriority(); + return notification; +} + +} // namespace + +BatteryNotification::BatteryNotification( + MessageCenter* message_center, + TrayPower::NotificationState notification_state) + : message_center_(message_center) { + message_center_->AddNotification(CreateNotification(notification_state)); +} + +BatteryNotification::~BatteryNotification() { + if (message_center_->FindVisibleNotificationById(kBatteryNotificationId)) + message_center_->RemoveNotification(kBatteryNotificationId, false); +} + +void BatteryNotification::Update( + TrayPower::NotificationState notification_state) { + if (message_center_->FindVisibleNotificationById(kBatteryNotificationId)) { + message_center_->UpdateNotification(kBatteryNotificationId, + CreateNotification(notification_state)); + } +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/battery_notification.h b/ash/common/system/chromeos/power/battery_notification.h new file mode 100644 index 0000000..fa698320 --- /dev/null +++ b/ash/common/system/chromeos/power/battery_notification.h
@@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/power/tray_power.h" +#include "base/macros.h" + +namespace message_center { +class MessageCenter; +} + +namespace ash { + +// Class for showing and hiding a MessageCenter low battery notification. +class ASH_EXPORT BatteryNotification { + public: + BatteryNotification(message_center::MessageCenter* message_center, + TrayPower::NotificationState notification_state); + ~BatteryNotification(); + + // Updates the notification if it still exists. + void Update(TrayPower::NotificationState notification_state); + + private: + message_center::MessageCenter* message_center_; + + DISALLOW_COPY_AND_ASSIGN(BatteryNotification); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_POWER_BATTERY_NOTIFICATION_H_
diff --git a/ash/common/system/chromeos/power/dual_role_notification.cc b/ash/common/system/chromeos/power/dual_role_notification.cc new file mode 100644 index 0000000..7baaaa57 --- /dev/null +++ b/ash/common/system/chromeos/power/dual_role_notification.cc
@@ -0,0 +1,157 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/dual_role_notification.h" + +#include <set> + +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" + +using message_center::MessageCenter; +using message_center::Notification; + +namespace ash { +namespace { + +const char kDualRoleNotificationId[] = "dual-role"; + +// Opens power settings on click. +class DualRoleNotificationDelegate + : public message_center::NotificationDelegate { + public: + DualRoleNotificationDelegate() {} + + // Overridden from message_center::NotificationDelegate. + void Click() override { + WmShell::Get()->system_tray_controller()->ShowPowerSettings(); + } + + private: + ~DualRoleNotificationDelegate() override {} + + DISALLOW_COPY_AND_ASSIGN(DualRoleNotificationDelegate); +}; + +} // namespace + +DualRoleNotification::DualRoleNotification(MessageCenter* message_center) + : message_center_(message_center), + num_dual_role_sinks_(0), + line_power_connected_(false) {} + +DualRoleNotification::~DualRoleNotification() { + if (message_center_->FindVisibleNotificationById(kDualRoleNotificationId)) + message_center_->RemoveNotification(kDualRoleNotificationId, false); +} + +void DualRoleNotification::Update() { + const PowerStatus& status = *PowerStatus::Get(); + DCHECK(status.HasDualRoleDevices()); + + std::string current_power_source_id = status.GetCurrentPowerSourceID(); + + std::unique_ptr<PowerStatus::PowerSource> new_source; + std::unique_ptr<PowerStatus::PowerSource> new_sink; + size_t num_sinks_found = 0; + for (const auto& source : status.GetPowerSources()) { + // The power source can't be changed if there's a dedicated charger. + if (source.type == PowerStatus::DEDICATED_CHARGER) { + dual_role_source_.reset(); + line_power_connected_ = true; + if (message_center_->FindVisibleNotificationById(kDualRoleNotificationId)) + message_center_->RemoveNotification(kDualRoleNotificationId, false); + return; + } + + if (source.id == current_power_source_id) { + new_source.reset(new PowerStatus::PowerSource(source)); + continue; + } + num_sinks_found++; + // The notification only shows the sink port if it is the only sink. + if (num_sinks_found == 1) + new_sink.reset(new PowerStatus::PowerSource(source)); + else + new_sink.reset(); + } + + // Check if the notification should change. + bool change = false; + if (PowerStatus::Get()->IsLinePowerConnected() != line_power_connected_) { + change = true; + line_power_connected_ = PowerStatus::Get()->IsLinePowerConnected(); + } else if (new_source && dual_role_source_) { + if (new_source->description_id != dual_role_source_->description_id) + change = true; + } else if (new_source || dual_role_source_) { + change = true; + } else { + // Notification differs for 0, 1, and 2+ sinks. + if ((num_sinks_found < num_dual_role_sinks_ && num_sinks_found < 2) || + (num_sinks_found > num_dual_role_sinks_ && num_dual_role_sinks_ < 2)) { + change = true; + } else if (num_sinks_found == 1) { + // The description matters if there's only one dual-role device. + change = new_sink->description_id != dual_role_sink_->description_id; + } + } + + dual_role_source_ = std::move(new_source); + dual_role_sink_ = std::move(new_sink); + num_dual_role_sinks_ = num_sinks_found; + + if (!change) + return; + + if (!message_center_->FindVisibleNotificationById(kDualRoleNotificationId)) { + message_center_->AddNotification(CreateNotification()); + } else { + message_center_->UpdateNotification(kDualRoleNotificationId, + CreateNotification()); + } +} + +std::unique_ptr<Notification> DualRoleNotification::CreateNotification() { + base::string16 title; + if (dual_role_source_) { + title = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_CHARGING_FROM_DUAL_ROLE_TITLE, + l10n_util::GetStringUTF16(dual_role_source_->description_id)); + } else if (num_dual_role_sinks_ == 1) { + title = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_CHARGING_DUAL_ROLE_DEVICE_TITLE, + l10n_util::GetStringUTF16(dual_role_sink_->description_id)); + } else { + title = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_CHARGING_DUAL_ROLE_DEVICES_TITLE); + } + + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kDualRoleNotificationId, title, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DUAL_ROLE_MESSAGE), + ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_AURA_NOTIFICATION_LOW_POWER_CHARGER), + base::string16(), GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierDualRole), + message_center::RichNotificationData(), + new DualRoleNotificationDelegate)); + notification->set_priority(message_center::MIN_PRIORITY); + return notification; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/dual_role_notification.h b/ash/common/system/chromeos/power/dual_role_notification.h new file mode 100644 index 0000000..a648783 --- /dev/null +++ b/ash/common/system/chromeos/power/dual_role_notification.h
@@ -0,0 +1,48 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_ + +#include <stddef.h> + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "base/macros.h" + +namespace message_center { +class MessageCenter; +class Notification; +} + +namespace ash { + +// Shows a non-toasting MessageCenter notification based on what dual-role +// devices are connected. +class ASH_EXPORT DualRoleNotification { + public: + explicit DualRoleNotification(message_center::MessageCenter* message_center); + ~DualRoleNotification(); + + // Creates or updates the notification. + void Update(); + + private: + // Creates the notification using the updated status. + std::unique_ptr<message_center::Notification> CreateNotification(); + + message_center::MessageCenter* message_center_; + std::unique_ptr<PowerStatus::PowerSource> dual_role_source_; + std::unique_ptr<PowerStatus::PowerSource> dual_role_sink_; + size_t num_dual_role_sinks_; + bool line_power_connected_; + + DISALLOW_COPY_AND_ASSIGN(DualRoleNotification); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_POWER_DUAL_ROLE_NOTIFICATION_H_
diff --git a/ash/common/system/chromeos/power/power_status.cc b/ash/common/system/chromeos/power/power_status.cc new file mode 100644 index 0000000..d7dd534 --- /dev/null +++ b/ash/common/system/chromeos/power/power_status.cc
@@ -0,0 +1,518 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/power_status.h" + +#include <algorithm> +#include <cmath> + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/paint_vector_icon.h" + +namespace ash { +namespace { + +// Updates |proto| to ensure that its fields are consistent. +void SanitizeProto(power_manager::PowerSupplyProperties* proto) { + DCHECK(proto); + + if (proto->battery_state() == + power_manager::PowerSupplyProperties_BatteryState_FULL) + proto->set_battery_percent(100.0); + + if (!proto->is_calculating_battery_time()) { + const bool on_line_power = + proto->external_power() != + power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED; + if ((on_line_power && proto->battery_time_to_full_sec() < 0) || + (!on_line_power && proto->battery_time_to_empty_sec() < 0)) + proto->set_is_calculating_battery_time(true); + } +} + +base::string16 GetBatteryTimeAccessibilityString(int hour, int min) { + DCHECK(hour || min); + if (hour && !min) { + return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, + base::TimeDelta::FromHours(hour)); + } + if (min && !hour) { + return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, + base::TimeDelta::FromMinutes(min)); + } + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_TIME_ACCESSIBLE, + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, + base::TimeDelta::FromHours(hour)), + ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, + base::TimeDelta::FromMinutes(min))); +} + +int PowerSourceToMessageID( + const power_manager::PowerSupplyProperties_PowerSource& source) { + switch (source.port()) { + case power_manager::PowerSupplyProperties_PowerSource_Port_UNKNOWN: + return IDS_ASH_POWER_SOURCE_PORT_UNKNOWN; + case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT: + return IDS_ASH_POWER_SOURCE_PORT_LEFT; + case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT: + return IDS_ASH_POWER_SOURCE_PORT_RIGHT; + case power_manager::PowerSupplyProperties_PowerSource_Port_BACK: + return IDS_ASH_POWER_SOURCE_PORT_BACK; + case power_manager::PowerSupplyProperties_PowerSource_Port_FRONT: + return IDS_ASH_POWER_SOURCE_PORT_FRONT; + case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT_FRONT: + return IDS_ASH_POWER_SOURCE_PORT_LEFT_FRONT; + case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT_BACK: + return IDS_ASH_POWER_SOURCE_PORT_LEFT_BACK; + case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT_FRONT: + return IDS_ASH_POWER_SOURCE_PORT_RIGHT_FRONT; + case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT_BACK: + return IDS_ASH_POWER_SOURCE_PORT_RIGHT_BACK; + case power_manager::PowerSupplyProperties_PowerSource_Port_BACK_LEFT: + return IDS_ASH_POWER_SOURCE_PORT_BACK_LEFT; + case power_manager::PowerSupplyProperties_PowerSource_Port_BACK_RIGHT: + return IDS_ASH_POWER_SOURCE_PORT_BACK_RIGHT; + } + NOTREACHED(); + return 0; +} + +const gfx::VectorIcon& VectorIconForIconBadge( + PowerStatus::IconBadge icon_badge) { + switch (icon_badge) { + case PowerStatus::ICON_BADGE_NONE: + return gfx::kNoneIcon; + case PowerStatus::ICON_BADGE_ALERT: + return kSystemTrayBatteryAlertIcon; + case PowerStatus::ICON_BADGE_BOLT: + return kSystemTrayBatteryBoltIcon; + case PowerStatus::ICON_BADGE_X: + return kSystemTrayBatteryXIcon; + case PowerStatus::ICON_BADGE_UNRELIABLE: + return kSystemTrayBatteryUnreliableIcon; + } + NOTREACHED(); + return gfx::kNoneIcon; +} + +static PowerStatus* g_power_status = NULL; + +// Minimum battery percentage rendered in UI. +const int kMinBatteryPercent = 1; + +// Width and height of battery images. +const int kBatteryImageHeight = 25; +const int kBatteryImageWidth = 25; + +// Number of different power states. +const int kNumPowerImages = 15; + +// The height of the battery icon in material design (as measured from the +// user-visible bottom of the icon to the user-visible top of the icon). +const int kBatteryImageHeightMd = 12; + +// The dimensions of the canvas containing the material design battery icon. +const int kBatteryCanvasSizeMd = 16; + +// The minimum height (in dp) of the charged region of the material design +// battery icon when the battery is present and has a charge greater than 0. +const int kMinVisualChargeLevelMd = 1; + +// The empty background color of the battery icon in the system tray. Used +// for material design. +// TODO(tdanderson): Move these constants to a shared location if they are +// shared by more than one material design system icon. +const SkColor kBatteryBaseColor = SkColorSetA(SK_ColorWHITE, 0x4C); + +// The background color of the charged region of the battery in the system +// tray. Used for material design. +const SkColor kBatteryChargeColor = SK_ColorWHITE; + +// The color of the battery's badge (bolt, unreliable, X). +const SkColor kBatteryBadgeColor = SkColorSetA(SK_ColorBLACK, 0xB2); + +// The color used for the battery's badge and charged color when the battery +// charge level is critically low. +const SkColor kBatteryAlertColor = SkColorSetRGB(0xDA, 0x27, 0x12); + +} // namespace + +bool PowerStatus::BatteryImageInfo::operator==( + const BatteryImageInfo& o) const { + if (ash::MaterialDesignController::UseMaterialDesignSystemIcons()) + return icon_badge == o.icon_badge && charge_level == o.charge_level; + + // TODO(tdanderson): |resource_id|, |offset|, and |index| are only used for + // non-MD. Remove these once MD is enabled by default. See crbug.com/614453. + return resource_id == o.resource_id && offset == o.offset && index == o.index; +} + +const int PowerStatus::kMaxBatteryTimeToDisplaySec = 24 * 60 * 60; + +const double PowerStatus::kCriticalBatteryChargePercentageMd = 5; + +// static +void PowerStatus::Initialize() { + CHECK(!g_power_status); + g_power_status = new PowerStatus(); +} + +// static +void PowerStatus::Shutdown() { + CHECK(g_power_status); + delete g_power_status; + g_power_status = NULL; +} + +// static +bool PowerStatus::IsInitialized() { + return g_power_status != NULL; +} + +// static +PowerStatus* PowerStatus::Get() { + CHECK(g_power_status) << "PowerStatus::Get() called before Initialize()."; + return g_power_status; +} + +// static +bool PowerStatus::ShouldDisplayBatteryTime(const base::TimeDelta& time) { + return time >= base::TimeDelta::FromMinutes(1) && + time.InSeconds() <= kMaxBatteryTimeToDisplaySec; +} + +// static +void PowerStatus::SplitTimeIntoHoursAndMinutes(const base::TimeDelta& time, + int* hours, + int* minutes) { + DCHECK(hours); + DCHECK(minutes); + const int total_minutes = static_cast<int>(time.InSecondsF() / 60 + 0.5); + *hours = total_minutes / 60; + *minutes = total_minutes % 60; +} + +void PowerStatus::AddObserver(Observer* observer) { + DCHECK(observer); + observers_.AddObserver(observer); +} + +void PowerStatus::RemoveObserver(Observer* observer) { + DCHECK(observer); + observers_.RemoveObserver(observer); +} + +void PowerStatus::RequestStatusUpdate() { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->RequestStatusUpdate(); +} + +void PowerStatus::SetPowerSource(const std::string& id) { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->SetPowerSource( + id); +} + +bool PowerStatus::IsBatteryPresent() const { + return proto_.battery_state() != + power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT; +} + +bool PowerStatus::IsBatteryFull() const { + return proto_.battery_state() == + power_manager::PowerSupplyProperties_BatteryState_FULL; +} + +bool PowerStatus::IsBatteryCharging() const { + return proto_.battery_state() == + power_manager::PowerSupplyProperties_BatteryState_CHARGING; +} + +bool PowerStatus::IsBatteryDischargingOnLinePower() const { + return IsLinePowerConnected() && + proto_.battery_state() == + power_manager::PowerSupplyProperties_BatteryState_DISCHARGING; +} + +double PowerStatus::GetBatteryPercent() const { + return proto_.battery_percent(); +} + +int PowerStatus::GetRoundedBatteryPercent() const { + return std::max(kMinBatteryPercent, + static_cast<int>(GetBatteryPercent() + 0.5)); +} + +bool PowerStatus::IsBatteryTimeBeingCalculated() const { + return proto_.is_calculating_battery_time(); +} + +base::TimeDelta PowerStatus::GetBatteryTimeToEmpty() const { + return base::TimeDelta::FromSeconds(proto_.battery_time_to_empty_sec()); +} + +base::TimeDelta PowerStatus::GetBatteryTimeToFull() const { + return base::TimeDelta::FromSeconds(proto_.battery_time_to_full_sec()); +} + +bool PowerStatus::IsLinePowerConnected() const { + return proto_.external_power() != + power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED; +} + +bool PowerStatus::IsMainsChargerConnected() const { + return proto_.external_power() == + power_manager::PowerSupplyProperties_ExternalPower_AC; +} + +bool PowerStatus::IsUsbChargerConnected() const { + return proto_.external_power() == + power_manager::PowerSupplyProperties_ExternalPower_USB; +} + +bool PowerStatus::SupportsDualRoleDevices() const { + return proto_.supports_dual_role_devices(); +} + +bool PowerStatus::HasDualRoleDevices() const { + if (!SupportsDualRoleDevices()) + return false; + + for (int i = 0; i < proto_.available_external_power_source_size(); i++) { + if (!proto_.available_external_power_source(i).active_by_default()) + return true; + } + return false; +} + +std::vector<PowerStatus::PowerSource> PowerStatus::GetPowerSources() const { + std::vector<PowerSource> sources; + for (int i = 0; i < proto_.available_external_power_source_size(); i++) { + const auto& source = proto_.available_external_power_source(i); + sources.push_back( + {source.id(), + source.active_by_default() ? DEDICATED_CHARGER : DUAL_ROLE_USB, + PowerSourceToMessageID(source)}); + } + return sources; +} + +std::string PowerStatus::GetCurrentPowerSourceID() const { + return proto_.external_power_source_id(); +} + +PowerStatus::BatteryImageInfo PowerStatus::GetBatteryImageInfo( + IconSet icon_set) const { + BatteryImageInfo info; + if (MaterialDesignController::UseMaterialDesignSystemIcons()) + CalculateBatteryImageInfoMd(&info); + else + CalculateBatteryImageInfoNonMd(&info, icon_set); + return info; +} + +void PowerStatus::CalculateBatteryImageInfoMd(BatteryImageInfo* info) const { + if (!IsUsbChargerConnected() && !IsBatteryPresent()) { + info->icon_badge = ICON_BADGE_X; + info->charge_level = 0; + return; + } + + if (IsUsbChargerConnected()) + info->icon_badge = ICON_BADGE_UNRELIABLE; + else if (IsLinePowerConnected()) + info->icon_badge = ICON_BADGE_BOLT; + else + info->icon_badge = ICON_BADGE_NONE; + + // |charge_state| is a value between 0 and kBatteryImageHeightMd representing + // the number of device pixels the battery image should be shown charged. The + // exception is when |charge_state| is 0 (a critically-low battery); in this + // case, still draw 1dp of charge. + int charge_state = + static_cast<int>(GetBatteryPercent() / 100.0 * kBatteryImageHeightMd); + charge_state = std::max(std::min(charge_state, kBatteryImageHeightMd), 0); + info->charge_level = std::max(charge_state, kMinVisualChargeLevelMd); + + // Use ICON_BADGE_ALERT if the battery is critically low and does not already + // have a badge assigned. + if (GetBatteryPercent() < kCriticalBatteryChargePercentageMd && + info->icon_badge == ICON_BADGE_NONE) { + info->icon_badge = ICON_BADGE_ALERT; + } +} + +void PowerStatus::CalculateBatteryImageInfoNonMd( + BatteryImageInfo* info, + const IconSet& icon_set) const { + if (IsUsbChargerConnected()) { + info->resource_id = + (icon_set == ICON_DARK) + ? IDR_AURA_UBER_TRAY_POWER_SMALL_CHARGING_UNRELIABLE_DARK + : IDR_AURA_UBER_TRAY_POWER_SMALL_CHARGING_UNRELIABLE; + } else { + info->resource_id = (icon_set == ICON_DARK) + ? IDR_AURA_UBER_TRAY_POWER_SMALL_DARK + : IDR_AURA_UBER_TRAY_POWER_SMALL; + } + + info->offset = IsUsbChargerConnected() ? 0 : (IsLinePowerConnected() ? 1 : 0); + + if (GetBatteryPercent() >= 100.0) { + info->index = kNumPowerImages - 1; + } else if (!IsBatteryPresent()) { + info->index = kNumPowerImages; + } else { + info->index = + static_cast<int>(GetBatteryPercent() / 100.0 * (kNumPowerImages - 1)); + info->index = std::max(std::min(info->index, kNumPowerImages - 2), 0); + } +} + +gfx::ImageSkia PowerStatus::GetBatteryImage( + const BatteryImageInfo& info) const { + if (!MaterialDesignController::UseMaterialDesignSystemIcons()) + return GetBatteryImageNonMd(info); + + const bool use_alert_color = + (info.charge_level == kMinVisualChargeLevelMd && !IsLinePowerConnected()); + const SkColor badge_color = + use_alert_color ? kBatteryAlertColor : kBatteryBadgeColor; + const SkColor charge_color = + use_alert_color ? kBatteryAlertColor : kBatteryChargeColor; + gfx::Canvas canvas( + gfx::Size(kBatteryCanvasSizeMd, kBatteryCanvasSizeMd), + display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(), + false); + + // Paint the battery's base (background) color. + PaintVectorIcon(&canvas, kSystemTrayBatteryIcon, kBatteryCanvasSizeMd, + kBatteryBaseColor); + + // Paint the charged portion of the battery. Note that |charge_height| adjusts + // for the 2dp of padding between the bottom of the battery icon and the + // bottom edge of |canvas|. + const int charge_height = info.charge_level + 2; + gfx::Rect clip_rect(0, kBatteryCanvasSizeMd - charge_height, + kBatteryCanvasSizeMd, charge_height); + canvas.Save(); + canvas.ClipRect(clip_rect); + PaintVectorIcon(&canvas, kSystemTrayBatteryIcon, kBatteryCanvasSizeMd, + charge_color); + canvas.Restore(); + + // Paint the badge over top of the battery, if applicable. + if (info.icon_badge != ICON_BADGE_NONE) { + PaintVectorIcon(&canvas, VectorIconForIconBadge(info.icon_badge), + kBatteryCanvasSizeMd, badge_color); + } + + return gfx::ImageSkia(canvas.ExtractImageRep()); +} + +gfx::ImageSkia PowerStatus::GetBatteryImageNonMd( + const BatteryImageInfo& info) const { + gfx::Image all; + all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(info.resource_id); + gfx::Rect region(info.offset * kBatteryImageWidth, + info.index * kBatteryImageHeight, kBatteryImageWidth, + kBatteryImageHeight); + return gfx::ImageSkiaOperations::ExtractSubset(*all.ToImageSkia(), region); +} + +base::string16 PowerStatus::GetAccessibleNameString( + bool full_description) const { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + if (IsBatteryFull()) { + return rb.GetLocalizedString( + IDS_ASH_STATUS_TRAY_BATTERY_FULL_CHARGE_ACCESSIBLE); + } + + base::string16 battery_percentage_accessible = l10n_util::GetStringFUTF16( + IsBatteryCharging() + ? IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_CHARGING_ACCESSIBLE + : IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_ACCESSIBLE, + base::IntToString16(GetRoundedBatteryPercent())); + if (!full_description) + return battery_percentage_accessible; + + base::string16 battery_time_accessible = base::string16(); + const base::TimeDelta time = + IsBatteryCharging() ? GetBatteryTimeToFull() : GetBatteryTimeToEmpty(); + + if (IsUsbChargerConnected()) { + battery_time_accessible = rb.GetLocalizedString( + IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE_ACCESSIBLE); + } else if (IsBatteryTimeBeingCalculated()) { + battery_time_accessible = rb.GetLocalizedString( + IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING_ACCESSIBLE); + } else if (ShouldDisplayBatteryTime(time) && + !IsBatteryDischargingOnLinePower()) { + int hour = 0, min = 0; + PowerStatus::SplitTimeIntoHoursAndMinutes(time, &hour, &min); + base::string16 minute = + min < 10 ? base::ASCIIToUTF16("0") + base::IntToString16(min) + : base::IntToString16(min); + battery_time_accessible = l10n_util::GetStringFUTF16( + IsBatteryCharging() + ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_ACCESSIBLE + : IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_ACCESSIBLE, + GetBatteryTimeAccessibilityString(hour, min)); + } + return battery_time_accessible.empty() + ? battery_percentage_accessible + : battery_percentage_accessible + base::ASCIIToUTF16(". ") + + battery_time_accessible; +} + +PowerStatus::PowerStatus() { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( + this); + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->RequestStatusUpdate(); +} + +PowerStatus::~PowerStatus() { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( + this); +} + +void PowerStatus::SetProtoForTesting( + const power_manager::PowerSupplyProperties& proto) { + proto_ = proto; + SanitizeProto(&proto_); +} + +void PowerStatus::PowerChanged( + const power_manager::PowerSupplyProperties& proto) { + proto_ = proto; + SanitizeProto(&proto_); + for (auto& observer : observers_) + observer.OnPowerStatusChanged(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/power_status.h b/ash/common/system/chromeos/power/power_status.h new file mode 100644 index 0000000..90d06fff --- /dev/null +++ b/ash/common/system/chromeos/power/power_status.h
@@ -0,0 +1,265 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_ + +#include <string> +#include <vector> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/strings/string16.h" +#include "base/time/time.h" +#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/gfx/image/image_skia.h" + +namespace ash { + +// PowerStatus is a singleton that receives updates about the system's +// power status from chromeos::PowerManagerClient and makes the information +// available to interested classes within Ash. +class ASH_EXPORT PowerStatus : public chromeos::PowerManagerClient::Observer { + public: + // Types of badges which can be drawn on top of a battery icon. + enum IconBadge { + ICON_BADGE_NONE, + ICON_BADGE_ALERT, + ICON_BADGE_BOLT, + ICON_BADGE_X, + ICON_BADGE_UNRELIABLE + }; + + // Different styles of battery icons. + enum IconSet { ICON_LIGHT, ICON_DARK }; + + // Interface for classes that wish to be notified when the power status + // has changed. + class Observer { + public: + // Called when the power status changes. + virtual void OnPowerStatusChanged() = 0; + + protected: + virtual ~Observer() {} + }; + + // Power source types. + enum DeviceType { + // Dedicated charger (AC adapter, USB power supply, etc.). + DEDICATED_CHARGER, + + // Dual-role device. + DUAL_ROLE_USB, + }; + + // Information about an available power source. + struct PowerSource { + // ID provided by kernel. + std::string id; + + // Type of power source. + DeviceType type; + + // Message ID of a description for this port. + int description_id; + }; + + // Information about the battery image corresponding to the status at a given + // point in time. This can be cached and later compared to avoid unnecessarily + // updating onscreen icons (GetBatteryImage() creates a new image on each + // call). + struct BatteryImageInfo { + BatteryImageInfo() + : resource_id(-1), + offset(-1), + index(-1), + icon_badge(ICON_BADGE_NONE), + charge_level(-1) {} + + bool operator==(const BatteryImageInfo& o) const; + + bool operator!=(const BatteryImageInfo& o) const { return !(*this == o); } + + // Resource ID of the image containing the specific battery icon to use. + // Only used in non-MD. + int resource_id; + + // Horizontal offset in the battery icon array image. The USB / "unreliable + // charging" image has a single column of icons; the other image contains a + // "battery" column on the left and a "line power" column on the right. + // Only used in non-MD. + int offset; + + // Vertical offset corresponding to the current battery level. Only used in + // non-MD. + int index; + + // The badge (lightning bolt, exclamation mark, etc) that should be drawn + // on top of the battery icon. Only used for MD. + // TODO(tdanderson): Consider using gfx::VectorIconId instead of this enum + // once all possible badges have been vectorized. See crbug.com/617298. + IconBadge icon_badge; + + // A value between 0 and kBatteryImageHeightMD representing the height + // of the battery's charge level in dp. Only used for MD. + int charge_level; + }; + + // Maximum battery time-to-full or time-to-empty that should be displayed + // in the UI. If the current is close to zero, battery time estimates can + // get very large; avoid displaying these large numbers. + static const int kMaxBatteryTimeToDisplaySec; + + // An alert badge is drawn over the material design battery icon if the + // battery is not connected to a charger and has less than + // |kCriticalBatteryChargePercentageMd| percentage of charge remaining. + static const double kCriticalBatteryChargePercentageMd; + + // Sets the global instance. Must be called before any calls to Get(). + static void Initialize(); + + // Destroys the global instance. + static void Shutdown(); + + // Returns true if the global instance is initialized. + static bool IsInitialized(); + + // Gets the global instance. Initialize must be called first. + static PowerStatus* Get(); + + // Returns true if |time|, a time returned by GetBatteryTimeToEmpty() or + // GetBatteryTimeToFull(), should be displayed in the UI. + // Less-than-a-minute or very large values aren't displayed. + static bool ShouldDisplayBatteryTime(const base::TimeDelta& time); + + // Copies the hour and minute components of |time| to |hours| and |minutes|. + // The minute component is rounded rather than truncated: a |time| value + // corresponding to 92 seconds will produce a |minutes| value of 2, for + // example. + static void SplitTimeIntoHoursAndMinutes(const base::TimeDelta& time, + int* hours, + int* minutes); + + // Adds or removes an observer. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Requests updated status from the power manager. + void RequestStatusUpdate(); + + // Changes the power source to the source with the given ID. + void SetPowerSource(const std::string& id); + + // Returns true if a battery is present. + bool IsBatteryPresent() const; + + // Returns true if the battery is full. This also implies that a charger + // is connected. + bool IsBatteryFull() const; + + // Returns true if the battery is charging. Note that this implies that a + // charger is connected but the converse is not necessarily true: the + // battery may be discharging even while a (perhaps low-power) charger is + // connected. Use Is*Connected() to test for the presence of a charger + // and also see IsBatteryDischargingOnLinePower(). + bool IsBatteryCharging() const; + + // Returns true if the battery is discharging (or neither charging nor + // discharging while not being full) while line power is connected. + bool IsBatteryDischargingOnLinePower() const; + + // Returns the battery's remaining charge as a value in the range [0.0, + // 100.0]. + double GetBatteryPercent() const; + + // Returns the battery's remaining charge, rounded to an integer with a + // maximum value of 100. + int GetRoundedBatteryPercent() const; + + // Returns true if the battery's time-to-full and time-to-empty estimates + // should not be displayed because the power manager is still calculating + // them. + bool IsBatteryTimeBeingCalculated() const; + + // Returns the estimated time until the battery is empty (if line power + // is disconnected) or full (if line power is connected). These estimates + // should only be used if IsBatteryTimeBeingCalculated() returns false. + base::TimeDelta GetBatteryTimeToEmpty() const; + base::TimeDelta GetBatteryTimeToFull() const; + + // Returns true if line power (including a charger of any type) is connected. + bool IsLinePowerConnected() const; + + // Returns true if an official, non-USB charger is connected. + bool IsMainsChargerConnected() const; + + // Returns true if a USB charger (which is likely to only support a low + // charging rate) is connected. + bool IsUsbChargerConnected() const; + + // Returns true if the system allows some connected devices to function as + // either power sources or sinks. + bool SupportsDualRoleDevices() const; + + // Returns true if at least one dual-role device is connected. + bool HasDualRoleDevices() const; + + // Returns a list of available power sources which the user may select. + std::vector<PowerSource> GetPowerSources() const; + + // Returns the ID of the currently used power source, or an empty string if no + // power source is selected. + std::string GetCurrentPowerSourceID() const; + + // Returns information about the image that would be returned by + // GetBatteryImage(). This can be cached and compared against future objects + // returned by this method to avoid creating new images unnecessarily. + BatteryImageInfo GetBatteryImageInfo(IconSet icon_set) const; + + // A helper function called by GetBatteryImageInfo(). Populates the + // MD-specific fields of |info|. + void CalculateBatteryImageInfoMd(BatteryImageInfo* info) const; + + // A helper function called by GetBatteryImageInfo(). Populates the + // non-MD-specific fields of |info|. + void CalculateBatteryImageInfoNonMd(BatteryImageInfo* info, + const IconSet& icon_set) const; + + // Creates a new image that should be shown for the battery's current state. + gfx::ImageSkia GetBatteryImage(const BatteryImageInfo& info) const; + + // A version of GetBatteryImage() that is used when material design is not + // enabled. + // TODO(tdanderson): Remove this once material design is enabled by default. + // See crbug.com/614453. + gfx::ImageSkia GetBatteryImageNonMd(const BatteryImageInfo& info) const; + + // Returns an string describing the current state for accessibility. + base::string16 GetAccessibleNameString(bool full_description) const; + + // Updates |proto_|. Does not notify observers. + void SetProtoForTesting(const power_manager::PowerSupplyProperties& proto); + + protected: + PowerStatus(); + ~PowerStatus() override; + + private: + // Overriden from PowerManagerClient::Observer. + void PowerChanged(const power_manager::PowerSupplyProperties& proto) override; + + base::ObserverList<Observer> observers_; + + // Current state. + power_manager::PowerSupplyProperties proto_; + + DISALLOW_COPY_AND_ASSIGN(PowerStatus); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_H_
diff --git a/ash/common/system/chromeos/power/power_status_unittest.cc b/ash/common/system/chromeos/power/power_status_unittest.cc new file mode 100644 index 0000000..b31c6002 --- /dev/null +++ b/ash/common/system/chromeos/power/power_status_unittest.cc
@@ -0,0 +1,319 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/power_status.h" + +#include <memory> + +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +using power_manager::PowerSupplyProperties; + +namespace ash { +namespace { + +class TestObserver : public PowerStatus::Observer { + public: + TestObserver() : power_changed_count_(0) {} + ~TestObserver() override {} + + int power_changed_count() const { return power_changed_count_; } + + // PowerStatus::Observer overrides: + void OnPowerStatusChanged() override { ++power_changed_count_; } + + private: + int power_changed_count_; + + DISALLOW_COPY_AND_ASSIGN(TestObserver); +}; + +} // namespace + +class PowerStatusTest : public testing::Test { + public: + PowerStatusTest() : power_status_(NULL) {} + ~PowerStatusTest() override {} + + void SetUp() override { + chromeos::DBusThreadManager::Initialize(); + PowerStatus::Initialize(); + power_status_ = PowerStatus::Get(); + test_observer_.reset(new TestObserver); + power_status_->AddObserver(test_observer_.get()); + } + + void TearDown() override { + power_status_->RemoveObserver(test_observer_.get()); + test_observer_.reset(); + PowerStatus::Shutdown(); + chromeos::DBusThreadManager::Shutdown(); + } + + protected: + base::MessageLoopForUI message_loop_; + PowerStatus* power_status_; // Not owned. + std::unique_ptr<TestObserver> test_observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(PowerStatusTest); +}; + +TEST_F(PowerStatusTest, InitializeAndUpdate) { + // Test that the initial power supply state should be acquired after + // PowerStatus is instantiated. This depends on + // PowerManagerClientStubImpl, which responds to power status update + // requests, pretends there is a battery present, and generates some valid + // power supply status data. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1, test_observer_->power_changed_count()); + + // Test RequestUpdate, test_obsever_ should be notified for power suuply + // status change. + power_status_->RequestStatusUpdate(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2, test_observer_->power_changed_count()); +} + +TEST_F(PowerStatusTest, ShouldDisplayBatteryTime) { + EXPECT_FALSE( + PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(-1))); + EXPECT_FALSE( + PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(0))); + EXPECT_FALSE( + PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(59))); + EXPECT_TRUE( + PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(60))); + EXPECT_TRUE( + PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(600))); + EXPECT_TRUE(PowerStatus::ShouldDisplayBatteryTime( + base::TimeDelta::FromSeconds(3600))); + EXPECT_TRUE(PowerStatus::ShouldDisplayBatteryTime( + base::TimeDelta::FromSeconds(PowerStatus::kMaxBatteryTimeToDisplaySec))); + EXPECT_FALSE( + PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds( + PowerStatus::kMaxBatteryTimeToDisplaySec + 1))); +} + +TEST_F(PowerStatusTest, SplitTimeIntoHoursAndMinutes) { + int hours = 0, minutes = 0; + PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(0), + &hours, &minutes); + EXPECT_EQ(0, hours); + EXPECT_EQ(0, minutes); + + PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(60), + &hours, &minutes); + EXPECT_EQ(0, hours); + EXPECT_EQ(1, minutes); + + PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(3600), + &hours, &minutes); + EXPECT_EQ(1, hours); + EXPECT_EQ(0, minutes); + + PowerStatus::SplitTimeIntoHoursAndMinutes( + base::TimeDelta::FromSeconds(3600 + 60), &hours, &minutes); + EXPECT_EQ(1, hours); + EXPECT_EQ(1, minutes); + + PowerStatus::SplitTimeIntoHoursAndMinutes( + base::TimeDelta::FromSeconds(7 * 3600 + 23 * 60), &hours, &minutes); + EXPECT_EQ(7, hours); + EXPECT_EQ(23, minutes); + + // Check that minutes are rounded. + PowerStatus::SplitTimeIntoHoursAndMinutes( + base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 30), &hours, &minutes); + EXPECT_EQ(2, hours); + EXPECT_EQ(4, minutes); + + PowerStatus::SplitTimeIntoHoursAndMinutes( + base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 29), &hours, &minutes); + EXPECT_EQ(2, hours); + EXPECT_EQ(3, minutes); + + // Check that times close to hour boundaries aren't incorrectly rounded such + // that they display 60 minutes: http://crbug.com/368261 + PowerStatus::SplitTimeIntoHoursAndMinutes( + base::TimeDelta::FromSecondsD(3599.9), &hours, &minutes); + EXPECT_EQ(1, hours); + EXPECT_EQ(0, minutes); + + PowerStatus::SplitTimeIntoHoursAndMinutes( + base::TimeDelta::FromSecondsD(3600.1), &hours, &minutes); + EXPECT_EQ(1, hours); + EXPECT_EQ(0, minutes); +} + +TEST_F(PowerStatusTest, GetBatteryImageInfo) { + PowerSupplyProperties prop; + prop.set_external_power(PowerSupplyProperties::AC); + prop.set_battery_state(PowerSupplyProperties::CHARGING); + prop.set_battery_percent(98.0); + power_status_->SetProtoForTesting(prop); + const PowerStatus::BatteryImageInfo info_charging_98 = + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT); + + // 99% should use the same icon as 98%. + prop.set_battery_percent(99.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ(info_charging_98, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); + + // The dark icon set should use a different image for non-MD, but the + // same image for MD. + prop.set_battery_percent(98.0); + EXPECT_EQ(info_charging_98, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_DARK)); + + // A different icon should be used when the battery is full, too. + prop.set_battery_state(PowerSupplyProperties::FULL); + prop.set_battery_percent(100.0); + power_status_->SetProtoForTesting(prop); + EXPECT_NE(info_charging_98, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); + + // A much-lower battery level should use a different icon. + prop.set_battery_state(PowerSupplyProperties::CHARGING); + prop.set_battery_percent(20.0); + power_status_->SetProtoForTesting(prop); + EXPECT_NE(info_charging_98, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); + + // Ditto for 98%, but on USB instead of AC. + prop.set_external_power(PowerSupplyProperties::USB); + prop.set_battery_percent(98.0); + power_status_->SetProtoForTesting(prop); + EXPECT_NE(info_charging_98, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); +} + +// Tests that the |icon_badge| member of BatteryImageInfo is set correctly +// with various power supply property values. +TEST_F(PowerStatusTest, BatteryImageInfoIconBadge) { + PowerSupplyProperties prop; + + // A charging battery connected to AC power should have an ICON_BADGE_BOLT. + prop.set_external_power(PowerSupplyProperties::AC); + prop.set_battery_state(PowerSupplyProperties::CHARGING); + prop.set_battery_percent(98.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_BOLT, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + + // A discharging battery connected to AC should also have an ICON_BADGE_BOLT. + prop.set_battery_state(PowerSupplyProperties::DISCHARGING); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_BOLT, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + + // A charging battery connected to USB power should have an + // ICON_BADGE_UNRELIABLE. + prop.set_external_power(PowerSupplyProperties::USB); + prop.set_battery_state(PowerSupplyProperties::CHARGING); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_UNRELIABLE, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + + // A discharging battery connected to USB power should also have an + // ICON_BADGE_UNRELIABLE. + prop.set_battery_state(PowerSupplyProperties::DISCHARGING); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_UNRELIABLE, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + + // Show an ICON_BADGE_X when no battery is present. + prop.set_external_power(PowerSupplyProperties::DISCONNECTED); + prop.set_battery_state(PowerSupplyProperties::NOT_PRESENT); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_X, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + + // Do not show a badge when the battery is discharging. + prop.set_battery_state(PowerSupplyProperties::DISCHARGING); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_NONE, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + + // Show ICON_BADGE_ALERT for a discharging battery when it falls below + // a charge level of PowerStatus::kCriticalBatteryChargePercentageMd. + prop.set_battery_percent(PowerStatus::kCriticalBatteryChargePercentageMd); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_NONE, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); + prop.set_battery_percent(PowerStatus::kCriticalBatteryChargePercentageMd - 1); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + PowerStatus::ICON_BADGE_ALERT, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); +} + +// Tests that the |charge_level| member of BatteryImageInfo is set correctly +// with various power supply property values. +TEST_F(PowerStatusTest, BatteryImageInfoChargeLevel) { + PowerSupplyProperties prop; + + // No charge level is drawn when the battery is not present. + prop.set_external_power(PowerSupplyProperties::DISCONNECTED); + prop.set_battery_state(PowerSupplyProperties::NOT_PRESENT); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + 0, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); + + // A charge level of 0 when the battery is 0% full. + prop.set_external_power(PowerSupplyProperties::AC); + prop.set_battery_state(PowerSupplyProperties::CHARGING); + prop.set_battery_percent(0.0); + EXPECT_EQ( + 0, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); + + // A charge level of 1 when the battery is up to 16% full, and a level of 2 + // for 17% full. + prop.set_battery_percent(16.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + 1, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); + prop.set_battery_percent(17.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + 2, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); + + // A charge level of 6 when the battery is 50% full. + prop.set_battery_percent(50.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + 6, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); + + // A charge level of 11 when the battery is 99% full, and a level of 12 when + // the battery is 100% full. + prop.set_battery_percent(99.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + 11, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); + prop.set_battery_percent(100.0); + power_status_->SetProtoForTesting(prop); + EXPECT_EQ( + 12, + power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/power_status_view.cc b/ash/common/system/chromeos/power/power_status_view.cc new file mode 100644 index 0000000..0a0f554 --- /dev/null +++ b/ash/common/system/chromeos/power/power_status_view.cc
@@ -0,0 +1,176 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/power_status_view.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/chromeos/power/tray_power.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/i18n/number_formatting.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/grid_layout.h" + +namespace ash { + +// Padding between battery status text and battery icon on default view. +const int kPaddingBetweenBatteryStatusAndIcon = 3; + +PowerStatusView::PowerStatusView(bool default_view_right_align) + : default_view_right_align_(default_view_right_align), + percentage_label_(new views::Label), + separator_label_(new views::Label), + time_status_label_(new views::Label), + icon_(nullptr) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + SetFocusBehavior(FocusBehavior::ALWAYS); + + percentage_label_->SetEnabledColor(kHeaderTextColorNormal); + separator_label_->SetEnabledColor(kHeaderTextColorNormal); + separator_label_->SetText(base::ASCIIToUTF16(" - ")); + LayoutView(); + PowerStatus::Get()->AddObserver(this); + OnPowerStatusChanged(); +} + +PowerStatusView::~PowerStatusView() { + PowerStatus::Get()->RemoveObserver(this); +} + +void PowerStatusView::OnPowerStatusChanged() { + UpdateText(); + + // We do not show a battery icon in the material design system menu. + // TODO(tdanderson): Remove the non-MD code and the IconSet enum once + // material design is enabled by default. See crbug.com/614453. + if (MaterialDesignController::UseMaterialDesignSystemIcons()) + return; + + const PowerStatus::BatteryImageInfo info = + PowerStatus::Get()->GetBatteryImageInfo(PowerStatus::ICON_DARK); + if (info != previous_battery_image_info_) { + icon_->SetImage(PowerStatus::Get()->GetBatteryImage(info)); + icon_->SetVisible(true); + previous_battery_image_info_ = info; + } +} + +void PowerStatusView::LayoutView() { + if (default_view_right_align_) { + views::BoxLayout* layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, + kPaddingBetweenBatteryStatusAndIcon); + SetLayoutManager(layout); + + AddChildView(percentage_label_); + AddChildView(separator_label_); + AddChildView(time_status_label_); + + icon_ = new views::ImageView; + AddChildView(icon_); + + return; + } + + // TODO(tdanderson): Tweak padding values for material design. + const bool material_design = + MaterialDesignController::IsSystemTrayMenuMaterial(); + views::BoxLayout* layout = new views::BoxLayout( + views::BoxLayout::kHorizontal, material_design ? 12 : 0, 0, + kTrayPopupPaddingBetweenItems); + SetLayoutManager(layout); + + if (!material_design) { + icon_ = TrayPopupUtils::CreateMainImageView(); + AddChildView(icon_); + } + + AddChildView(percentage_label_); + AddChildView(separator_label_); + AddChildView(time_status_label_); +} + +void PowerStatusView::UpdateText() { + const PowerStatus& status = *PowerStatus::Get(); + base::string16 battery_percentage; + base::string16 battery_time_status; + + if (status.IsBatteryFull()) { + battery_time_status = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_FULL); + } else { + battery_percentage = base::FormatPercent(status.GetRoundedBatteryPercent()); + if (status.IsUsbChargerConnected()) { + battery_time_status = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE); + } else if (status.IsBatteryTimeBeingCalculated()) { + battery_time_status = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING); + } else { + base::TimeDelta time = status.IsBatteryCharging() + ? status.GetBatteryTimeToFull() + : status.GetBatteryTimeToEmpty(); + if (PowerStatus::ShouldDisplayBatteryTime(time) && + !status.IsBatteryDischargingOnLinePower()) { + battery_time_status = l10n_util::GetStringFUTF16( + status.IsBatteryCharging() + ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_SHORT + : IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_SHORT, + TimeDurationFormat(time, base::DURATION_WIDTH_NUMERIC)); + } + } + } + percentage_label_->SetVisible(!battery_percentage.empty()); + percentage_label_->SetText(battery_percentage); + separator_label_->SetVisible(!battery_percentage.empty() && + !battery_time_status.empty()); + time_status_label_->SetVisible(!battery_time_status.empty()); + time_status_label_->SetText(battery_time_status); + + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true); + + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); + style.SetupLabel(percentage_label_); + style.SetupLabel(separator_label_); + style.SetupLabel(time_status_label_); + } +} + +void PowerStatusView::ChildPreferredSizeChanged(views::View* child) { + PreferredSizeChanged(); +} + +void PowerStatusView::Layout() { + views::View::Layout(); + + // Move the time_status_label_, separator_label_, and percentage_label_ + // closer to each other. + if (percentage_label_ && separator_label_ && time_status_label_ && + percentage_label_->visible() && time_status_label_->visible()) { + separator_label_->SetX(percentage_label_->bounds().right() + 1); + time_status_label_->SetX(separator_label_->bounds().right() + 1); + } +} + +void PowerStatusView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + if (!MaterialDesignController::IsSystemTrayMenuMaterial()) + return; + + node_data->role = ui::AX_ROLE_LABEL_TEXT; + node_data->SetName(accessible_name_); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/power_status_view.h b/ash/common/system/chromeos/power/power_status_view.h new file mode 100644 index 0000000..1cd5cee --- /dev/null +++ b/ash/common/system/chromeos/power/power_status_view.h
@@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "ui/views/view.h" + +namespace views { +class ImageView; +class Label; +} + +namespace ash { + +class ASH_EXPORT PowerStatusView : public views::View, + public PowerStatus::Observer { + public: + explicit PowerStatusView(bool default_view_right_align); + ~PowerStatusView() override; + + // views::View: + void Layout() override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + // PowerStatus::Observer: + void OnPowerStatusChanged() override; + + private: + friend class PowerStatusViewTest; + + void LayoutView(); + void UpdateText(); + + // views::View: + void ChildPreferredSizeChanged(views::View* child) override; + + // Layout default view UI items on the right side of system tray pop up item + // if true; otherwise, layout the UI items on the left side. + bool default_view_right_align_; + + views::Label* percentage_label_; + views::Label* separator_label_; + views::Label* time_status_label_; + + // Battery status indicator icon. Unused in material design. + views::ImageView* icon_; + + // Information about the image last used to update |icon_|. Cached to avoid + // unnecessary updates (http://crbug.com/589348). + PowerStatus::BatteryImageInfo previous_battery_image_info_; + + // Only used in material design. + base::string16 accessible_name_; + + DISALLOW_COPY_AND_ASSIGN(PowerStatusView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_POWER_POWER_STATUS_VIEW_H_
diff --git a/ash/common/system/chromeos/power/power_status_view_unittest.cc b/ash/common/system/chromeos/power/power_status_view_unittest.cc new file mode 100644 index 0000000..7103adb --- /dev/null +++ b/ash/common/system/chromeos/power/power_status_view_unittest.cc
@@ -0,0 +1,119 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/power_status_view.h" + +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/test/ash_test_base.h" +#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" + +using power_manager::PowerSupplyProperties; + +namespace ash { + +class PowerStatusViewTest : public test::AshTestBase { + public: + PowerStatusViewTest() {} + ~PowerStatusViewTest() override {} + + // Overridden from testing::Test: + void SetUp() override { + test::AshTestBase::SetUp(); + view_.reset(new PowerStatusView(false)); + } + + void TearDown() override { + view_.reset(); + test::AshTestBase::TearDown(); + } + + protected: + void UpdatePowerStatus(const power_manager::PowerSupplyProperties& proto) { + PowerStatus::Get()->SetProtoForTesting(proto); + view_->OnPowerStatusChanged(); + } + + bool IsPercentageVisible() const { + return view_->percentage_label_->visible(); + } + + bool IsTimeStatusVisible() const { + return view_->time_status_label_->visible(); + } + + base::string16 RemainingTimeInView() const { + return view_->time_status_label_->text(); + } + + gfx::ImageSkia GetBatteryImage() const { return view_->icon_->GetImage(); } + + private: + std::unique_ptr<PowerStatusView> view_; + + DISALLOW_COPY_AND_ASSIGN(PowerStatusViewTest); +}; + +TEST_F(PowerStatusViewTest, Basic) { + EXPECT_FALSE(IsPercentageVisible()); + EXPECT_TRUE(IsTimeStatusVisible()); + + // Disconnect the power. + PowerSupplyProperties prop; + prop.set_external_power(PowerSupplyProperties::DISCONNECTED); + prop.set_battery_state(PowerSupplyProperties::DISCHARGING); + prop.set_battery_percent(99.0); + prop.set_battery_time_to_empty_sec(120); + prop.set_is_calculating_battery_time(true); + UpdatePowerStatus(prop); + + EXPECT_TRUE(IsPercentageVisible()); + EXPECT_TRUE(IsTimeStatusVisible()); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), + RemainingTimeInView()); + + prop.set_is_calculating_battery_time(false); + UpdatePowerStatus(prop); + EXPECT_NE(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), + RemainingTimeInView()); + EXPECT_NE(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), + RemainingTimeInView()); + + prop.set_external_power(PowerSupplyProperties::AC); + prop.set_battery_state(PowerSupplyProperties::CHARGING); + prop.set_battery_time_to_full_sec(120); + UpdatePowerStatus(prop); + EXPECT_TRUE(IsPercentageVisible()); + EXPECT_TRUE(IsTimeStatusVisible()); + EXPECT_NE(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), + RemainingTimeInView()); + EXPECT_NE(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), + RemainingTimeInView()); + + prop.set_external_power(PowerSupplyProperties::USB); + UpdatePowerStatus(prop); + EXPECT_TRUE(IsPercentageVisible()); + EXPECT_TRUE(IsTimeStatusVisible()); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), + RemainingTimeInView()); + + // Tricky -- connected to non-USB but still discharging. Not likely happening + // on production though. + prop.set_external_power(PowerSupplyProperties::AC); + prop.set_battery_state(PowerSupplyProperties::DISCHARGING); + prop.set_battery_time_to_full_sec(120); + UpdatePowerStatus(prop); + EXPECT_TRUE(IsPercentageVisible()); + EXPECT_FALSE(IsTimeStatusVisible()); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/tray_power.cc b/ash/common/system/chromeos/power/tray_power.cc new file mode 100644 index 0000000..7d071ed --- /dev/null +++ b/ash/common/system/chromeos/power/tray_power.cc
@@ -0,0 +1,363 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/tray_power.h" + +#include <utility> + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/ash_switches.h" +#include "ash/common/system/chromeos/devicetype_utils.h" +#include "ash/common/system/chromeos/power/battery_notification.h" +#include "ash/common/system/chromeos/power/dual_role_notification.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/time/time.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/view.h" + +using message_center::MessageCenter; +using message_center::Notification; + +namespace ash { + +// Informs the TrayPower instance when a USB notification is closed. +class UsbNotificationDelegate : public message_center::NotificationDelegate { + public: + explicit UsbNotificationDelegate(TrayPower* tray_power) + : tray_power_(tray_power) {} + + // Overridden from message_center::NotificationDelegate. + void Close(bool by_user) override { + if (by_user) + tray_power_->NotifyUsbNotificationClosedByUser(); + } + + private: + ~UsbNotificationDelegate() override {} + + TrayPower* tray_power_; + + DISALLOW_COPY_AND_ASSIGN(UsbNotificationDelegate); +}; + +namespace { + +std::string GetNotificationStateString( + TrayPower::NotificationState notification_state) { + switch (notification_state) { + case TrayPower::NOTIFICATION_NONE: + return "none"; + case TrayPower::NOTIFICATION_LOW_POWER: + return "low power"; + case TrayPower::NOTIFICATION_CRITICAL: + return "critical power"; + } + NOTREACHED() << "Unknown state " << notification_state; + return "Unknown state"; +} + +void LogBatteryForUsbCharger(TrayPower::NotificationState state, + int battery_percent) { + LOG(WARNING) << "Showing " << GetNotificationStateString(state) + << " notification. USB charger is connected. " + << "Battery percentage: " << battery_percent << "%."; +} + +void LogBatteryForNoCharger(TrayPower::NotificationState state, + int remaining_minutes) { + LOG(WARNING) << "Showing " << GetNotificationStateString(state) + << " notification. No charger connected." + << " Remaining time: " << remaining_minutes << " minutes."; +} + +} // namespace + +namespace tray { + +// This view is used only for the tray. +class PowerTrayView : public TrayItemView { + public: + explicit PowerTrayView(SystemTrayItem* owner) : TrayItemView(owner) { + CreateImageView(); + UpdateImage(); + } + + ~PowerTrayView() override {} + + // Overriden from views::View. + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->SetName(accessible_name_); + node_data->role = ui::AX_ROLE_BUTTON; + } + + void UpdateStatus(bool battery_alert) { + UpdateImage(); + SetVisible(PowerStatus::Get()->IsBatteryPresent()); + + if (battery_alert) { + accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true); + NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + } + } + + private: + void UpdateImage() { + const PowerStatus::BatteryImageInfo info = + PowerStatus::Get()->GetBatteryImageInfo(PowerStatus::ICON_LIGHT); + if (info != previous_image_info_) { + image_view()->SetImage(PowerStatus::Get()->GetBatteryImage(info)); + previous_image_info_ = info; + } + } + + base::string16 accessible_name_; + + // Information about the last-used image. Cached to avoid unnecessary updates + // (http://crbug.com/589348). + PowerStatus::BatteryImageInfo previous_image_info_; + + DISALLOW_COPY_AND_ASSIGN(PowerTrayView); +}; + +} // namespace tray + +const int TrayPower::kCriticalMinutes = 5; +const int TrayPower::kLowPowerMinutes = 15; +const int TrayPower::kNoWarningMinutes = 30; +const int TrayPower::kCriticalPercentage = 5; +const int TrayPower::kLowPowerPercentage = 10; +const int TrayPower::kNoWarningPercentage = 15; + +const char TrayPower::kUsbNotificationId[] = "usb-charger"; + +TrayPower::TrayPower(SystemTray* system_tray, MessageCenter* message_center) + : SystemTrayItem(system_tray, UMA_POWER), + message_center_(message_center), + power_tray_(NULL), + notification_state_(NOTIFICATION_NONE), + usb_charger_was_connected_(false), + line_power_was_connected_(false), + usb_notification_dismissed_(false) { + PowerStatus::Get()->AddObserver(this); +} + +TrayPower::~TrayPower() { + PowerStatus::Get()->RemoveObserver(this); + message_center_->RemoveNotification(kUsbNotificationId, false); +} + +views::View* TrayPower::CreateTrayView(LoginStatus status) { + // There may not be enough information when this is created about whether + // there is a battery or not. So always create this, and adjust visibility as + // necessary. + CHECK(power_tray_ == NULL); + power_tray_ = new tray::PowerTrayView(this); + power_tray_->UpdateStatus(false); + return power_tray_; +} + +views::View* TrayPower::CreateDefaultView(LoginStatus status) { + // Make sure icon status is up to date. (Also triggers stub activation). + PowerStatus::Get()->RequestStatusUpdate(); + return NULL; +} + +void TrayPower::DestroyTrayView() { + power_tray_ = NULL; +} + +void TrayPower::DestroyDefaultView() {} + +void TrayPower::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayPower::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + SetTrayImageItemBorder(power_tray_, alignment); +} + +void TrayPower::OnPowerStatusChanged() { + bool battery_alert = UpdateNotificationState(); + if (power_tray_) + power_tray_->UpdateStatus(battery_alert); + + // Factory testing may place the battery into unusual states. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + ash::switches::kAshHideNotificationsForFactory)) + return; + + MaybeShowUsbChargerNotification(); + MaybeShowDualRoleNotification(); + + if (battery_alert) { + // Remove any existing notification so it's dismissed before adding a new + // one. Otherwise we might update a "low battery" notification to "critical" + // without it being shown again. + battery_notification_.reset(); + battery_notification_.reset( + new BatteryNotification(message_center_, notification_state_)); + } else if (notification_state_ == NOTIFICATION_NONE) { + battery_notification_.reset(); + } else if (battery_notification_.get()) { + battery_notification_->Update(notification_state_); + } + + usb_charger_was_connected_ = PowerStatus::Get()->IsUsbChargerConnected(); + line_power_was_connected_ = PowerStatus::Get()->IsLinePowerConnected(); +} + +bool TrayPower::MaybeShowUsbChargerNotification() { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + const PowerStatus& status = *PowerStatus::Get(); + + bool usb_charger_is_connected = status.IsUsbChargerConnected(); + + // Check for a USB charger being connected. + if (usb_charger_is_connected && !usb_charger_was_connected_ && + !usb_notification_dismissed_) { + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kUsbNotificationId, + rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_TITLE), + ash::SubstituteChromeOSDeviceType( + IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_MESSAGE_SHORT), + rb.GetImageNamed(IDR_AURA_NOTIFICATION_LOW_POWER_CHARGER), + base::string16(), GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierPower), + message_center::RichNotificationData(), + new UsbNotificationDelegate(this))); + message_center_->AddNotification(std::move(notification)); + return true; + } else if (!usb_charger_is_connected && usb_charger_was_connected_) { + // USB charger was unplugged or was identified as a different type while + // the USB charger notification was showing. + message_center_->RemoveNotification(kUsbNotificationId, false); + if (!status.IsLinePowerConnected()) + usb_notification_dismissed_ = false; + return true; + } + return false; +} + +void TrayPower::MaybeShowDualRoleNotification() { + const PowerStatus& status = *PowerStatus::Get(); + if (!status.HasDualRoleDevices()) { + dual_role_notification_.reset(); + return; + } + + if (!dual_role_notification_) + dual_role_notification_.reset(new DualRoleNotification(message_center_)); + dual_role_notification_->Update(); +} + +bool TrayPower::UpdateNotificationState() { + const PowerStatus& status = *PowerStatus::Get(); + if (!status.IsBatteryPresent() || status.IsBatteryTimeBeingCalculated() || + status.IsMainsChargerConnected()) { + notification_state_ = NOTIFICATION_NONE; + return false; + } + + return status.IsUsbChargerConnected() + ? UpdateNotificationStateForRemainingPercentage() + : UpdateNotificationStateForRemainingTime(); +} + +bool TrayPower::UpdateNotificationStateForRemainingTime() { + // The notification includes a rounded minutes value, so round the estimate + // received from the power manager to match. + const int remaining_minutes = static_cast<int>( + PowerStatus::Get()->GetBatteryTimeToEmpty().InSecondsF() / 60.0 + 0.5); + + if (remaining_minutes >= kNoWarningMinutes || + PowerStatus::Get()->IsBatteryFull()) { + notification_state_ = NOTIFICATION_NONE; + return false; + } + + switch (notification_state_) { + case NOTIFICATION_NONE: + if (remaining_minutes <= kCriticalMinutes) { + notification_state_ = NOTIFICATION_CRITICAL; + LogBatteryForNoCharger(notification_state_, remaining_minutes); + return true; + } + if (remaining_minutes <= kLowPowerMinutes) { + notification_state_ = NOTIFICATION_LOW_POWER; + LogBatteryForNoCharger(notification_state_, remaining_minutes); + return true; + } + return false; + case NOTIFICATION_LOW_POWER: + if (remaining_minutes <= kCriticalMinutes) { + notification_state_ = NOTIFICATION_CRITICAL; + LogBatteryForNoCharger(notification_state_, remaining_minutes); + return true; + } + return false; + case NOTIFICATION_CRITICAL: + return false; + } + NOTREACHED(); + return false; +} + +bool TrayPower::UpdateNotificationStateForRemainingPercentage() { + // The notification includes a rounded percentage, so round the value received + // from the power manager to match. + const int remaining_percentage = + PowerStatus::Get()->GetRoundedBatteryPercent(); + + if (remaining_percentage >= kNoWarningPercentage || + PowerStatus::Get()->IsBatteryFull()) { + notification_state_ = NOTIFICATION_NONE; + return false; + } + + switch (notification_state_) { + case NOTIFICATION_NONE: + if (remaining_percentage <= kCriticalPercentage) { + notification_state_ = NOTIFICATION_CRITICAL; + LogBatteryForUsbCharger(notification_state_, remaining_percentage); + return true; + } + if (remaining_percentage <= kLowPowerPercentage) { + notification_state_ = NOTIFICATION_LOW_POWER; + LogBatteryForUsbCharger(notification_state_, remaining_percentage); + return true; + } + return false; + case NOTIFICATION_LOW_POWER: + if (remaining_percentage <= kCriticalPercentage) { + notification_state_ = NOTIFICATION_CRITICAL; + LogBatteryForUsbCharger(notification_state_, remaining_percentage); + return true; + } + return false; + case NOTIFICATION_CRITICAL: + return false; + } + NOTREACHED(); + return false; +} + +void TrayPower::NotifyUsbNotificationClosedByUser() { + usb_notification_dismissed_ = true; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/power/tray_power.h b/ash/common/system/chromeos/power/tray_power.h new file mode 100644 index 0000000..c04de6c --- /dev/null +++ b/ash/common/system/chromeos/power/tray_power.h
@@ -0,0 +1,117 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_ + +#include <memory> + +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace message_center { +class MessageCenter; +} + +namespace ash { + +class BatteryNotification; +class DualRoleNotification; + +namespace tray { +class PowerTrayView; +} + +class ASH_EXPORT TrayPower : public SystemTrayItem, + public PowerStatus::Observer { + public: + enum NotificationState { + NOTIFICATION_NONE, + + // Low battery charge. + NOTIFICATION_LOW_POWER, + + // Critically low battery charge. + NOTIFICATION_CRITICAL, + }; + + // Time-based notification thresholds when on battery power. + static const int kCriticalMinutes; + static const int kLowPowerMinutes; + static const int kNoWarningMinutes; + + // Percentage-based notification thresholds when using a low-power charger. + static const int kCriticalPercentage; + static const int kLowPowerPercentage; + static const int kNoWarningPercentage; + + static const char kUsbNotificationId[]; + + TrayPower(SystemTray* system_tray, + message_center::MessageCenter* message_center); + ~TrayPower() override; + + void NotifyUsbNotificationClosedByUser(); + + private: + friend class TrayPowerTest; + + // This enum is used for histogram. The existing values should not be removed, + // and the new values should be added just before CHARGER_TYPE_COUNT. + enum ChargerType { + UNKNOWN_CHARGER, + MAINS_CHARGER, + USB_CHARGER, + UNCONFIRMED_SPRING_CHARGER, + SAFE_SPRING_CHARGER, + CHARGER_TYPE_COUNT, + }; + + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // Overridden from PowerStatus::Observer. + void OnPowerStatusChanged() override; + + // Shows a notification that a low-power USB charger has been connected. + // Returns true if a notification was shown or explicitly hidden. + bool MaybeShowUsbChargerNotification(); + + // Shows a notification when dual-role devices are connected. + void MaybeShowDualRoleNotification(); + + // Sets |notification_state_|. Returns true if a notification should be shown. + bool UpdateNotificationState(); + bool UpdateNotificationStateForRemainingTime(); + bool UpdateNotificationStateForRemainingPercentage(); + + message_center::MessageCenter* message_center_; // Not owned. + tray::PowerTrayView* power_tray_; + std::unique_ptr<BatteryNotification> battery_notification_; + std::unique_ptr<DualRoleNotification> dual_role_notification_; + NotificationState notification_state_; + + // Was a USB charger connected the last time OnPowerStatusChanged() was + // called? + bool usb_charger_was_connected_; + + // Was line power connected the last time onPowerStatusChanged() was called? + bool line_power_was_connected_; + + // Has the user already dismissed a low-power notification? Should be set + // back to false when all power sources are disconnected. + bool usb_notification_dismissed_; + + DISALLOW_COPY_AND_ASSIGN(TrayPower); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_POWER_TRAY_POWER_H_
diff --git a/ash/common/system/chromeos/power/tray_power_unittest.cc b/ash/common/system/chromeos/power/tray_power_unittest.cc new file mode 100644 index 0000000..76f3e17 --- /dev/null +++ b/ash/common/system/chromeos/power/tray_power_unittest.cc
@@ -0,0 +1,434 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/power/tray_power.h" + +#include <map> +#include <memory> +#include <string> + +#include "ash/test/ash_test_base.h" +#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" +#include "ui/message_center/fake_message_center.h" + +using message_center::Notification; +using power_manager::PowerSupplyProperties; + +namespace { + +class MockMessageCenter : public message_center::FakeMessageCenter { + public: + MockMessageCenter() : add_count_(0), remove_count_(0), update_count_(0) {} + ~MockMessageCenter() override {} + + int add_count() const { return add_count_; } + int remove_count() const { return remove_count_; } + int update_count() const { return update_count_; } + + // message_center::FakeMessageCenter overrides: + void AddNotification(std::unique_ptr<Notification> notification) override { + add_count_++; + notifications_.insert( + std::make_pair(notification->id(), std::move(notification))); + } + void RemoveNotification(const std::string& id, bool by_user) override { + Notification* notification = FindVisibleNotificationById(id); + if (notification && notification->delegate()) + notification->delegate()->Close(by_user); + remove_count_++; + notifications_.erase(id); + } + void UpdateNotification( + const std::string& id, + std::unique_ptr<Notification> new_notification) override { + update_count_++; + Notification* notification = FindVisibleNotificationById(id); + if (notification) + notifications_.erase(id); + notifications_.insert( + std::make_pair(new_notification->id(), std::move(new_notification))); + } + + Notification* FindVisibleNotificationById(const std::string& id) override { + auto it = notifications_.find(id); + return it == notifications_.end() ? NULL : it->second.get(); + } + + private: + int add_count_; + int remove_count_; + int update_count_; + std::map<std::string, std::unique_ptr<Notification>> notifications_; + + DISALLOW_COPY_AND_ASSIGN(MockMessageCenter); +}; + +} // namespace + +namespace ash { + +class TrayPowerTest : public test::AshTestBase { + public: + TrayPowerTest() {} + ~TrayPowerTest() override {} + + MockMessageCenter* message_center() { return message_center_.get(); } + TrayPower* tray_power() { return tray_power_.get(); } + + // test::AshTestBase::SetUp() overrides: + void SetUp() override { + test::AshTestBase::SetUp(); + message_center_.reset(new MockMessageCenter()); + tray_power_.reset(new TrayPower(NULL, message_center_.get())); + } + + void TearDown() override { + tray_power_.reset(); + message_center_.reset(); + test::AshTestBase::TearDown(); + } + + TrayPower::NotificationState notification_state() const { + return tray_power_->notification_state_; + } + + bool MaybeShowUsbChargerNotification(const PowerSupplyProperties& proto) { + PowerStatus::Get()->SetProtoForTesting(proto); + return tray_power_->MaybeShowUsbChargerNotification(); + } + + void MaybeShowDualRoleNotification(const PowerSupplyProperties& proto) { + PowerStatus::Get()->SetProtoForTesting(proto); + tray_power_->MaybeShowDualRoleNotification(); + } + + void UpdateNotificationState(const PowerSupplyProperties& proto, + TrayPower::NotificationState expected_state, + bool expected_add, + bool expected_remove) { + int prev_add = message_center_->add_count(); + int prev_remove = message_center_->remove_count(); + PowerStatus::Get()->SetProtoForTesting(proto); + tray_power_->OnPowerStatusChanged(); + EXPECT_EQ(expected_state, notification_state()); + EXPECT_EQ(expected_add, message_center_->add_count() == prev_add + 1); + EXPECT_EQ(expected_remove, + message_center_->remove_count() == prev_remove + 1); + } + + void SetUsbChargerConnected(bool connected) { + tray_power_->usb_charger_was_connected_ = connected; + } + + // Returns a discharging PowerSupplyProperties more appropriate for testing. + static PowerSupplyProperties DefaultPowerSupplyProperties() { + PowerSupplyProperties proto; + proto.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED); + proto.set_battery_state( + power_manager::PowerSupplyProperties_BatteryState_DISCHARGING); + proto.set_battery_percent(50.0); + proto.set_battery_time_to_empty_sec(3 * 60 * 60); + proto.set_battery_time_to_full_sec(2 * 60 * 60); + proto.set_is_calculating_battery_time(false); + return proto; + } + + private: + std::unique_ptr<MockMessageCenter> message_center_; + std::unique_ptr<TrayPower> tray_power_; + + DISALLOW_COPY_AND_ASSIGN(TrayPowerTest); +}; + +TEST_F(TrayPowerTest, MaybeShowUsbChargerNotification) { + PowerSupplyProperties discharging = DefaultPowerSupplyProperties(); + EXPECT_FALSE(MaybeShowUsbChargerNotification(discharging)); + EXPECT_EQ(0, message_center()->add_count()); + EXPECT_EQ(0, message_center()->remove_count()); + + // Notification shows when connecting a USB charger. + PowerSupplyProperties usb_connected = DefaultPowerSupplyProperties(); + usb_connected.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected)); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(0, message_center()->remove_count()); + SetUsbChargerConnected(true); + + // Change in charge does not trigger the notification again. + PowerSupplyProperties more_charge = DefaultPowerSupplyProperties(); + more_charge.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + more_charge.set_battery_time_to_full_sec(60 * 60); + more_charge.set_battery_percent(75.0); + EXPECT_FALSE(MaybeShowUsbChargerNotification(more_charge)); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(0, message_center()->remove_count()); + + // Disconnecting a USB charger with the notification showing should close + // the notification. + EXPECT_TRUE(MaybeShowUsbChargerNotification(discharging)); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(1, message_center()->remove_count()); + SetUsbChargerConnected(false); + + // Notification shows when connecting a USB charger again. + EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected)); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(1, message_center()->remove_count()); + SetUsbChargerConnected(true); + + // Notification hides when external power switches to AC. + PowerSupplyProperties ac_charger = DefaultPowerSupplyProperties(); + ac_charger.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_AC); + EXPECT_TRUE(MaybeShowUsbChargerNotification(ac_charger)); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(2, message_center()->remove_count()); + SetUsbChargerConnected(false); + + // Notification shows when external power switches back to USB. + EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected)); + EXPECT_EQ(3, message_center()->add_count()); + EXPECT_EQ(2, message_center()->remove_count()); + SetUsbChargerConnected(true); + + // Notification does not re-appear after being manually dismissed if + // power supply flickers between AC and USB charger. + message_center()->RemoveNotification(TrayPower::kUsbNotificationId, true); + EXPECT_EQ(3, message_center()->remove_count()); + EXPECT_TRUE(MaybeShowUsbChargerNotification(ac_charger)); + SetUsbChargerConnected(false); + EXPECT_FALSE(MaybeShowUsbChargerNotification(usb_connected)); + EXPECT_EQ(3, message_center()->add_count()); + SetUsbChargerConnected(true); + + // Notification appears again after being manually dismissed if the charger + // is removed, and then a USB charger is attached. + MaybeShowUsbChargerNotification(discharging); + EXPECT_EQ(3, message_center()->add_count()); + SetUsbChargerConnected(false); + MaybeShowUsbChargerNotification(usb_connected); + EXPECT_EQ(4, message_center()->add_count()); + SetUsbChargerConnected(true); +} + +TEST_F(TrayPowerTest, MaybeShowDualRoleNotification) { + PowerSupplyProperties discharging = DefaultPowerSupplyProperties(); + discharging.set_supports_dual_role_devices(true); + MaybeShowDualRoleNotification(discharging); + EXPECT_EQ(0, message_center()->add_count()); + EXPECT_EQ(0, message_center()->update_count()); + EXPECT_EQ(0, message_center()->remove_count()); + + // Notification shows when connecting a dual-role device. + PowerSupplyProperties dual_role = DefaultPowerSupplyProperties(); + dual_role.set_supports_dual_role_devices(true); + power_manager::PowerSupplyProperties_PowerSource* source = + dual_role.add_available_external_power_source(); + source->set_id("dual-role1"); + source->set_active_by_default(false); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(0, message_center()->update_count()); + EXPECT_EQ(0, message_center()->remove_count()); + + // Connecting another dual-role device updates the notification to be plural. + source = dual_role.add_available_external_power_source(); + source->set_id("dual-role2"); + source->set_active_by_default(false); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(1, message_center()->update_count()); + EXPECT_EQ(0, message_center()->remove_count()); + + // Connecting a 3rd dual-role device doesn't affect the notification. + source = dual_role.add_available_external_power_source(); + source->set_id("dual-role3"); + source->set_active_by_default(false); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(1, message_center()->update_count()); + EXPECT_EQ(0, message_center()->remove_count()); + + // Connecting a legacy USB device removes the notification. + PowerSupplyProperties legacy(dual_role); + power_manager::PowerSupplyProperties_PowerSource* legacy_source = + legacy.add_available_external_power_source(); + legacy_source->set_id("legacy"); + legacy_source->set_active_by_default(true); + legacy.set_external_power_source_id("legacy"); + legacy.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + MaybeShowDualRoleNotification(legacy); + EXPECT_EQ(1, message_center()->add_count()); + EXPECT_EQ(1, message_center()->update_count()); + EXPECT_EQ(1, message_center()->remove_count()); + + // Removing the legacy USB device adds the notification again. + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(1, message_center()->update_count()); + EXPECT_EQ(1, message_center()->remove_count()); + + // Charging from the device updates the notification. + dual_role.set_external_power_source_id("dual-role1"); + dual_role.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(2, message_center()->update_count()); + EXPECT_EQ(1, message_center()->remove_count()); + + // Adding a device as a sink doesn't change the notification, because the + // notification exposes the source. + source = dual_role.add_available_external_power_source(); + source->set_active_by_default(false); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(2, message_center()->update_count()); + EXPECT_EQ(1, message_center()->remove_count()); + + // Changing the source to a sink changes the notification. + dual_role.set_external_power_source_id(""); + dual_role.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(3, message_center()->update_count()); + EXPECT_EQ(1, message_center()->remove_count()); + + // An unrelated change has no effect. + dual_role.set_battery_time_to_empty_sec(2 * 60 * 60); + MaybeShowDualRoleNotification(dual_role); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(3, message_center()->update_count()); + EXPECT_EQ(1, message_center()->remove_count()); + + // Removing devices hides the notification. + MaybeShowDualRoleNotification(discharging); + EXPECT_EQ(2, message_center()->add_count()); + EXPECT_EQ(3, message_center()->update_count()); + EXPECT_EQ(2, message_center()->remove_count()); +} + +TEST_F(TrayPowerTest, UpdateNotificationState) { + // No notifications when no battery present. + PowerSupplyProperties no_battery = DefaultPowerSupplyProperties(); + no_battery.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_AC); + no_battery.set_battery_state( + power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT); + { + SCOPED_TRACE("No notifications when no battery present"); + UpdateNotificationState(no_battery, TrayPower::NOTIFICATION_NONE, false, + false); + } + + // No notification when calculating remaining battery time. + PowerSupplyProperties calculating = DefaultPowerSupplyProperties(); + calculating.set_is_calculating_battery_time(true); + { + SCOPED_TRACE("No notification when calculating remaining battery time"); + UpdateNotificationState(calculating, TrayPower::NOTIFICATION_NONE, false, + false); + } + + // No notification when charging. + PowerSupplyProperties charging = DefaultPowerSupplyProperties(); + charging.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_AC); + charging.set_battery_state( + power_manager::PowerSupplyProperties_BatteryState_CHARGING); + { + SCOPED_TRACE("No notification when charging"); + UpdateNotificationState(charging, TrayPower::NOTIFICATION_NONE, false, + false); + } + + // When the rounded minutes-to-empty are above the threshold, no notification + // should be shown. + PowerSupplyProperties low = DefaultPowerSupplyProperties(); + low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 30); + { + SCOPED_TRACE("No notification when time to empty above threshold"); + UpdateNotificationState(low, TrayPower::NOTIFICATION_NONE, false, false); + } + + // When the rounded value matches the threshold, the notification should + // appear. + low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 29); + { + SCOPED_TRACE("Notification when time to empty matches threshold"); + UpdateNotificationState(low, TrayPower::NOTIFICATION_LOW_POWER, true, + false); + } + + // It should persist at lower values. + low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 - 20); + { + SCOPED_TRACE("Notification persists at lower values"); + UpdateNotificationState(low, TrayPower::NOTIFICATION_LOW_POWER, false, + false); + } + + // The critical low battery notification should be shown when the rounded + // value is at the lower threshold. + PowerSupplyProperties critical = DefaultPowerSupplyProperties(); + critical.set_battery_time_to_empty_sec(TrayPower::kCriticalMinutes * 60 + 29); + { + SCOPED_TRACE("Critical notification when time to empty is critical"); + UpdateNotificationState(critical, TrayPower::NOTIFICATION_CRITICAL, true, + true); + } + + // The notification should be dismissed when the no-warning threshold is + // reached. + PowerSupplyProperties safe = DefaultPowerSupplyProperties(); + safe.set_battery_time_to_empty_sec(TrayPower::kNoWarningMinutes * 60 - 29); + { + SCOPED_TRACE("Notification removed when battery not low"); + UpdateNotificationState(safe, TrayPower::NOTIFICATION_NONE, false, true); + } + + // Test that rounded percentages are used when a USB charger is connected. + PowerSupplyProperties low_usb = DefaultPowerSupplyProperties(); + low_usb.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.5); + { + SCOPED_TRACE("No notification for rounded battery percent"); + UpdateNotificationState(low_usb, TrayPower::NOTIFICATION_NONE, true, false); + } + + low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.49); + { + SCOPED_TRACE("Notification for rounded low power percent"); + UpdateNotificationState(low_usb, TrayPower::NOTIFICATION_LOW_POWER, true, + false); + } + + PowerSupplyProperties critical_usb = DefaultPowerSupplyProperties(); + critical_usb.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + critical_usb.set_battery_percent(TrayPower::kCriticalPercentage + 0.2); + { + SCOPED_TRACE("Notification for rounded critical power percent"); + UpdateNotificationState(critical_usb, TrayPower::NOTIFICATION_CRITICAL, + true, true); + } + + PowerSupplyProperties safe_usb = DefaultPowerSupplyProperties(); + safe_usb.set_external_power( + power_manager::PowerSupplyProperties_ExternalPower_USB); + safe_usb.set_battery_percent(TrayPower::kNoWarningPercentage - 0.1); + { + SCOPED_TRACE("Notification removed for rounded percent above threshold"); + UpdateNotificationState(safe_usb, TrayPower::NOTIFICATION_NONE, false, + true); + } +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/screen_security/screen_capture_observer.h b/ash/common/system/chromeos/screen_security/screen_capture_observer.h new file mode 100644 index 0000000..854cb4a2 --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_capture_observer.h
@@ -0,0 +1,29 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_CAPTURE_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_CAPTURE_OBSERVER_H_ + +#include "base/callback.h" +#include "base/strings/string16.h" + +namespace ash { + +class ScreenCaptureObserver { + public: + // Called when screen capture is started. + virtual void OnScreenCaptureStart( + const base::Closure& stop_callback, + const base::string16& screen_capture_status) = 0; + + // Called when screen capture is stopped. + virtual void OnScreenCaptureStop() = 0; + + protected: + virtual ~ScreenCaptureObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_CAPTURE_OBSERVER_H_
diff --git a/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc b/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc new file mode 100644 index 0000000..d845f67 --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_capture_tray_item.cc
@@ -0,0 +1,108 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/screen_security/screen_capture_tray_item.h" + +#include <utility> + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" + +using message_center::Notification; + +namespace ash { +namespace { + +const char kScreenCaptureNotificationId[] = "chrome://screen/capture"; + +} // namespace + +ScreenCaptureTrayItem::ScreenCaptureTrayItem(SystemTray* system_tray) + : ScreenTrayItem(system_tray, UMA_SCREEN_CAPTURE) { + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->system_tray_notifier()->AddScreenCaptureObserver(this); +} + +ScreenCaptureTrayItem::~ScreenCaptureTrayItem() { + WmShell::Get()->RemoveShellObserver(this); + WmShell::Get()->system_tray_notifier()->RemoveScreenCaptureObserver(this); +} + +views::View* ScreenCaptureTrayItem::CreateDefaultView(LoginStatus status) { + set_default_view(new tray::ScreenStatusView( + this, screen_capture_status_, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP))); + return default_view(); +} + +void ScreenCaptureTrayItem::CreateOrUpdateNotification() { + message_center::RichNotificationData data; + data.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP))); + ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kScreenCaptureNotificationId, + screen_capture_status_, base::string16() /* body is blank */, + resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE_DARK), + base::string16() /* display_source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierScreenCapture), + data, new tray::ScreenNotificationDelegate(this))); + notification->SetSystemPriority(); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +std::string ScreenCaptureTrayItem::GetNotificationId() { + return kScreenCaptureNotificationId; +} + +void ScreenCaptureTrayItem::RecordStoppedFromDefaultViewMetric() { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_SCREEN_CAPTURE_DEFAULT_STOP); +} + +void ScreenCaptureTrayItem::RecordStoppedFromNotificationViewMetric() { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_SCREEN_CAPTURE_NOTIFICATION_STOP); +} + +void ScreenCaptureTrayItem::OnScreenCaptureStart( + const base::Closure& stop_callback, + const base::string16& screen_capture_status) { + screen_capture_status_ = screen_capture_status; + + // We do not want to show the screen capture tray item and the chromecast + // casting tray item at the same time. We will hide this tray item. + // + // This suppression technique is currently dependent on the order + // that OnScreenCaptureStart and OnCastingSessionStartedOrStopped + // get invoked. OnCastingSessionStartedOrStopped currently gets + // called first. + if (is_casting_) + return; + + Start(stop_callback); +} + +void ScreenCaptureTrayItem::OnScreenCaptureStop() { + // We do not need to run the stop callback when + // screen capture is stopped externally. + set_is_started(false); + Update(); +} + +void ScreenCaptureTrayItem::OnCastingSessionStartedOrStopped(bool started) { + is_casting_ = started; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/screen_security/screen_capture_tray_item.h b/ash/common/system/chromeos/screen_security/screen_capture_tray_item.h new file mode 100644 index 0000000..8d56a0d --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_capture_tray_item.h
@@ -0,0 +1,53 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_CAPTURE_TRAY_ITEM_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_CAPTURE_TRAY_ITEM_H_ + +#include "ash/common/shell_observer.h" +#include "ash/common/system/chromeos/screen_security/screen_capture_observer.h" +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" +#include "base/macros.h" + +namespace views { +class View; +} + +namespace ash { + +class ASH_EXPORT ScreenCaptureTrayItem : public ScreenTrayItem, + public ScreenCaptureObserver, + public ShellObserver { + public: + explicit ScreenCaptureTrayItem(SystemTray* system_tray); + ~ScreenCaptureTrayItem() override; + + private: + // Overridden from SystemTrayItem. + views::View* CreateDefaultView(LoginStatus status) override; + + // Overridden from ScreenTrayItem. + void CreateOrUpdateNotification() override; + std::string GetNotificationId() override; + void RecordStoppedFromDefaultViewMetric() override; + void RecordStoppedFromNotificationViewMetric() override; + + // Overridden from ScreenCaptureObserver. + void OnScreenCaptureStart( + const base::Closure& stop_callback, + const base::string16& screen_capture_status) override; + void OnScreenCaptureStop() override; + + // Overridden from ShellObserver. + void OnCastingSessionStartedOrStopped(bool started) override; + + base::string16 screen_capture_status_; + bool is_casting_ = false; + + DISALLOW_COPY_AND_ASSIGN(ScreenCaptureTrayItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_CAPTURE_TRAY_ITEM_H_
diff --git a/ash/common/system/chromeos/screen_security/screen_share_observer.h b/ash/common/system/chromeos/screen_security/screen_share_observer.h new file mode 100644 index 0000000..fd8d86521 --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_share_observer.h
@@ -0,0 +1,28 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_SHARE_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_SHARE_OBSERVER_H_ + +#include "base/callback.h" +#include "base/strings/string16.h" + +namespace ash { + +class ScreenShareObserver { + public: + // Called when screen share is started. + virtual void OnScreenShareStart(const base::Closure& stop_callback, + const base::string16& helper_name) = 0; + + // Called when screen share is stopped. + virtual void OnScreenShareStop() = 0; + + protected: + virtual ~ScreenShareObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_SHARE_OBSERVER_H_
diff --git a/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc b/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc new file mode 100644 index 0000000..61d2632 --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_share_tray_item.cc
@@ -0,0 +1,97 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/screen_security/screen_share_tray_item.h" + +#include <utility> + +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" + +using message_center::Notification; + +namespace ash { +namespace { + +const char kScreenShareNotificationId[] = "chrome://screen/share"; +} + +ScreenShareTrayItem::ScreenShareTrayItem(SystemTray* system_tray) + : ScreenTrayItem(system_tray, UMA_SCREEN_SHARE) { + WmShell::Get()->system_tray_notifier()->AddScreenShareObserver(this); +} + +ScreenShareTrayItem::~ScreenShareTrayItem() { + WmShell::Get()->system_tray_notifier()->RemoveScreenShareObserver(this); +} + +views::View* ScreenShareTrayItem::CreateDefaultView(LoginStatus status) { + set_default_view(new tray::ScreenStatusView( + this, + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED), + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP))); + return default_view(); +} + +void ScreenShareTrayItem::CreateOrUpdateNotification() { + base::string16 help_label_text; + if (!helper_name_.empty()) { + help_label_text = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED_NAME, helper_name_); + } else { + help_label_text = l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED); + } + + message_center::RichNotificationData data; + data.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP))); + ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kScreenShareNotificationId, + help_label_text, base::string16() /* body is blank */, + resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE_DARK), + base::string16() /* display_source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierScreenShare), + data, new tray::ScreenNotificationDelegate(this))); + notification->SetSystemPriority(); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +std::string ScreenShareTrayItem::GetNotificationId() { + return kScreenShareNotificationId; +} + +void ScreenShareTrayItem::RecordStoppedFromDefaultViewMetric() { + // Intentionally not recording a metric. +} + +void ScreenShareTrayItem::RecordStoppedFromNotificationViewMetric() { + // Intentionally not recording a metric. +} + +void ScreenShareTrayItem::OnScreenShareStart( + const base::Closure& stop_callback, + const base::string16& helper_name) { + helper_name_ = helper_name; + Start(stop_callback); +} + +void ScreenShareTrayItem::OnScreenShareStop() { + // We do not need to run the stop callback + // when screening is stopped externally. + set_is_started(false); + Update(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/screen_security/screen_share_tray_item.h b/ash/common/system/chromeos/screen_security/screen_share_tray_item.h new file mode 100644 index 0000000..3c74f23 --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_share_tray_item.h
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_SHARE_TRAY_ITEM_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_SHARE_TRAY_ITEM_H_ + +#include "ash/common/system/chromeos/screen_security/screen_share_observer.h" +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" +#include "base/macros.h" + +namespace views { +class View; +} + +namespace ash { + +class ASH_EXPORT ScreenShareTrayItem : public ScreenTrayItem, + public ScreenShareObserver { + public: + explicit ScreenShareTrayItem(SystemTray* system_tray); + ~ScreenShareTrayItem() override; + + private: + // Overridden from SystemTrayItem. + views::View* CreateDefaultView(LoginStatus status) override; + + // Overridden from ScreenTrayItem. + void CreateOrUpdateNotification() override; + std::string GetNotificationId() override; + void RecordStoppedFromDefaultViewMetric() override; + void RecordStoppedFromNotificationViewMetric() override; + + // Overridden from ScreenShareObserver. + void OnScreenShareStart(const base::Closure& stop_callback, + const base::string16& helper_name) override; + void OnScreenShareStop() override; + + base::string16 helper_name_; + + DISALLOW_COPY_AND_ASSIGN(ScreenShareTrayItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_SHARE_TRAY_ITEM_H_
diff --git a/ash/common/system/chromeos/screen_security/screen_tray_item.cc b/ash/common/system/chromeos/screen_security/screen_tray_item.cc new file mode 100644 index 0000000..8c0ebae --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_tray_item.cc
@@ -0,0 +1,195 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/message_center/message_center.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { +namespace tray { + +// ScreenTrayView implementations. +ScreenTrayView::ScreenTrayView(ScreenTrayItem* screen_tray_item) + : TrayItemView(screen_tray_item), screen_tray_item_(screen_tray_item) { + CreateImageView(); + if (MaterialDesignController::UseMaterialDesignSystemIcons()) { + image_view()->SetImage( + gfx::CreateVectorIcon(kSystemTrayScreenShareIcon, kTrayIconColor)); + } else { + image_view()->SetImage(ui::ResourceBundle::GetSharedInstance() + .GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE) + .ToImageSkia()); + } + Update(); +} + +ScreenTrayView::~ScreenTrayView() {} + +void ScreenTrayView::Update() { + SetVisible(screen_tray_item_->is_started()); +} + +// ScreenStatusView implementations. +ScreenStatusView::ScreenStatusView(ScreenTrayItem* screen_tray_item, + const base::string16& label_text, + const base::string16& stop_button_text) + : screen_tray_item_(screen_tray_item), + icon_(nullptr), + label_(nullptr), + stop_button_(nullptr), + label_text_(label_text), + stop_button_text_(stop_button_text) { + CreateItems(); + TriView* tri_view(TrayPopupUtils::CreateDefaultRowView()); + SetLayoutManager(new views::FillLayout); + AddChildView(tri_view); + tri_view->AddView(TriView::Container::START, icon_); + // TODO(bruthig): Multiline Labels don't lay out well with borders so we add + // the border to the Label's container instead. See https://crbug.com/678337 & + // https://crbug.com/682221. + tri_view->SetContainerBorder( + TriView::Container::CENTER, + views::CreateEmptyBorder(0, 0, 0, kTrayPopupLabelRightPadding)); + tri_view->AddView(TriView::Container::CENTER, label_); + tri_view->AddView(TriView::Container::END, stop_button_); + tri_view->SetContainerBorder( + TriView::Container::END, + views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); + if (screen_tray_item_) + UpdateFromScreenTrayItem(); +} + +ScreenStatusView::~ScreenStatusView() {} + +void ScreenStatusView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + DCHECK(sender == stop_button_); + screen_tray_item_->Stop(); + screen_tray_item_->RecordStoppedFromDefaultViewMetric(); +} + +void ScreenStatusView::CreateItems() { + const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial(); + icon_ = TrayPopupUtils::CreateMainImageView(); + icon_->SetImage(gfx::CreateVectorIcon( + kSystemMenuScreenShareIcon, TrayPopupItemStyle::GetIconColor( + TrayPopupItemStyle::ColorStyle::ACTIVE))); + if (!use_md) { + set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + icon_->SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE_DARK) + .ToImageSkia()); + } + + label_ = TrayPopupUtils::CreateDefaultLabel(); + label_->SetMultiLine(true); + label_->SetText(label_text_); + // TODO(bruthig): Multiline Labels don't lay out well with borders. + // See https://crbug.com/678337 & https://crbug.com/682221. + label_->SetBorder(nullptr); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + style.SetupLabel(label_); + + stop_button_ = TrayPopupUtils::CreateTrayPopupButton(this, stop_button_text_); +} + +void ScreenStatusView::UpdateFromScreenTrayItem() { + SetVisible(screen_tray_item_->is_started()); +} + +ScreenNotificationDelegate::ScreenNotificationDelegate( + ScreenTrayItem* screen_tray) + : screen_tray_(screen_tray) {} + +ScreenNotificationDelegate::~ScreenNotificationDelegate() {} + +void ScreenNotificationDelegate::ButtonClick(int button_index) { + DCHECK_EQ(0, button_index); + screen_tray_->Stop(); + screen_tray_->RecordStoppedFromNotificationViewMetric(); +} + +} // namespace tray + +ScreenTrayItem::ScreenTrayItem(SystemTray* system_tray, UmaType uma_type) + : SystemTrayItem(system_tray, uma_type), + tray_view_(nullptr), + default_view_(nullptr), + is_started_(false), + stop_callback_(base::Bind(&base::DoNothing)) {} + +ScreenTrayItem::~ScreenTrayItem() {} + +void ScreenTrayItem::Update() { + if (tray_view_) + tray_view_->Update(); + if (default_view_) + default_view_->UpdateFromScreenTrayItem(); + if (is_started_) { + CreateOrUpdateNotification(); + } else { + message_center::MessageCenter::Get()->RemoveNotification( + GetNotificationId(), false /* by_user */); + } +} + +void ScreenTrayItem::Start(const base::Closure& stop_callback) { + stop_callback_ = stop_callback; + is_started_ = true; + + if (tray_view_) + tray_view_->Update(); + + if (default_view_) + default_view_->UpdateFromScreenTrayItem(); + + if (!system_tray()->HasSystemBubbleType( + SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { + CreateOrUpdateNotification(); + } +} + +void ScreenTrayItem::Stop() { + is_started_ = false; + Update(); + + if (stop_callback_.is_null()) + return; + + base::Closure callback = stop_callback_; + stop_callback_.Reset(); + callback.Run(); +} + +views::View* ScreenTrayItem::CreateTrayView(LoginStatus status) { + tray_view_ = new tray::ScreenTrayView(this); + return tray_view_; +} + +void ScreenTrayItem::RecordStoppedFromDefaultViewMetric() {} + +void ScreenTrayItem::RecordStoppedFromNotificationViewMetric() {} + +void ScreenTrayItem::DestroyTrayView() { + tray_view_ = nullptr; +} + +void ScreenTrayItem::DestroyDefaultView() { + default_view_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/screen_security/screen_tray_item.h b/ash/common/system/chromeos/screen_security/screen_tray_item.h new file mode 100644 index 0000000..5ed992a --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_tray_item.h
@@ -0,0 +1,140 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_TRAY_ITEM_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_TRAY_ITEM_H_ + +#include <string> + +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_notification_view.h" +#include "base/macros.h" +#include "ui/message_center/notification_delegate.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/image_view.h" + +namespace views { +class View; +} + +namespace ash { +class ScreenTrayItem; + +namespace tray { + +class ScreenTrayView : public TrayItemView { + public: + explicit ScreenTrayView(ScreenTrayItem* screen_tray_item); + ~ScreenTrayView() override; + + void Update(); + + private: + ScreenTrayItem* screen_tray_item_; + + DISALLOW_COPY_AND_ASSIGN(ScreenTrayView); +}; + +class ScreenStatusView : public views::View, public views::ButtonListener { + public: + ScreenStatusView(ScreenTrayItem* screen_tray_item, + const base::string16& label_text, + const base::string16& stop_button_text); + ~ScreenStatusView() override; + + // Overridden from views::ButtonListener. + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + void CreateItems(); + void UpdateFromScreenTrayItem(); + + protected: + views::ImageView* icon() { return icon_; } + views::Label* label() { return label_; } + views::Button* stop_button() { return stop_button_; } + + private: + // The controller for this view. May be null. + ScreenTrayItem* screen_tray_item_; + views::ImageView* icon_; + views::Label* label_; + views::Button* stop_button_; + base::string16 label_text_; + base::string16 stop_button_text_; + + DISALLOW_COPY_AND_ASSIGN(ScreenStatusView); +}; + +class ScreenNotificationDelegate : public message_center::NotificationDelegate { + public: + explicit ScreenNotificationDelegate(ScreenTrayItem* screen_tray); + + // message_center::NotificationDelegate overrides: + void ButtonClick(int button_index) override; + + protected: + ~ScreenNotificationDelegate() override; + + private: + ScreenTrayItem* screen_tray_; + + DISALLOW_COPY_AND_ASSIGN(ScreenNotificationDelegate); +}; + +} // namespace tray + +// The base tray item for screen capture and screen sharing. The +// Start method brings up a notification and a tray item, and the user +// can stop the screen capture/sharing by pressing the stop button. +class ASH_EXPORT ScreenTrayItem : public SystemTrayItem { + public: + ScreenTrayItem(SystemTray* system_tray, UmaType uma_type); + ~ScreenTrayItem() override; + + tray::ScreenTrayView* tray_view() { return tray_view_; } + + tray::ScreenStatusView* default_view() { return default_view_; } + void set_default_view(tray::ScreenStatusView* default_view) { + default_view_ = default_view; + } + + bool is_started() const { return is_started_; } + void set_is_started(bool is_started) { is_started_ = is_started; } + + void Update(); + void Start(const base::Closure& stop_callback); + void Stop(); + + // Creates or updates the notification for the tray item. + virtual void CreateOrUpdateNotification() = 0; + + // Returns the id of the notification for the tray item. + virtual std::string GetNotificationId() = 0; + + // Called after Stop() is invoked from the default view. + virtual void RecordStoppedFromDefaultViewMetric() = 0; + + // Called after Stop() is invoked from the notification view. + virtual void RecordStoppedFromNotificationViewMetric() = 0; + + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override = 0; + void DestroyTrayView() override; + void DestroyDefaultView() override; + + private: + tray::ScreenTrayView* tray_view_; + tray::ScreenStatusView* default_view_; + bool is_started_; + base::Closure stop_callback_; + + DISALLOW_COPY_AND_ASSIGN(ScreenTrayItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SCREEN_SECURITY_SCREEN_TRAY_ITEM_H_
diff --git a/ash/common/system/chromeos/screen_security/screen_tray_item_unittest.cc b/ash/common/system/chromeos/screen_security/screen_tray_item_unittest.cc new file mode 100644 index 0000000..764b2f4 --- /dev/null +++ b/ash/common/system/chromeos/screen_security/screen_tray_item_unittest.cc
@@ -0,0 +1,223 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" + +#include "ash/common/system/chromeos/screen_security/screen_capture_tray_item.h" +#include "ash/common/system/chromeos/screen_security/screen_share_tray_item.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/test/ash_test.h" +#include "ash/common/wm_shell.h" +#include "base/callback.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/events/event.h" +#include "ui/events/event_utils.h" +#include "ui/gfx/geometry/point.h" +#include "ui/message_center/message_center.h" +#include "ui/views/view.h" + +namespace ash { + +// Test with unicode strings. +const char kTestScreenCaptureAppName[] = + "\xE0\xB2\xA0\x5F\xE0\xB2\xA0 (Screen Capture Test)"; +const char kTestScreenShareHelperName[] = + "\xE5\xAE\x8B\xE8\x85\xBE (Screen Share Test)"; + +void ClickViewCenter(views::View* view) { + gfx::Point click_location_in_local = + gfx::Point(view->width() / 2, view->height() / 2); + view->OnMousePressed(ui::MouseEvent( + ui::ET_MOUSE_PRESSED, click_location_in_local, click_location_in_local, + ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE)); +} + +class ScreenTrayItemTest : public AshTest { + public: + ScreenTrayItemTest() : tray_item_(NULL), stop_callback_hit_count_(0) {} + ~ScreenTrayItemTest() override {} + + ScreenTrayItem* tray_item() { return tray_item_; } + void set_tray_item(ScreenTrayItem* tray_item) { tray_item_ = tray_item; } + + int stop_callback_hit_count() const { return stop_callback_hit_count_; } + + void SetUp() override { + AshTest::SetUp(); + TrayItemView::DisableAnimationsForTest(); + } + + void StartSession() { + tray_item_->Start( + base::Bind(&ScreenTrayItemTest::StopCallback, base::Unretained(this))); + } + + void StopSession() { tray_item_->Stop(); } + + void StopCallback() { stop_callback_hit_count_++; } + + private: + ScreenTrayItem* tray_item_; + int stop_callback_hit_count_; + + DISALLOW_COPY_AND_ASSIGN(ScreenTrayItemTest); +}; + +class ScreenCaptureTest : public ScreenTrayItemTest { + public: + ScreenCaptureTest() {} + ~ScreenCaptureTest() override {} + + void SetUp() override { + ScreenTrayItemTest::SetUp(); + // This tray item is owned by its parent system tray view and will + // be deleted automatically when its parent is destroyed in AshTestBase. + ScreenTrayItem* item = new ScreenCaptureTrayItem(GetPrimarySystemTray()); + GetPrimarySystemTray()->AddTrayItem(base::WrapUnique(item)); + set_tray_item(item); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ScreenCaptureTest); +}; + +class ScreenShareTest : public ScreenTrayItemTest { + public: + ScreenShareTest() {} + ~ScreenShareTest() override {} + + void SetUp() override { + ScreenTrayItemTest::SetUp(); + // This tray item is owned by its parent system tray view and will + // be deleted automatically when its parent is destroyed in AshTestBase. + ScreenTrayItem* item = new ScreenShareTrayItem(GetPrimarySystemTray()); + GetPrimarySystemTray()->AddTrayItem(base::WrapUnique(item)); + set_tray_item(item); + } + + DISALLOW_COPY_AND_ASSIGN(ScreenShareTest); +}; + +void TestStartAndStop(ScreenTrayItemTest* test) { + ScreenTrayItem* tray_item = test->tray_item(); + + EXPECT_FALSE(tray_item->is_started()); + EXPECT_EQ(0, test->stop_callback_hit_count()); + + test->StartSession(); + EXPECT_TRUE(tray_item->is_started()); + + test->StopSession(); + EXPECT_FALSE(tray_item->is_started()); + EXPECT_EQ(1, test->stop_callback_hit_count()); +} + +TEST_F(ScreenCaptureTest, StartAndStop) { + TestStartAndStop(this); +} + +TEST_F(ScreenShareTest, StartAndStop) { + TestStartAndStop(this); +} + +void TestNotificationStartAndStop(ScreenTrayItemTest* test, + const base::Closure& start_function, + const base::Closure& stop_function) { + ScreenTrayItem* tray_item = test->tray_item(); + EXPECT_FALSE(tray_item->is_started()); + + start_function.Run(); + EXPECT_TRUE(tray_item->is_started()); + + // The stop callback shouldn't be called because we stopped + // through the notification system. + stop_function.Run(); + EXPECT_FALSE(tray_item->is_started()); + EXPECT_EQ(0, test->stop_callback_hit_count()); +} + +TEST_F(ScreenCaptureTest, NotificationStartAndStop) { + base::Closure start_function = base::Bind( + &SystemTrayNotifier::NotifyScreenCaptureStart, + base::Unretained(WmShell::Get()->system_tray_notifier()), + base::Bind(&ScreenTrayItemTest::StopCallback, base::Unretained(this)), + base::UTF8ToUTF16(kTestScreenCaptureAppName)); + + base::Closure stop_function = + base::Bind(&SystemTrayNotifier::NotifyScreenCaptureStop, + base::Unretained(WmShell::Get()->system_tray_notifier())); + + TestNotificationStartAndStop(this, start_function, stop_function); +} + +TEST_F(ScreenShareTest, NotificationStartAndStop) { + base::Closure start_func = base::Bind( + &SystemTrayNotifier::NotifyScreenShareStart, + base::Unretained(WmShell::Get()->system_tray_notifier()), + base::Bind(&ScreenTrayItemTest::StopCallback, base::Unretained(this)), + base::UTF8ToUTF16(kTestScreenShareHelperName)); + + base::Closure stop_func = + base::Bind(&SystemTrayNotifier::NotifyScreenShareStop, + base::Unretained(WmShell::Get()->system_tray_notifier())); + + TestNotificationStartAndStop(this, start_func, stop_func); +} + +void TestNotificationView(ScreenTrayItemTest* test) { + ScreenTrayItem* tray_item = test->tray_item(); + + test->StartSession(); + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + EXPECT_TRUE(message_center->FindVisibleNotificationById( + tray_item->GetNotificationId())); + test->StopSession(); +} + +TEST_F(ScreenCaptureTest, NotificationView) { + TestNotificationView(this); +} + +TEST_F(ScreenShareTest, NotificationView) { + TestNotificationView(this); +} + +void TestSystemTrayInteraction(ScreenTrayItemTest* test) { + ScreenTrayItem* tray_item = test->tray_item(); + EXPECT_FALSE(tray_item->tray_view()->visible()); + + std::vector<SystemTrayItem*> tray_items = + AshTest::GetPrimarySystemTray()->GetTrayItems(); + EXPECT_NE(std::find(tray_items.begin(), tray_items.end(), tray_item), + tray_items.end()); + + test->StartSession(); + EXPECT_TRUE(tray_item->tray_view()->visible()); + + // The default view should be created in a new bubble. + AshTest::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); + EXPECT_TRUE(tray_item->default_view()); + AshTest::GetPrimarySystemTray()->CloseSystemBubble(); + EXPECT_FALSE(tray_item->default_view()); + + test->StopSession(); + EXPECT_FALSE(tray_item->tray_view()->visible()); + + // The default view should not be visible because session is stopped. + AshTest::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); + EXPECT_FALSE(tray_item->default_view()->visible()); +} + +TEST_F(ScreenCaptureTest, SystemTrayInteraction) { + TestSystemTrayInteraction(this); +} + +TEST_F(ScreenShareTest, SystemTrayInteraction) { + TestSystemTrayInteraction(this); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/session/last_window_closed_observer.h b/ash/common/system/chromeos/session/last_window_closed_observer.h new file mode 100644 index 0000000..c19df95 --- /dev/null +++ b/ash/common/system/chromeos/session/last_window_closed_observer.h
@@ -0,0 +1,22 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LAST_WINDOW_CLOSED_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LAST_WINDOW_CLOSED_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class ASH_EXPORT LastWindowClosedObserver { + public: + virtual void OnLastWindowClosed() = 0; + + protected: + virtual ~LastWindowClosedObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LAST_WINDOW_CLOSED_OBSERVER_H_
diff --git a/ash/common/system/chromeos/session/logout_button_observer.h b/ash/common/system/chromeos/session/logout_button_observer.h new file mode 100644 index 0000000..c0e7ce3 --- /dev/null +++ b/ash/common/system/chromeos/session/logout_button_observer.h
@@ -0,0 +1,30 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_BUTTON_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_BUTTON_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "base/time/time.h" + +namespace ash { + +class ASH_EXPORT LogoutButtonObserver { + public: + virtual ~LogoutButtonObserver() {} + + // Called when the value of the kShowLogoutButtonInTray pref changes, which + // determines whether a logout button should be shown in the system tray + // during a session. + virtual void OnShowLogoutButtonInTrayChanged(bool show) = 0; + + // Called when the value of the kLogoutDialogDurationMs pref changes. + // |duration| is the duration for which the logout confirmation dialog is + // shown after the user has pressed the logout button. + virtual void OnLogoutDialogDurationChanged(base::TimeDelta duration) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_BUTTON_OBSERVER_H_
diff --git a/ash/common/system/chromeos/session/logout_button_tray.cc b/ash/common/system/chromeos/session/logout_button_tray.cc new file mode 100644 index 0000000..06574c0 --- /dev/null +++ b/ash/common/system/chromeos/session/logout_button_tray.cc
@@ -0,0 +1,132 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/session/logout_button_tray.h" + +#include <memory> +#include <utility> + +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/system/user/login_status.h" +#include "ash/common/wm_shell.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/logging.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/events/event.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/bubble/tray_bubble_view.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/button/label_button_border.h" +#include "ui/views/controls/button/md_text_button.h" +#include "ui/views/painter.h" + +namespace ash { + +LogoutButtonTray::LogoutButtonTray(WmShelf* wm_shelf) + : TrayBackgroundView(wm_shelf), + button_(nullptr), + login_status_(LoginStatus::NOT_LOGGED_IN), + show_logout_button_in_tray_(false) { + views::MdTextButton* button = + views::MdTextButton::Create(this, base::string16()); + button->SetProminent(true); + button->SetBgColorOverride(gfx::kGoogleRed700); + // Base font size + 2 = 14. + // TODO(estade): should this 2 be shared with other tray views? See + // crbug.com/623987 + button->AdjustFontSize(2); + button_ = button; + + // Since LogoutButtonTray has a red background and it is distinguished + // by itself, no separator is needed on its right side. + set_separator_visibility(false); + tray_container()->AddChildView(button_); + WmShell::Get()->system_tray_notifier()->AddLogoutButtonObserver(this); +} + +LogoutButtonTray::~LogoutButtonTray() { + WmShell::Get()->system_tray_notifier()->RemoveLogoutButtonObserver(this); +} + +void LogoutButtonTray::SetShelfAlignment(ShelfAlignment alignment) { + // We must first update the button so that + // TrayBackgroundView::SetShelfAlignment() can lay it out correctly. + UpdateButtonTextAndImage(login_status_, alignment); + TrayBackgroundView::SetShelfAlignment(alignment); +} + +base::string16 LogoutButtonTray::GetAccessibleNameForTray() { + return button_->GetText(); +} + +void LogoutButtonTray::HideBubbleWithView( + const views::TrayBubbleView* bubble_view) {} + +void LogoutButtonTray::ClickedOutsideBubble() {} + +void LogoutButtonTray::ButtonPressed(views::Button* sender, + const ui::Event& event) { + if (sender != button_) { + TrayBackgroundView::ButtonPressed(sender, event); + return; + } + + if (dialog_duration_ <= base::TimeDelta()) { + // Sign out immediately if |dialog_duration_| is non-positive. + WmShell::Get()->system_tray_controller()->SignOut(); + } else if (WmShell::Get()->logout_confirmation_controller()) { + WmShell::Get()->logout_confirmation_controller()->ConfirmLogout( + base::TimeTicks::Now() + dialog_duration_); + } +} + +void LogoutButtonTray::OnShowLogoutButtonInTrayChanged(bool show) { + show_logout_button_in_tray_ = show; + UpdateVisibility(); +} + +void LogoutButtonTray::OnLogoutDialogDurationChanged(base::TimeDelta duration) { + dialog_duration_ = duration; +} + +void LogoutButtonTray::UpdateAfterLoginStatusChange(LoginStatus login_status) { + UpdateButtonTextAndImage(login_status, shelf_alignment()); +} + +void LogoutButtonTray::UpdateVisibility() { + SetVisible(show_logout_button_in_tray_ && + login_status_ != LoginStatus::NOT_LOGGED_IN && + login_status_ != LoginStatus::LOCKED); +} + +void LogoutButtonTray::UpdateButtonTextAndImage(LoginStatus login_status, + ShelfAlignment alignment) { + login_status_ = login_status; + const base::string16 title = + user::GetLocalizedSignOutStringForStatus(login_status, false); + if (IsHorizontalAlignment(alignment)) { + button_->SetText(title); + button_->SetImage(views::LabelButton::STATE_NORMAL, gfx::ImageSkia()); + button_->SetMinSize(gfx::Size(0, kTrayItemSize)); + } else { + button_->SetText(base::string16()); + button_->SetAccessibleName(title); + button_->SetImage(views::LabelButton::STATE_NORMAL, + gfx::CreateVectorIcon(kShelfLogoutIcon, kTrayIconColor)); + button_->SetMinSize(gfx::Size(kTrayItemSize, kTrayItemSize)); + } + UpdateVisibility(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/session/logout_button_tray.h b/ash/common/system/chromeos/session/logout_button_tray.h new file mode 100644 index 0000000..cc0d3746 --- /dev/null +++ b/ash/common/system/chromeos/session/logout_button_tray.h
@@ -0,0 +1,58 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_BUTTON_TRAY_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_BUTTON_TRAY_H_ + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/common/system/chromeos/session/logout_button_observer.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "ui/views/controls/button/button.h" + +namespace views { +class LabelButton; +} + +namespace ash { + +// Adds a logout button to the launcher's status area if enabled by the +// kShowLogoutButtonInTray pref. +class ASH_EXPORT LogoutButtonTray : public TrayBackgroundView, + public LogoutButtonObserver { + public: + explicit LogoutButtonTray(WmShelf* wm_shelf); + ~LogoutButtonTray() override; + + // TrayBackgroundView: + void SetShelfAlignment(ShelfAlignment alignment) override; + base::string16 GetAccessibleNameForTray() override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void ClickedOutsideBubble() override; + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + // LogoutButtonObserver: + void OnShowLogoutButtonInTrayChanged(bool show) override; + void OnLogoutDialogDurationChanged(base::TimeDelta duration) override; + + void UpdateAfterLoginStatusChange(LoginStatus login_status); + + private: + void UpdateVisibility(); + void UpdateButtonTextAndImage(LoginStatus login_status, + ShelfAlignment alignment); + + views::LabelButton* button_; + LoginStatus login_status_; + bool show_logout_button_in_tray_; + base::TimeDelta dialog_duration_; + + DISALLOW_COPY_AND_ASSIGN(LogoutButtonTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_BUTTON_TRAY_H_
diff --git a/ash/common/system/chromeos/session/logout_confirmation_controller.cc b/ash/common/system/chromeos/session/logout_confirmation_controller.cc new file mode 100644 index 0000000..80726792b --- /dev/null +++ b/ash/common/system/chromeos/session/logout_confirmation_controller.cc
@@ -0,0 +1,108 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" + +#include <utility> + +#include "ash/common/login_status.h" +#include "ash/common/system/chromeos/session/logout_confirmation_dialog.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "base/location.h" +#include "base/time/default_tick_clock.h" +#include "base/time/tick_clock.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { +const int kLogoutConfirmationDelayInSeconds = 20; +} + +LogoutConfirmationController::LogoutConfirmationController( + const base::Closure& logout_closure) + : clock_(new base::DefaultTickClock), + logout_closure_(logout_closure), + dialog_(NULL), + logout_timer_(false, false) { + if (WmShell::HasInstance()) { + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->system_tray_notifier()->AddLastWindowClosedObserver(this); + } +} + +LogoutConfirmationController::~LogoutConfirmationController() { + if (WmShell::HasInstance()) { + WmShell::Get()->RemoveShellObserver(this); + WmShell::Get()->system_tray_notifier()->RemoveLastWindowClosedObserver( + this); + } + if (dialog_) + dialog_->ControllerGone(); +} + +void LogoutConfirmationController::ConfirmLogout(base::TimeTicks logout_time) { + if (!logout_time_.is_null() && logout_time >= logout_time_) { + // If a confirmation dialog is already being shown and its countdown expires + // no later than the |logout_time| requested now, keep the current dialog + // open. + return; + } + logout_time_ = logout_time; + + if (!dialog_) { + // Show confirmation dialog unless this is a unit test without a Shell. + if (WmShell::HasInstance()) + dialog_ = new LogoutConfirmationDialog(this, logout_time_); + } else { + dialog_->Update(logout_time_); + } + + logout_timer_.Start(FROM_HERE, logout_time_ - clock_->NowTicks(), + logout_closure_); +} + +void LogoutConfirmationController::SetClockForTesting( + std::unique_ptr<base::TickClock> clock) { + clock_ = std::move(clock); +} + +void LogoutConfirmationController::OnLockStateChanged(bool locked) { + if (!locked || logout_time_.is_null()) + return; + + // If the screen is locked while a confirmation dialog is being shown, close + // the dialog. + logout_time_ = base::TimeTicks(); + if (dialog_) + dialog_->GetWidget()->Close(); + logout_timer_.Stop(); +} + +void LogoutConfirmationController::OnLogoutConfirmed() { + logout_timer_.Stop(); + logout_closure_.Run(); +} + +void LogoutConfirmationController::OnDialogClosed() { + logout_time_ = base::TimeTicks(); + dialog_ = NULL; + logout_timer_.Stop(); +} + +void LogoutConfirmationController::OnLastWindowClosed() { + if (WmShell::Get()->system_tray_delegate()->GetUserLoginStatus() != + LoginStatus::PUBLIC) { + return; + } + + // Ask the user to confirm logout if a public session is in progress and the + // screen is not locked. + ConfirmLogout( + base::TimeTicks::Now() + + base::TimeDelta::FromSeconds(kLogoutConfirmationDelayInSeconds)); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/session/logout_confirmation_controller.h b/ash/common/system/chromeos/session/logout_confirmation_controller.h new file mode 100644 index 0000000..8634bc03 --- /dev/null +++ b/ash/common/system/chromeos/session/logout_confirmation_controller.h
@@ -0,0 +1,80 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_CONFIRMATION_CONTROLLER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_CONFIRMATION_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/common/system/chromeos/session/last_window_closed_observer.h" +#include "base/callback.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "base/timer/timer.h" + +namespace base { +class TickClock; +} + +namespace ash { + +class LogoutConfirmationDialog; + +// This class shows a dialog asking the user to confirm or deny logout and +// terminates the session if the user either confirms or allows the countdown +// shown in the dialog to expire. +// +// It is guaranteed that no more than one confirmation dialog will be visible at +// any given time. If there are multiple requests to show a confirmation dialog +// at the same time, the dialog whose countdown expires first is shown. +// +// In public sessions, asks the user to end the session when the last window is +// closed. +class ASH_EXPORT LogoutConfirmationController + : public ShellObserver, + public LastWindowClosedObserver { + public: + // The |logout_closure| must be safe to call as long as |this| is alive. + explicit LogoutConfirmationController(const base::Closure& logout_closure); + ~LogoutConfirmationController() override; + + base::TickClock* clock() const { return clock_.get(); } + + // Shows a LogoutConfirmationDialog. If a confirmation dialog is already being + // shown, it is closed and a new one opened if |logout_time| is earlier than + // the current dialog's |logout_time_|. + void ConfirmLogout(base::TimeTicks logout_time); + + void SetClockForTesting(std::unique_ptr<base::TickClock> clock); + + // ShellObserver: + void OnLockStateChanged(bool locked) override; + + // Called by the |dialog_| when the user confirms logout. + void OnLogoutConfirmed(); + + // Called by the |dialog_| when it is closed. + void OnDialogClosed(); + + LogoutConfirmationDialog* dialog_for_testing() const { return dialog_; } + + private: + // LastWindowClosedObserver: + void OnLastWindowClosed() override; + + std::unique_ptr<base::TickClock> clock_; + base::Closure logout_closure_; + + base::TimeTicks logout_time_; + LogoutConfirmationDialog* dialog_; // Owned by the Views hierarchy. + base::Timer logout_timer_; + + DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationController); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_CONFIRMATION_CONTROLLER_H_
diff --git a/ash/common/system/chromeos/session/logout_confirmation_controller_unittest.cc b/ash/common/system/chromeos/session/logout_confirmation_controller_unittest.cc new file mode 100644 index 0000000..57fbeb20 --- /dev/null +++ b/ash/common/system/chromeos/session/logout_confirmation_controller_unittest.cc
@@ -0,0 +1,154 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/tick_clock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { + +class LogoutConfirmationControllerTest : public testing::Test { + protected: + LogoutConfirmationControllerTest(); + ~LogoutConfirmationControllerTest() override; + + void LogOut(); + + bool log_out_called_; + + scoped_refptr<base::TestMockTimeTaskRunner> runner_; + base::ThreadTaskRunnerHandle runner_handle_; + + LogoutConfirmationController controller_; + + private: + DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationControllerTest); +}; + +LogoutConfirmationControllerTest::LogoutConfirmationControllerTest() + : log_out_called_(false), + runner_(new base::TestMockTimeTaskRunner), + runner_handle_(runner_), + controller_(base::Bind(&LogoutConfirmationControllerTest::LogOut, + base::Unretained(this))) { + controller_.SetClockForTesting(runner_->GetMockTickClock()); +} + +LogoutConfirmationControllerTest::~LogoutConfirmationControllerTest() {} + +void LogoutConfirmationControllerTest::LogOut() { + log_out_called_ = true; +} + +// Verifies that the user is logged out immediately if logout confirmation with +// a zero-length countdown is requested. +TEST_F(LogoutConfirmationControllerTest, ZeroDuration) { + controller_.ConfirmLogout(runner_->NowTicks()); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta()); + EXPECT_TRUE(log_out_called_); +} + +// Verifies that the user is logged out when the countdown expires. +TEST_F(LogoutConfirmationControllerTest, DurationExpired) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); + EXPECT_TRUE(log_out_called_); +} + +// Verifies that when a second request to confirm logout is made and the second +// request's countdown ends before the original request's, the user is logged +// out when the new countdown expires. +TEST_F(LogoutConfirmationControllerTest, DurationShortened) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(30)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); + EXPECT_FALSE(log_out_called_); + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); + EXPECT_TRUE(log_out_called_); +} + +// Verifies that when a second request to confirm logout is made and the second +// request's countdown ends after the original request's, the user is logged +// out when the original countdown expires. +TEST_F(LogoutConfirmationControllerTest, DurationExtended) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); + EXPECT_FALSE(log_out_called_); + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); + EXPECT_TRUE(log_out_called_); +} + +// Verifies that when the screen is locked while the countdown is running, the +// user is not logged out, even when the original countdown expires. +TEST_F(LogoutConfirmationControllerTest, Lock) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + controller_.OnLockStateChanged(true); + runner_->FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(log_out_called_); +} + +// Verifies that when the user confirms the logout request, the user is logged +// out immediately. +TEST_F(LogoutConfirmationControllerTest, UserAccepted) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + controller_.OnLogoutConfirmed(); + EXPECT_TRUE(log_out_called_); +} + +// Verifies that when the user denies the logout request, the user is not logged +// out, even when the original countdown expires. +TEST_F(LogoutConfirmationControllerTest, UserDenied) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + controller_.OnDialogClosed(); + runner_->FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(log_out_called_); +} + +// Verifies that after the user has denied a logout request, a subsequent logout +// request is handled correctly and the user is logged out when the countdown +// expires. +TEST_F(LogoutConfirmationControllerTest, DurationExpiredAfterDeniedRequest) { + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + controller_.OnDialogClosed(); + runner_->FastForwardUntilNoTasksRemain(); + EXPECT_FALSE(log_out_called_); + + controller_.ConfirmLogout(runner_->NowTicks() + + base::TimeDelta::FromSeconds(10)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); + EXPECT_FALSE(log_out_called_); + runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); + EXPECT_TRUE(log_out_called_); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/session/logout_confirmation_dialog.cc b/ash/common/system/chromeos/session/logout_confirmation_dialog.cc new file mode 100644 index 0000000..46247c13a --- /dev/null +++ b/ash/common/system/chromeos/session/logout_confirmation_dialog.cc
@@ -0,0 +1,122 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/session/logout_confirmation_dialog.h" + +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/location.h" +#include "base/time/tick_clock.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" +#include "ui/base/ui_base_types.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/text_constants.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +const int kCountdownUpdateIntervalMs = 1000; // 1 second. + +const int kHalfSecondInMs = 500; // Half a second. + +} // namespace + +LogoutConfirmationDialog::LogoutConfirmationDialog( + LogoutConfirmationController* controller, + base::TimeTicks logout_time) + : controller_(controller), logout_time_(logout_time) { + SetLayoutManager(new views::FillLayout()); + + label_ = new views::Label; + label_->SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, + kTrayPopupPaddingHorizontal)); + label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label_->SetMultiLine(true); + AddChildView(label_); + + UpdateLabel(); + + views::Widget* widget = new views::Widget; + views::Widget::InitParams params = + GetDialogWidgetInitParams(this, nullptr, nullptr, gfx::Rect()); + WmShell::Get() + ->GetPrimaryRootWindow() + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + widget, kShellWindowId_SystemModalContainer, ¶ms); + widget->Init(params); + widget->Show(); + + update_timer_.Start( + FROM_HERE, base::TimeDelta::FromMilliseconds(kCountdownUpdateIntervalMs), + this, &LogoutConfirmationDialog::UpdateLabel); +} + +LogoutConfirmationDialog::~LogoutConfirmationDialog() {} + +void LogoutConfirmationDialog::Update(base::TimeTicks logout_time) { + logout_time_ = logout_time; + UpdateLabel(); +} + +void LogoutConfirmationDialog::ControllerGone() { + controller_ = nullptr; + GetWidget()->Close(); +} + +bool LogoutConfirmationDialog::Accept() { + logout_time_ = controller_->clock()->NowTicks(); + UpdateLabel(); + controller_->OnLogoutConfirmed(); + return true; +} + +ui::ModalType LogoutConfirmationDialog::GetModalType() const { + return ui::MODAL_TYPE_SYSTEM; +} + +base::string16 LogoutConfirmationDialog::GetWindowTitle() const { + return l10n_util::GetStringUTF16(IDS_ASH_LOGOUT_CONFIRMATION_TITLE); +} + +base::string16 LogoutConfirmationDialog::GetDialogButtonLabel( + ui::DialogButton button) const { + if (button == ui::DIALOG_BUTTON_OK) + return l10n_util::GetStringUTF16(IDS_ASH_LOGOUT_CONFIRMATION_BUTTON); + return views::DialogDelegateView::GetDialogButtonLabel(button); +} + +void LogoutConfirmationDialog::WindowClosing() { + update_timer_.Stop(); + if (controller_) + controller_->OnDialogClosed(); +} + +void LogoutConfirmationDialog::UpdateLabel() { + const base::TimeDelta time_remaining = + logout_time_ - controller_->clock()->NowTicks(); + if (time_remaining >= base::TimeDelta::FromMilliseconds(kHalfSecondInMs)) { + label_->SetText(l10n_util::GetStringFUTF16( + IDS_ASH_LOGOUT_CONFIRMATION_WARNING, + ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, 10, + time_remaining))); + } else { + label_->SetText( + l10n_util::GetStringUTF16(IDS_ASH_LOGOUT_CONFIRMATION_WARNING_NOW)); + update_timer_.Stop(); + } +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/session/logout_confirmation_dialog.h b/ash/common/system/chromeos/session/logout_confirmation_dialog.h new file mode 100644 index 0000000..fa3c4d42 --- /dev/null +++ b/ash/common/system/chromeos/session/logout_confirmation_dialog.h
@@ -0,0 +1,57 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_CONFIRMATION_DIALOG_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_CONFIRMATION_DIALOG_H_ + +#include "base/macros.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "ui/views/window/dialog_delegate.h" + +namespace views { +class Label; +} + +namespace ash { + +class LogoutConfirmationController; + +// A dialog that asks the user to confirm or deny logout. The dialog shows a +// countdown and informs the user that a logout will happen automatically if no +// choice is made before the countdown has expired. +class LogoutConfirmationDialog : public views::DialogDelegateView { + public: + LogoutConfirmationDialog(LogoutConfirmationController* controller, + base::TimeTicks logout_time); + ~LogoutConfirmationDialog() override; + + void Update(base::TimeTicks logout_time); + + // Called when |controller_| is no longer valid. + void ControllerGone(); + + // views::DialogDelegateView: + bool Accept() override; + ui::ModalType GetModalType() const override; + base::string16 GetWindowTitle() const override; + base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; + void WindowClosing() override; + + private: + void UpdateLabel(); + + LogoutConfirmationController* controller_; + base::TimeTicks logout_time_; + + views::Label* label_; + + base::RepeatingTimer update_timer_; + + DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationDialog); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_LOGOUT_CONFIRMATION_DIALOG_H_
diff --git a/ash/common/system/chromeos/session/session_length_limit_observer.h b/ash/common/system/chromeos/session/session_length_limit_observer.h new file mode 100644 index 0000000..d46a253 --- /dev/null +++ b/ash/common/system/chromeos/session/session_length_limit_observer.h
@@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_SESSION_LENGTH_LIMIT_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_SESSION_LENGTH_LIMIT_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +// Observer for the session length limit. +class ASH_EXPORT SessionLengthLimitObserver { + public: + virtual ~SessionLengthLimitObserver() {} + + // Called when the session start time is updated. + virtual void OnSessionStartTimeChanged() = 0; + + // Called when the session length limit is updated. + virtual void OnSessionLengthLimitChanged() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_SESSION_LENGTH_LIMIT_OBSERVER_H_
diff --git a/ash/common/system/chromeos/session/tray_session_length_limit.cc b/ash/common/system/chromeos/session/tray_session_length_limit.cc new file mode 100644 index 0000000..3439a8d --- /dev/null +++ b/ash/common/system/chromeos/session/tray_session_length_limit.cc
@@ -0,0 +1,196 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/session/tray_session_length_limit.h" + +#include <algorithm> +#include <memory> +#include <utility> + +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/label_tray_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/views/view.h" + +namespace ash { +namespace { + +// If the remaining session time falls below this threshold, the user should be +// informed that the session is about to expire. +const int kExpiringSoonThresholdInMinutes = 5; + +// Use 500ms interval for updates to notification and tray bubble to reduce the +// likelihood of a user-visible skip in high load situations (as might happen +// with 1000ms). +const int kTimerIntervalInMilliseconds = 500; + +} // namespace + +// static +const char TraySessionLengthLimit::kNotificationId[] = + "chrome://session/timeout"; + +TraySessionLengthLimit::TraySessionLengthLimit(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_SESSION_LENGTH_LIMIT), + limit_state_(LIMIT_NONE), + last_limit_state_(LIMIT_NONE), + tray_bubble_view_(NULL) { + WmShell::Get()->system_tray_notifier()->AddSessionLengthLimitObserver(this); + Update(); +} + +TraySessionLengthLimit::~TraySessionLengthLimit() { + WmShell::Get()->system_tray_notifier()->RemoveSessionLengthLimitObserver( + this); +} + +// Add view to tray bubble. +views::View* TraySessionLengthLimit::CreateDefaultView(LoginStatus status) { + CHECK(!tray_bubble_view_); + UpdateState(); + if (limit_state_ == LIMIT_NONE) + return NULL; + tray_bubble_view_ = + new LabelTrayView(NULL /* click_listener */, + IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT); + tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage()); + return tray_bubble_view_; +} + +// View has been removed from tray bubble. +void TraySessionLengthLimit::DestroyDefaultView() { + tray_bubble_view_ = NULL; +} + +void TraySessionLengthLimit::OnSessionStartTimeChanged() { + Update(); +} + +void TraySessionLengthLimit::OnSessionLengthLimitChanged() { + Update(); +} + +void TraySessionLengthLimit::Update() { + UpdateState(); + UpdateNotification(); + UpdateTrayBubbleView(); +} + +void TraySessionLengthLimit::UpdateState() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (delegate->GetSessionStartTime(&session_start_time_) && + delegate->GetSessionLengthLimit(&time_limit_)) { + const base::TimeDelta expiring_soon_threshold( + base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes)); + remaining_session_time_ = + std::max(time_limit_ - (base::TimeTicks::Now() - session_start_time_), + base::TimeDelta()); + limit_state_ = remaining_session_time_ <= expiring_soon_threshold + ? LIMIT_EXPIRING_SOON + : LIMIT_SET; + if (!timer_) + timer_.reset(new base::RepeatingTimer); + if (!timer_->IsRunning()) { + timer_->Start(FROM_HERE, base::TimeDelta::FromMilliseconds( + kTimerIntervalInMilliseconds), + this, &TraySessionLengthLimit::Update); + } + } else { + remaining_session_time_ = base::TimeDelta(); + limit_state_ = LIMIT_NONE; + timer_.reset(); + } +} + +void TraySessionLengthLimit::UpdateNotification() { + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + + // If state hasn't changed and the notification has already been acknowledged, + // we won't re-create it. + if (limit_state_ == last_limit_state_ && + !message_center->FindVisibleNotificationById(kNotificationId)) { + return; + } + + // After state change, any possibly existing notification is removed to make + // sure it is re-shown even if it had been acknowledged by the user before + // (and in the rare case of state change towards LIMIT_NONE to make the + // notification disappear). + if (limit_state_ != last_limit_state_ && + message_center->FindVisibleNotificationById(kNotificationId)) { + message_center::MessageCenter::Get()->RemoveNotification( + kNotificationId, false /* by_user */); + } + + // For LIMIT_NONE, there's nothing more to do. + if (limit_state_ == LIMIT_NONE) { + last_limit_state_ = limit_state_; + return; + } + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + message_center::RichNotificationData data; + data.should_make_spoken_feedback_for_popup_updates = + (limit_state_ != last_limit_state_); + std::unique_ptr<message_center::Notification> notification( + new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, + base::string16() /* title */, + ComposeNotificationMessage() /* message */, + bundle.GetImageNamed( + IDR_AURA_UBER_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT), + base::string16() /* display_source */, GURL(), + message_center::NotifierId( + message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierSessionLengthTimeout), + data, NULL /* delegate */)); + notification->SetSystemPriority(); + if (message_center->FindVisibleNotificationById(kNotificationId)) + message_center->UpdateNotification(kNotificationId, + std::move(notification)); + else + message_center->AddNotification(std::move(notification)); + last_limit_state_ = limit_state_; +} + +void TraySessionLengthLimit::UpdateTrayBubbleView() const { + if (!tray_bubble_view_) + return; + if (limit_state_ == LIMIT_NONE) + tray_bubble_view_->SetMessage(base::string16()); + else + tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage()); + tray_bubble_view_->Layout(); +} + +base::string16 TraySessionLengthLimit::ComposeNotificationMessage() const { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT, + ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, 10, + remaining_session_time_)); +} + +base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT, + ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION, + ui::TimeFormat::LENGTH_LONG, 10, + remaining_session_time_)); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/session/tray_session_length_limit.h b/ash/common/system/chromeos/session/tray_session_length_limit.h new file mode 100644 index 0000000..cc307e1 --- /dev/null +++ b/ash/common/system/chromeos/session/tray_session_length_limit.h
@@ -0,0 +1,75 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SESSION_TRAY_SESSION_LENGTH_LIMIT_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SESSION_TRAY_SESSION_LENGTH_LIMIT_H_ + +#include <memory> + +#include "ash/common/system/chromeos/session/session_length_limit_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "base/time/time.h" +#include "base/timer/timer.h" + +namespace ash { +namespace test { +class TraySessionLengthLimitTest; +} + +class LabelTrayView; + +// Adds a countdown timer to the system tray if the session length is limited. +class ASH_EXPORT TraySessionLengthLimit : public SystemTrayItem, + public SessionLengthLimitObserver { + public: + enum LimitState { LIMIT_NONE, LIMIT_SET, LIMIT_EXPIRING_SOON }; + + explicit TraySessionLengthLimit(SystemTray* system_tray); + ~TraySessionLengthLimit() override; + + // SystemTrayItem: + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyDefaultView() override; + + // SessionLengthLimitObserver: + void OnSessionStartTimeChanged() override; + void OnSessionLengthLimitChanged() override; + + private: + friend class test::TraySessionLengthLimitTest; + + static const char kNotificationId[]; + + // Update state, notification and tray bubble view. Called by the + // RepeatingTimer in regular intervals and also by OnSession*Changed(). + void Update(); + + // Recalculate |limit_state_| and |remaining_session_time_|. + void UpdateState(); + + void UpdateNotification(); + void UpdateTrayBubbleView() const; + + // These require that the state has been updated before. + base::string16 ComposeNotificationMessage() const; + base::string16 ComposeTrayBubbleMessage() const; + + base::TimeTicks session_start_time_; + base::TimeDelta time_limit_; + base::TimeDelta remaining_session_time_; + + LimitState limit_state_; // Current state. + LimitState last_limit_state_; // State of last notification update. + + LabelTrayView* tray_bubble_view_; + std::unique_ptr<base::RepeatingTimer> timer_; + + DISALLOW_COPY_AND_ASSIGN(TraySessionLengthLimit); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SESSION_TRAY_SESSION_LENGTH_LIMIT_H_
diff --git a/ash/common/system/chromeos/session/tray_session_length_limit_unittest.cc b/ash/common/system/chromeos/session/tray_session_length_limit_unittest.cc new file mode 100644 index 0000000..ec5f40ae --- /dev/null +++ b/ash/common/system/chromeos/session/tray_session_length_limit_unittest.cc
@@ -0,0 +1,157 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/session/tray_session_length_limit.h" + +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/test/ash_test_base.h" +#include "base/memory/ptr_util.h" +#include "base/time/time.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_types.h" + +namespace ash { +namespace test { + +class TraySessionLengthLimitTest : public AshTestBase { + public: + TraySessionLengthLimitTest() {} + ~TraySessionLengthLimitTest() override {} + + void SetUp() override { + AshTestBase::SetUp(); + SystemTray* system_tray = GetPrimarySystemTray(); + tray_session_length_limit_ = new TraySessionLengthLimit(system_tray); + system_tray->AddTrayItem(base::WrapUnique(tray_session_length_limit_)); + } + + void TearDown() override { + ClearSessionLengthLimit(); + AshTestBase::TearDown(); + } + + protected: + void UpdateSessionLengthLimitInMin(int mins) { + GetSystemTrayDelegate()->SetSessionLengthLimitForTest( + base::TimeDelta::FromMinutes(mins)); + tray_session_length_limit_->OnSessionLengthLimitChanged(); + } + + message_center::Notification* GetNotification() { + const message_center::NotificationList::Notifications& notifications = + message_center::MessageCenter::Get()->GetVisibleNotifications(); + for (message_center::NotificationList::Notifications::const_iterator iter = + notifications.begin(); + iter != notifications.end(); ++iter) { + if ((*iter)->id() == TraySessionLengthLimit::kNotificationId) + return *iter; + } + return nullptr; + } + + void ClearSessionLengthLimit() { + GetSystemTrayDelegate()->ClearSessionLengthLimit(); + tray_session_length_limit_->OnSessionLengthLimitChanged(); + } + + void RemoveNotification() { + message_center::MessageCenter::Get()->RemoveNotification( + TraySessionLengthLimit::kNotificationId, false /* by_user */); + } + + TraySessionLengthLimit* tray_session_length_limit() { + return tray_session_length_limit_; + } + + private: + // Weak reference, owned by the SystemTray. + TraySessionLengthLimit* tray_session_length_limit_; + + DISALLOW_COPY_AND_ASSIGN(TraySessionLengthLimitTest); +}; + +TEST_F(TraySessionLengthLimitTest, Notification) { + // No notifications when no session limit. + EXPECT_FALSE(GetNotification()); + + // Limit is 15 min. + UpdateSessionLengthLimitInMin(15); + message_center::Notification* notification = GetNotification(); + EXPECT_TRUE(notification); + EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); + base::string16 first_content = notification->message(); + // Should read the content. + EXPECT_TRUE(notification->rich_notification_data() + .should_make_spoken_feedback_for_popup_updates); + + // Limit is 10 min. + UpdateSessionLengthLimitInMin(10); + notification = GetNotification(); + EXPECT_TRUE(notification); + EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); + // The content should be updated. + EXPECT_NE(first_content, notification->message()); + // Should NOT read, because just update the remaining time. + EXPECT_FALSE(notification->rich_notification_data() + .should_make_spoken_feedback_for_popup_updates); + + // Limit is 3 min. + UpdateSessionLengthLimitInMin(3); + notification = GetNotification(); + EXPECT_TRUE(notification); + EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); + // Should read the content again because the state has changed. + EXPECT_TRUE(notification->rich_notification_data() + .should_make_spoken_feedback_for_popup_updates); + + // Session length limit is updated to longer: 15 min. + UpdateSessionLengthLimitInMin(15); + notification = GetNotification(); + EXPECT_TRUE(notification); + EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); + // Should read again because an increase of the remaining time is noteworthy. + EXPECT_TRUE(notification->rich_notification_data() + .should_make_spoken_feedback_for_popup_updates); + + // Clears the limit: the notification should be gone. + ClearSessionLengthLimit(); + EXPECT_FALSE(GetNotification()); +} + +TEST_F(TraySessionLengthLimitTest, RemoveNotification) { + // Limit is 15 min. + UpdateSessionLengthLimitInMin(15); + EXPECT_TRUE(GetNotification()); + + // Removes the notification. + RemoveNotification(); + EXPECT_FALSE(GetNotification()); + + // Limit is 10 min. The notification should not re-appear. + UpdateSessionLengthLimitInMin(10); + EXPECT_FALSE(GetNotification()); + + // Limit is 3 min. The notification should re-appear and should be re-read + // because of state change. + UpdateSessionLengthLimitInMin(3); + message_center::Notification* notification = GetNotification(); + EXPECT_TRUE(notification); + EXPECT_TRUE(notification->rich_notification_data() + .should_make_spoken_feedback_for_popup_updates); + + RemoveNotification(); + + // Session length limit is updated to longer state. Notification should + // re-appear and be re-read. + UpdateSessionLengthLimitInMin(15); + notification = GetNotification(); + EXPECT_TRUE(notification); + EXPECT_TRUE(notification->rich_notification_data() + .should_make_spoken_feedback_for_popup_updates); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/system/chromeos/settings/tray_settings.cc b/ash/common/system/chromeos/settings/tray_settings.cc new file mode 100644 index 0000000..4b613ffc --- /dev/null +++ b/ash/common/system/chromeos/settings/tray_settings.cc
@@ -0,0 +1,176 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/settings/tray_settings.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/chromeos/power/power_status_view.h" +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" + +namespace ash { +namespace tray { + +// TODO(tdanderson): Remove this class once material design is enabled by +// default. See crbug.com/614453. +class SettingsDefaultView : public ActionableView, + public PowerStatus::Observer { + public: + SettingsDefaultView(SystemTrayItem* owner, LoginStatus status) + : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), + login_status_(status), + label_(nullptr), + power_status_view_(nullptr) { + PowerStatus::Get()->AddObserver(this); + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, + ash::kTrayPopupPaddingHorizontal, 0, + ash::kTrayPopupPaddingBetweenItems)); + + bool power_view_right_align = false; + if (login_status_ != LoginStatus::NOT_LOGGED_IN && + login_status_ != LoginStatus::LOCKED && + !WmShell::Get() + ->GetSessionStateDelegate() + ->IsInSecondaryLoginScreen()) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + views::ImageView* icon = TrayPopupUtils::CreateMainImageView(); + + icon->SetImage( + rb.GetImageNamed(IDR_AURA_UBER_TRAY_SETTINGS).ToImageSkia()); + icon->set_id(test::kSettingsTrayItemViewId); + AddChildView(icon); + + base::string16 text = rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_SETTINGS); + label_ = TrayPopupUtils::CreateDefaultLabel(); + label_->SetText(text); + AddChildView(label_); + SetAccessibleName(text); + + power_view_right_align = true; + } + + if (PowerStatus::Get()->IsBatteryPresent()) { + power_status_view_ = new ash::PowerStatusView(power_view_right_align); + AddChildView(power_status_view_); + OnPowerStatusChanged(); + } + + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + SetInkDropMode(InkDropHostView::InkDropMode::ON); + } + + ~SettingsDefaultView() override { PowerStatus::Get()->RemoveObserver(this); } + + // Overridden from ash::ActionableView. + bool PerformAction(const ui::Event& event) override { + if (login_status_ == LoginStatus::NOT_LOGGED_IN || + login_status_ == LoginStatus::LOCKED || + WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen()) { + return false; + } + + WmShell::Get()->system_tray_controller()->ShowSettings(); + CloseSystemBubble(); + return true; + } + + // Overridden from views::View. + void Layout() override { + views::View::Layout(); + + if (label_ && power_status_view_) { + // Let the box-layout do the layout first. Then move power_status_view_ + // to right align if it is created. + gfx::Size size = power_status_view_->GetPreferredSize(); + gfx::Rect bounds(size); + bounds.set_x(width() - size.width() - ash::kTrayPopupPaddingBetweenItems); + bounds.set_y((height() - size.height()) / 2); + power_status_view_->SetBoundsRect(bounds); + } + } + + // Overridden from views::View. + void ChildPreferredSizeChanged(views::View* child) override { + views::View::ChildPreferredSizeChanged(child); + Layout(); + } + + // Overridden from PowerStatus::Observer. + void OnPowerStatusChanged() override { + if (!PowerStatus::Get()->IsBatteryPresent()) + return; + + base::string16 accessible_name = + label_ + ? label_->text() + base::ASCIIToUTF16(", ") + + PowerStatus::Get()->GetAccessibleNameString(true) + : PowerStatus::Get()->GetAccessibleNameString(true); + SetAccessibleName(accessible_name); + } + + private: + LoginStatus login_status_; + views::Label* label_; + ash::PowerStatusView* power_status_view_; + + DISALLOW_COPY_AND_ASSIGN(SettingsDefaultView); +}; + +} // namespace tray + +TraySettings::TraySettings(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_SETTINGS), default_view_(nullptr) {} + +TraySettings::~TraySettings() {} + +views::View* TraySettings::CreateTrayView(LoginStatus status) { + return nullptr; +} + +views::View* TraySettings::CreateDefaultView(LoginStatus status) { + if ((status == LoginStatus::NOT_LOGGED_IN || status == LoginStatus::LOCKED) && + !PowerStatus::Get()->IsBatteryPresent()) + return nullptr; + if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings()) + return nullptr; + CHECK(default_view_ == nullptr); + default_view_ = new tray::SettingsDefaultView(this, status); + return default_view_; +} + +views::View* TraySettings::CreateDetailedView(LoginStatus status) { + NOTIMPLEMENTED(); + return nullptr; +} + +void TraySettings::DestroyTrayView() {} + +void TraySettings::DestroyDefaultView() { + default_view_ = nullptr; +} + +void TraySettings::DestroyDetailedView() {} + +void TraySettings::UpdateAfterLoginStatusChange(LoginStatus status) {} + +} // namespace ash
diff --git a/ash/common/system/chromeos/settings/tray_settings.h b/ash/common/system/chromeos/settings/tray_settings.h new file mode 100644 index 0000000..974856c3 --- /dev/null +++ b/ash/common/system/chromeos/settings/tray_settings.h
@@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_ + +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { +namespace tray { +class SettingsDefaultView; +} + +// TODO(tdanderson): Remove this class once material design is enabled by +// default. See crbug.com/614453. +class TraySettings : public SystemTrayItem { + public: + explicit TraySettings(SystemTray* system_tray); + ~TraySettings() override; + + private: + // Overridden from SystemTrayItem + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + + tray::SettingsDefaultView* default_view_; + + DISALLOW_COPY_AND_ASSIGN(TraySettings); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SETTINGS_TRAY_SETTINGS_H_
diff --git a/ash/common/system/chromeos/supervised/custodian_info_tray_observer.h b/ash/common/system/chromeos/supervised/custodian_info_tray_observer.h new file mode 100644 index 0000000..4df0a9a --- /dev/null +++ b/ash/common/system/chromeos/supervised/custodian_info_tray_observer.h
@@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SUPERVISED_CUSTODIAN_INFO_TRAY_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SUPERVISED_CUSTODIAN_INFO_TRAY_OBSERVER_H_ + +namespace ash { + +// Used to observe SystemTrayDelegate. +class CustodianInfoTrayObserver { + public: + // Called when information about the supervised user's custodian is changed, + // e.g. the display name. + virtual void OnCustodianInfoChanged() = 0; + + protected: + virtual ~CustodianInfoTrayObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SUPERVISED_CUSTODIAN_INFO_TRAY_OBSERVER_H_
diff --git a/ash/common/system/chromeos/supervised/tray_supervised_user.cc b/ash/common/system/chromeos/supervised/tray_supervised_user.cc new file mode 100644 index 0000000..ffb6797a --- /dev/null +++ b/ash/common/system/chromeos/supervised/tray_supervised_user.cc
@@ -0,0 +1,132 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/supervised/tray_supervised_user.h" + +#include <utility> + +#include "ash/common/login_status.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/label_tray_view.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "base/callback.h" +#include "base/logging.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" + +using message_center::Notification; + +namespace ash { + +const char TraySupervisedUser::kNotificationId[] = + "chrome://user/locally-managed"; + +TraySupervisedUser::TraySupervisedUser(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_SUPERVISED_USER), + tray_view_(NULL), + status_(LoginStatus::NOT_LOGGED_IN), + is_user_supervised_(false) { + WmShell::Get()->system_tray_delegate()->AddCustodianInfoTrayObserver(this); +} + +TraySupervisedUser::~TraySupervisedUser() { + // We need the check as on shell destruction delegate is destroyed first. + SystemTrayDelegate* system_tray_delegate = + WmShell::Get()->system_tray_delegate(); + if (system_tray_delegate) + system_tray_delegate->RemoveCustodianInfoTrayObserver(this); +} + +void TraySupervisedUser::UpdateMessage() { + base::string16 message = + WmShell::Get()->system_tray_delegate()->GetSupervisedUserMessage(); + if (tray_view_) + tray_view_->SetMessage(message); + if (message_center::MessageCenter::Get()->FindVisibleNotificationById( + kNotificationId)) + CreateOrUpdateNotification(message); +} + +views::View* TraySupervisedUser::CreateDefaultView(LoginStatus status) { + CHECK(tray_view_ == NULL); + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (!delegate->IsUserSupervised()) + return NULL; + + tray_view_ = new LabelTrayView(this, GetSupervisedUserIconId()); + UpdateMessage(); + return tray_view_; +} + +void TraySupervisedUser::DestroyDefaultView() { + tray_view_ = NULL; +} + +void TraySupervisedUser::OnViewClicked(views::View* sender) { + // TODO(antrim): Find out what should we show in this case. +} + +void TraySupervisedUser::UpdateAfterLoginStatusChange(LoginStatus status) { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + + bool is_user_supervised = delegate->IsUserSupervised(); + if (status == status_ && is_user_supervised == is_user_supervised_) + return; + + if (is_user_supervised && !delegate->IsUserChild() && + status_ != LoginStatus::LOCKED && + !delegate->GetSupervisedUserManager().empty()) + CreateOrUpdateSupervisedWarningNotification(); + + status_ = status; + is_user_supervised_ = is_user_supervised; +} + +void TraySupervisedUser::CreateOrUpdateNotification( + const base::string16& new_message) { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + std::unique_ptr<Notification> notification( + message_center::Notification::CreateSystemNotification( + kNotificationId, base::string16() /* no title */, new_message, + bundle.GetImageNamed(GetSupervisedUserIconId()), + system_notifier::kNotifierSupervisedUser, + base::Closure() /* null callback */)); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +void TraySupervisedUser::CreateOrUpdateSupervisedWarningNotification() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + CreateOrUpdateNotification(delegate->GetSupervisedUserMessage()); +} + +void TraySupervisedUser::OnCustodianInfoChanged() { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + std::string manager_name = delegate->GetSupervisedUserManager(); + if (!manager_name.empty()) { + if (!delegate->IsUserChild() && + !message_center::MessageCenter::Get()->FindVisibleNotificationById( + kNotificationId)) { + CreateOrUpdateSupervisedWarningNotification(); + } + UpdateMessage(); + } +} + +int TraySupervisedUser::GetSupervisedUserIconId() const { + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + + // Not intended to be used for non-supervised users. + CHECK(delegate->IsUserSupervised()); + + if (delegate->IsUserChild()) + return IDR_AURA_UBER_TRAY_CHILD_USER; + return IDR_AURA_UBER_TRAY_SUPERVISED_USER; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/supervised/tray_supervised_user.h b/ash/common/system/chromeos/supervised/tray_supervised_user.h new file mode 100644 index 0000000..a066fe8 --- /dev/null +++ b/ash/common/system/chromeos/supervised/tray_supervised_user.h
@@ -0,0 +1,65 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SUPERVISED_TRAY_SUPERVISED_USER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SUPERVISED_TRAY_SUPERVISED_USER_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/chromeos/supervised/custodian_info_tray_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "base/macros.h" +#include "base/strings/string16.h" + +namespace ash { +class LabelTrayView; +class SystemTray; + +class ASH_EXPORT TraySupervisedUser : public SystemTrayItem, + public ViewClickListener, + public CustodianInfoTrayObserver { + public: + explicit TraySupervisedUser(SystemTray* system_tray); + ~TraySupervisedUser() override; + + // If message is not empty updates content of default view, otherwise hides + // tray items. + void UpdateMessage(); + + // Overridden from SystemTrayItem. + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyDefaultView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + + // Overridden from ViewClickListener. + void OnViewClicked(views::View* sender) override; + + // Overridden from CustodianInfoTrayObserver: + void OnCustodianInfoChanged() override; + + private: + friend class TraySupervisedUserTest; + + static const char kNotificationId[]; + + void CreateOrUpdateNotification(const base::string16& new_message); + + void CreateOrUpdateSupervisedWarningNotification(); + + int GetSupervisedUserIconId() const; + + LabelTrayView* tray_view_; + + // Previous login status to avoid showing notification upon unlock. + LoginStatus status_; + + // Previous user supervised state to avoid showing notification upon unlock. + bool is_user_supervised_; + + DISALLOW_COPY_AND_ASSIGN(TraySupervisedUser); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SUPERVISED_TRAY_SUPERVISED_USER_H_
diff --git a/ash/common/system/chromeos/supervised/tray_supervised_user_unittest.cc b/ash/common/system/chromeos/supervised/tray_supervised_user_unittest.cc new file mode 100644 index 0000000..7ccb5a8 --- /dev/null +++ b/ash/common/system/chromeos/supervised/tray_supervised_user_unittest.cc
@@ -0,0 +1,76 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/supervised/tray_supervised_user.h" + +#include "ash/common/login_status.h" +#include "ash/common/test/ash_test.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_list.h" +#include "ui/message_center/notification_types.h" + +using message_center::NotificationList; + +namespace ash { + +class TraySupervisedUserTest : public AshTest { + public: + TraySupervisedUserTest() {} + ~TraySupervisedUserTest() override {} + + protected: + message_center::Notification* GetPopup(); + + private: + DISALLOW_COPY_AND_ASSIGN(TraySupervisedUserTest); +}; + +message_center::Notification* TraySupervisedUserTest::GetPopup() { + NotificationList::PopupNotifications popups = + message_center::MessageCenter::Get()->GetPopupNotifications(); + for (NotificationList::PopupNotifications::const_iterator iter = + popups.begin(); + iter != popups.end(); ++iter) { + if ((*iter)->id() == TraySupervisedUser::kNotificationId) + return *iter; + } + return NULL; +} + +class TraySupervisedUserInitialTest : public TraySupervisedUserTest { + public: + // Set the initial login status to supervised-user before AshTest::SetUp() + // constructs the system tray. + TraySupervisedUserInitialTest() + : scoped_initial_login_status_(LoginStatus::SUPERVISED) {} + ~TraySupervisedUserInitialTest() override {} + + private: + test::ScopedInitialLoginStatus scoped_initial_login_status_; + + DISALLOW_COPY_AND_ASSIGN(TraySupervisedUserInitialTest); +}; + +TEST_F(TraySupervisedUserTest, SupervisedUserHasNotification) { + test::TestSystemTrayDelegate* delegate = GetSystemTrayDelegate(); + delegate->SetLoginStatus(LoginStatus::SUPERVISED); + + message_center::Notification* notification = GetPopup(); + ASSERT_NE(static_cast<message_center::Notification*>(NULL), notification); + EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY), + notification->rich_notification_data().priority); +} + +TEST_F(TraySupervisedUserInitialTest, SupervisedUserNoCrash) { + // Initial login status is already SUPERVISED, which should create + // the notification and should not cause crashes. + message_center::Notification* notification = GetPopup(); + ASSERT_NE(static_cast<message_center::Notification*>(NULL), notification); + EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY), + notification->rich_notification_data().priority); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/system_clock_observer.cc b/ash/common/system/chromeos/system_clock_observer.cc new file mode 100644 index 0000000..984c6ca --- /dev/null +++ b/ash/common/system/chromeos/system_clock_observer.cc
@@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/system_clock_observer.h" + +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "chromeos/dbus/dbus_thread_manager.h" + +namespace ash { + +SystemClockObserver::SystemClockObserver() { + chromeos::DBusThreadManager::Get()->GetSystemClockClient()->AddObserver(this); + chromeos::system::TimezoneSettings::GetInstance()->AddObserver(this); + can_set_time_ = + chromeos::DBusThreadManager::Get()->GetSystemClockClient()->CanSetTime(); +} + +SystemClockObserver::~SystemClockObserver() { + chromeos::DBusThreadManager::Get()->GetSystemClockClient()->RemoveObserver( + this); + chromeos::system::TimezoneSettings::GetInstance()->RemoveObserver(this); +} + +void SystemClockObserver::SystemClockUpdated() { + WmShell::Get()->system_tray_notifier()->NotifySystemClockTimeUpdated(); +} + +void SystemClockObserver::SystemClockCanSetTimeChanged(bool can_set_time) { + can_set_time_ = can_set_time; + WmShell::Get()->system_tray_notifier()->NotifySystemClockCanSetTimeChanged( + can_set_time_); +} + +void SystemClockObserver::TimezoneChanged(const icu::TimeZone& timezone) { + WmShell::Get()->system_tray_notifier()->NotifyRefreshClock(); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/system_clock_observer.h b/ash/common/system/chromeos/system_clock_observer.h new file mode 100644 index 0000000..639f0082 --- /dev/null +++ b/ash/common/system/chromeos/system_clock_observer.h
@@ -0,0 +1,38 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_SYSTEM_CLOCK_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_SYSTEM_CLOCK_OBSERVER_H_ + +#include "base/macros.h" +#include "chromeos/dbus/system_clock_client.h" +#include "chromeos/settings/timezone_settings.h" + +namespace ash { + +class SystemClockObserver + : public chromeos::SystemClockClient::Observer, + public chromeos::system::TimezoneSettings::Observer { + public: + SystemClockObserver(); + ~SystemClockObserver() override; + + // chromeos::SystemClockClient::Observer + void SystemClockUpdated() override; + void SystemClockCanSetTimeChanged(bool can_set_time) override; + + // chromeos::system::TimezoneSettings::Observer + void TimezoneChanged(const icu::TimeZone& timezone) override; + + bool can_set_time() { return can_set_time_; } + + private: + bool can_set_time_; + + DISALLOW_COPY_AND_ASSIGN(SystemClockObserver); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_SYSTEM_CLOCK_OBSERVER_H_
diff --git a/ash/common/system/chromeos/tray_caps_lock.cc b/ash/common/system/chromeos/tray_caps_lock.cc new file mode 100644 index 0000000..c4c115e --- /dev/null +++ b/ash/common/system/chromeos/tray_caps_lock.cc
@@ -0,0 +1,232 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/tray_caps_lock.h" + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/sys_info.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/ime/chromeos/ime_keyboard.h" +#include "ui/base/ime/chromeos/input_method_manager.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +// Padding used to position the caption in the caps lock default view row. +const int kCaptionRightPadding = 6; + +bool CapsLockIsEnabled() { + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + return (ime && ime->GetImeKeyboard()) + ? ime->GetImeKeyboard()->CapsLockIsEnabled() + : false; +} +} + +class CapsLockDefaultView : public ActionableView { + public: + CapsLockDefaultView() + : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), + text_label_(TrayPopupUtils::CreateDefaultLabel()), + shortcut_label_(TrayPopupUtils::CreateDefaultLabel()) { + shortcut_label_->SetEnabled(false); + + TriView* tri_view(TrayPopupUtils::CreateDefaultRowView()); + SetLayoutManager(new views::FillLayout); + AddChildView(tri_view); + + auto* image = TrayPopupUtils::CreateMainImageView(); + image->SetEnabled(enabled()); + TrayPopupItemStyle default_view_style( + TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + image->SetImage(gfx::CreateVectorIcon(kSystemMenuCapsLockIcon, + default_view_style.GetIconColor())); + default_view_style.SetupLabel(text_label_); + + TrayPopupItemStyle caption_style(TrayPopupItemStyle::FontStyle::CAPTION); + caption_style.SetupLabel(shortcut_label_); + + SetInkDropMode(InkDropHostView::InkDropMode::ON); + + tri_view->AddView(TriView::Container::START, image); + tri_view->AddView(TriView::Container::CENTER, text_label_); + tri_view->AddView(TriView::Container::END, shortcut_label_); + tri_view->SetContainerBorder( + TriView::Container::END, + views::CreateEmptyBorder(0, 0, 0, kCaptionRightPadding)); + } + + ~CapsLockDefaultView() override {} + + // Updates the label text and the shortcut text. + void Update(bool caps_lock_enabled) { + const int text_string_id = caps_lock_enabled + ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_ENABLED + : IDS_ASH_STATUS_TRAY_CAPS_LOCK_DISABLED; + text_label_->SetText(l10n_util::GetStringUTF16(text_string_id)); + + int shortcut_string_id = 0; + bool search_mapped_to_caps_lock = + WmShell::Get()->system_tray_delegate()->IsSearchKeyMappedToCapsLock(); + if (caps_lock_enabled) { + shortcut_string_id = + search_mapped_to_caps_lock + ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_SEARCH_OR_SHIFT + : IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_ALT_SEARCH_OR_SHIFT; + } else { + shortcut_string_id = + search_mapped_to_caps_lock + ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_SEARCH + : IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_ALT_SEARCH; + } + shortcut_label_->SetText(l10n_util::GetStringUTF16(shortcut_string_id)); + + Layout(); + } + + private: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->role = ui::AX_ROLE_BUTTON; + node_data->SetName(text_label_->text()); + } + + // ActionableView: + bool PerformAction(const ui::Event& event) override { + chromeos::input_method::ImeKeyboard* keyboard = + chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard(); + if (keyboard) { + WmShell::Get()->RecordUserMetricsAction( + keyboard->CapsLockIsEnabled() + ? UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK + : UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK); + keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled()); + } + return true; + } + + // It indicates whether the Caps Lock is on or off. + views::Label* text_label_; + + // It indicates the shortcut can be used to turn on or turn off Caps Lock. + views::Label* shortcut_label_; + + DISALLOW_COPY_AND_ASSIGN(CapsLockDefaultView); +}; + +TrayCapsLock::TrayCapsLock(SystemTray* system_tray) + : TrayImageItem(system_tray, kSystemTrayCapsLockIcon, UMA_CAPS_LOCK), + default_(nullptr), + detailed_(nullptr), + caps_lock_enabled_(CapsLockIsEnabled()), + message_shown_(false) { + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + if (ime && ime->GetImeKeyboard()) + ime->GetImeKeyboard()->AddObserver(this); +} + +TrayCapsLock::~TrayCapsLock() { + chromeos::input_method::InputMethodManager* ime = + chromeos::input_method::InputMethodManager::Get(); + if (ime && ime->GetImeKeyboard()) + ime->GetImeKeyboard()->RemoveObserver(this); +} + +void TrayCapsLock::OnCapsLockChanged(bool enabled) { + caps_lock_enabled_ = enabled; + + // Send an a11y alert. + WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert( + enabled ? A11Y_ALERT_CAPS_ON : A11Y_ALERT_CAPS_OFF); + + if (tray_view()) + tray_view()->SetVisible(caps_lock_enabled_); + + if (default_) { + default_->Update(caps_lock_enabled_); + } else { + if (caps_lock_enabled_) { + if (!message_shown_) { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_CAPS_LOCK_POPUP); + PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); + message_shown_ = true; + } + } else if (detailed_) { + detailed_->GetWidget()->Close(); + } + } +} + +bool TrayCapsLock::GetInitialVisibility() { + return CapsLockIsEnabled(); +} + +views::View* TrayCapsLock::CreateDefaultView(LoginStatus status) { + if (!caps_lock_enabled_) + return nullptr; + DCHECK(!default_); + default_ = new CapsLockDefaultView; + default_->Update(caps_lock_enabled_); + return default_; +} + +views::View* TrayCapsLock::CreateDetailedView(LoginStatus status) { + DCHECK(!detailed_); + detailed_ = new views::View; + + detailed_->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kHorizontal, kTrayPopupPaddingHorizontal, 10, + kTrayPopupPaddingBetweenItems)); + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + views::ImageView* image = new views::ImageView; + image->SetImage( + CreateVectorIcon(kSystemMenuCapsLockIcon, kMenuIconSize, kMenuIconColor)); + detailed_->AddChildView(image); + + const int string_id = + WmShell::Get()->system_tray_delegate()->IsSearchKeyMappedToCapsLock() + ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH + : IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH; + views::Label* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(bundle.GetLocalizedString(string_id)); + label->SetMultiLine(true); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + detailed_->AddChildView(label); + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_CAPS_LOCK_DETAILED); + + return detailed_; +} + +void TrayCapsLock::DestroyDefaultView() { + default_ = nullptr; +} + +void TrayCapsLock::DestroyDetailedView() { + detailed_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/tray_caps_lock.h b/ash/common/system/chromeos/tray_caps_lock.h new file mode 100644 index 0000000..73eedd5f --- /dev/null +++ b/ash/common/system/chromeos/tray_caps_lock.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_TRAY_CAPS_LOCK_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_TRAY_CAPS_LOCK_H_ + +#include "ash/common/system/tray/tray_image_item.h" +#include "base/macros.h" +#include "ui/base/ime/chromeos/ime_keyboard.h" +#include "ui/events/event_handler.h" + +namespace views { +class View; +} + +namespace ash { +class CapsLockDefaultView; + +class TrayCapsLock : public TrayImageItem, + public chromeos::input_method::ImeKeyboard::Observer { + public: + explicit TrayCapsLock(SystemTray* system_tray); + ~TrayCapsLock() override; + + private: + // Overriden from chromeos::input_method::ImeKeyboard::Observer: + void OnCapsLockChanged(bool enabled) override; + + // Overridden from TrayImageItem. + bool GetInitialVisibility() override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + + CapsLockDefaultView* default_; + views::View* detailed_; + + bool caps_lock_enabled_; + bool message_shown_; + + DISALLOW_COPY_AND_ASSIGN(TrayCapsLock); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_TRAY_CAPS_LOCK_H_
diff --git a/ash/common/system/chromeos/tray_tracing.cc b/ash/common/system/chromeos/tray_tracing.cc new file mode 100644 index 0000000..cce4bce5 --- /dev/null +++ b/ash/common/system/chromeos/tray_tracing.cc
@@ -0,0 +1,114 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/tray_tracing.h" + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { +namespace tray { + +class DefaultTracingView : public ActionableView { + public: + explicit DefaultTracingView(SystemTrayItem* owner) + : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS) { + SetLayoutManager(new views::FillLayout); + TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view); + + auto* image = TrayPopupUtils::CreateMainImageView(); + tri_view->AddView(TriView::Container::START, image); + + auto* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetMultiLine(true); + label->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_TRACING)); + tri_view->AddView(TriView::Container::CENTER, label); + + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + style.SetupLabel(label); + image->SetImage( + gfx::CreateVectorIcon(kSystemMenuTracingIcon, style.GetIconColor())); + + SetInkDropMode(InkDropHostView::InkDropMode::ON); + } + + ~DefaultTracingView() override {} + + private: + bool PerformAction(const ui::Event& event) override { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_TRACING_DEFAULT_SELECTED); + WmShell::Get()->system_tray_controller()->ShowChromeSlow(); + CloseSystemBubble(); + return true; + } + + DISALLOW_COPY_AND_ASSIGN(DefaultTracingView); +}; + +} // namespace tray + +//////////////////////////////////////////////////////////////////////////////// +// ash::TrayTracing + +TrayTracing::TrayTracing(SystemTray* system_tray) + : TrayImageItem(system_tray, kSystemTrayTracingIcon, UMA_TRACING), + default_(nullptr) { + DCHECK(system_tray); + WmShell::Get()->system_tray_notifier()->AddTracingObserver(this); +} + +TrayTracing::~TrayTracing() { + WmShell::Get()->system_tray_notifier()->RemoveTracingObserver(this); +} + +void TrayTracing::SetTrayIconVisible(bool visible) { + if (tray_view()) + tray_view()->SetVisible(visible); +} + +bool TrayTracing::GetInitialVisibility() { + return false; +} + +views::View* TrayTracing::CreateDefaultView(LoginStatus status) { + CHECK(default_ == NULL); + if (tray_view() && tray_view()->visible()) + default_ = new tray::DefaultTracingView(this); + return default_; +} + +views::View* TrayTracing::CreateDetailedView(LoginStatus status) { + return NULL; +} + +void TrayTracing::DestroyDefaultView() { + default_ = NULL; +} + +void TrayTracing::DestroyDetailedView() {} + +void TrayTracing::OnTracingModeChanged(bool value) { + SetTrayIconVisible(value); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/tray_tracing.h b/ash/common/system/chromeos/tray_tracing.h new file mode 100644 index 0000000..363fc0c --- /dev/null +++ b/ash/common/system/chromeos/tray_tracing.h
@@ -0,0 +1,54 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_TRAY_TRACING_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_TRAY_TRACING_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/tray_image_item.h" +#include "base/macros.h" + +namespace views { +class View; +} + +namespace ash { + +class ASH_EXPORT TracingObserver { + public: + virtual ~TracingObserver() {} + + // Notifies when tracing mode changes. + virtual void OnTracingModeChanged(bool value) = 0; +}; + +// This is the item that displays when users enable performance tracing at +// chrome://slow. It alerts them that this mode is running, and provides an +// easy way to open the page to disable it. +class TrayTracing : public TrayImageItem, public TracingObserver { + public: + explicit TrayTracing(SystemTray* system_tray); + ~TrayTracing() override; + + private: + void SetTrayIconVisible(bool visible); + + // Overridden from TrayImageItem. + bool GetInitialVisibility() override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + + // Overridden from TracingObserver. + void OnTracingModeChanged(bool value) override; + + views::View* default_; + + DISALLOW_COPY_AND_ASSIGN(TrayTracing); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_TRAY_TRACING_H_
diff --git a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h new file mode 100644 index 0000000..fd86288 --- /dev/null +++ b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h
@@ -0,0 +1,22 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class ASH_EXPORT VirtualKeyboardObserver { + public: + virtual ~VirtualKeyboardObserver() {} + + // Notifies when the keyboard is suppressed. + virtual void OnKeyboardSuppressionChanged(bool suppressed) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_OBSERVER_H_
diff --git a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc new file mode 100644 index 0000000..916499d --- /dev/null +++ b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
@@ -0,0 +1,125 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.h" + +#include <algorithm> + +#include "ash/common/keyboard/keyboard_ui.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/display/display.h" +#include "ui/events/event.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/views/controls/image_view.h" + +namespace ash { + +VirtualKeyboardTray::VirtualKeyboardTray(WmShelf* wm_shelf) + : TrayBackgroundView(wm_shelf), + icon_(new views::ImageView), + wm_shelf_(wm_shelf) { + SetInkDropMode(InkDropMode::ON); + SetContentsBackground(false); + + icon_->SetImage(gfx::CreateVectorIcon(kShelfKeyboardIcon, kShelfIconColor)); + SetIconBorderForShelfAlignment(); + tray_container()->AddChildView(icon_); + + // The Shell may not exist in some unit tests. + if (WmShell::HasInstance()) + WmShell::Get()->keyboard_ui()->AddObserver(this); + // Try observing keyboard controller, in case it is already constructed. + ObserveKeyboardController(); +} + +VirtualKeyboardTray::~VirtualKeyboardTray() { + // Try unobserving keyboard controller, in case it still exists. + UnobserveKeyboardController(); + // The Shell may not exist in some unit tests. + if (WmShell::HasInstance()) + WmShell::Get()->keyboard_ui()->RemoveObserver(this); +} + +void VirtualKeyboardTray::SetShelfAlignment(ShelfAlignment alignment) { + if (alignment == shelf_alignment()) + return; + + TrayBackgroundView::SetShelfAlignment(alignment); + SetIconBorderForShelfAlignment(); +} + +base::string16 VirtualKeyboardTray::GetAccessibleNameForTray() { + return l10n_util::GetStringUTF16( + IDS_ASH_VIRTUAL_KEYBOARD_TRAY_ACCESSIBLE_NAME); +} + +void VirtualKeyboardTray::HideBubbleWithView( + const views::TrayBubbleView* bubble_view) {} + +void VirtualKeyboardTray::ClickedOutsideBubble() {} + +bool VirtualKeyboardTray::PerformAction(const ui::Event& event) { + const int64_t display_id = + wm_shelf_->GetWindow()->GetDisplayNearestWindow().id(); + WmShell::Get()->keyboard_ui()->ShowInDisplay(display_id); + // Normally, active status is set when virtual keyboard is shown/hidden, + // however, showing virtual keyboard happens asynchronously and, especially + // the first time, takes some time. We need to set active status here to + // prevent bad things happening if user clicked the button before keyboard is + // shown. + SetIsActive(true); + return true; +} + +void VirtualKeyboardTray::OnKeyboardEnabledStateChanged(bool new_enabled) { + SetVisible(new_enabled); + if (new_enabled) { + // Observe keyboard controller to detect when the virtual keyboard is + // shown/hidden. + ObserveKeyboardController(); + } else { + // Try unobserving keyboard controller, in case it is not yet destroyed. + UnobserveKeyboardController(); + } +} + +void VirtualKeyboardTray::OnKeyboardBoundsChanging( + const gfx::Rect& new_bounds) { + SetIsActive(!new_bounds.IsEmpty()); +} + +void VirtualKeyboardTray::OnKeyboardClosed() {} + +void VirtualKeyboardTray::SetIconBorderForShelfAlignment() { + const gfx::ImageSkia& image = icon_->GetImage(); + const int vertical_padding = (kTrayItemSize - image.height()) / 2; + const int horizontal_padding = (kTrayItemSize - image.width()) / 2; + icon_->SetBorder(views::CreateEmptyBorder( + gfx::Insets(vertical_padding, horizontal_padding))); +} + +void VirtualKeyboardTray::ObserveKeyboardController() { + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) + keyboard_controller->AddObserver(this); +} + +void VirtualKeyboardTray::UnobserveKeyboardController() { + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) + keyboard_controller->RemoveObserver(this); +} + +} // namespace ash
diff --git a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.h b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.h new file mode 100644 index 0000000..9a818ee --- /dev/null +++ b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.h
@@ -0,0 +1,59 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_CHROMEOS_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_ +#define ASH_COMMON_SYSTEM_CHROMEOS_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_ + +#include "ash/common/keyboard/keyboard_ui_observer.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "base/macros.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace views { +class ImageView; +} + +namespace ash { + +// TODO(sky): make this visible on non-chromeos platforms. +class VirtualKeyboardTray : public TrayBackgroundView, + public KeyboardUIObserver, + public keyboard::KeyboardControllerObserver { + public: + explicit VirtualKeyboardTray(WmShelf* wm_shelf); + ~VirtualKeyboardTray() override; + + // TrayBackgroundView: + void SetShelfAlignment(ShelfAlignment alignment) override; + base::string16 GetAccessibleNameForTray() override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void ClickedOutsideBubble() override; + bool PerformAction(const ui::Event& event) override; + + // KeyboardUIObserver: + void OnKeyboardEnabledStateChanged(bool new_enabled) override; + + // keyboard::KeyboardControllerObserver: + void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; + void OnKeyboardClosed() override; + + private: + // Creates a new border for the icon. The padding is determined based on the + // alignment of the shelf. + void SetIconBorderForShelfAlignment(); + + void ObserveKeyboardController(); + void UnobserveKeyboardController(); + + // Weak pointer, will be parented by TrayContainer for its lifetime. + views::ImageView* icon_; + + WmShelf* wm_shelf_; + + DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_CHROMEOS_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_
diff --git a/ash/common/system/date/clock_observer.h b/ash/common/system/date/clock_observer.h new file mode 100644 index 0000000..0ba4ed1 --- /dev/null +++ b/ash/common/system/date/clock_observer.h
@@ -0,0 +1,26 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_DATE_CLOCK_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_DATE_CLOCK_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class ASH_EXPORT ClockObserver { + public: + virtual ~ClockObserver() {} + + virtual void OnDateFormatChanged() = 0; + virtual void OnSystemClockTimeUpdated() = 0; + virtual void OnSystemClockCanSetTimeChanged(bool can_set_time) = 0; + + // Force a refresh (e.g. after the system is resumed). + virtual void Refresh() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_DATE_CLOCK_OBSERVER_H_
diff --git a/ash/common/system/date/date_default_view.cc b/ash/common/system/date/date_default_view.cc new file mode 100644 index 0000000..c54d7b8 --- /dev/null +++ b/ash/common/system/date/date_default_view.cc
@@ -0,0 +1,146 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/date_default_view.h" + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shutdown_controller.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/tray/special_popup_row.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_header_button.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/wm/lock_state_controller.h" +#include "base/i18n/rtl.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/session_manager_client.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" + +namespace { + +// The ISO-639 code for the Hebrew locale. The help icon asset is a '?' which is +// not mirrored in this locale. +const char kHebrewLocale[] = "he"; + +const int kPaddingVertical = 19; + +} // namespace + +namespace ash { + +DateDefaultView::DateDefaultView(SystemTrayItem* owner, LoginStatus login) + : help_button_(nullptr), + shutdown_button_(nullptr), + lock_button_(nullptr), + date_view_(nullptr) { + SetLayoutManager(new views::FillLayout); + + date_view_ = new tray::DateView(owner); + date_view_->SetBorder(views::CreateEmptyBorder( + kPaddingVertical, ash::kTrayPopupPaddingHorizontal, 0, 0)); + SpecialPopupRow* view = new SpecialPopupRow(); + view->SetContent(date_view_); + AddChildView(view); + + WmShell* shell = WmShell::Get(); + const bool adding_user = + shell->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); + + if (login == LoginStatus::LOCKED || login == LoginStatus::NOT_LOGGED_IN || + adding_user) + return; + + date_view_->SetAction(tray::DateView::DateAction::SHOW_DATE_SETTINGS); + + help_button_ = new TrayPopupHeaderButton( + this, IDR_AURA_UBER_TRAY_HELP, IDR_AURA_UBER_TRAY_HELP, + IDR_AURA_UBER_TRAY_HELP_HOVER, IDR_AURA_UBER_TRAY_HELP_HOVER, + IDS_ASH_STATUS_TRAY_HELP); + + if (base::i18n::IsRTL() && + base::i18n::GetConfiguredLocale() == kHebrewLocale) { + // The asset for the help button is a question mark '?'. Normally this asset + // is flipped in RTL locales, however Hebrew uses the LTR '?'. So the + // flipping must be disabled. (crbug.com/475237) + help_button_->EnableCanvasFlippingForRTLUI(false); + } + help_button_->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HELP)); + view->AddViewToRowNonMd(help_button_, true); + + if (login != LoginStatus::LOCKED) { + shutdown_button_ = new TrayPopupHeaderButton( + this, IDR_AURA_UBER_TRAY_SHUTDOWN, IDR_AURA_UBER_TRAY_SHUTDOWN, + IDR_AURA_UBER_TRAY_SHUTDOWN_HOVER, IDR_AURA_UBER_TRAY_SHUTDOWN_HOVER, + IDS_ASH_STATUS_TRAY_SHUTDOWN); + shutdown_button_->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SHUTDOWN)); + view->AddViewToRowNonMd(shutdown_button_, true); + // This object is recreated every time the menu opens. Don't bother updating + // the tooltip if the shutdown policy changes while the menu is open. + bool reboot = WmShell::Get()->shutdown_controller()->reboot_on_shutdown(); + shutdown_button_->SetTooltipText(l10n_util::GetStringUTF16( + reboot ? IDS_ASH_STATUS_TRAY_REBOOT : IDS_ASH_STATUS_TRAY_SHUTDOWN)); + } + + if (shell->GetSessionStateDelegate()->CanLockScreen()) { + lock_button_ = new TrayPopupHeaderButton( + this, IDR_AURA_UBER_TRAY_LOCKSCREEN, IDR_AURA_UBER_TRAY_LOCKSCREEN, + IDR_AURA_UBER_TRAY_LOCKSCREEN_HOVER, + IDR_AURA_UBER_TRAY_LOCKSCREEN_HOVER, IDS_ASH_STATUS_TRAY_LOCK); + lock_button_->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCK)); + view->AddViewToRowNonMd(lock_button_, true); + } +} + +DateDefaultView::~DateDefaultView() {} + +views::View* DateDefaultView::GetHelpButtonView() { + return help_button_; +} + +const views::View* DateDefaultView::GetShutdownButtonViewForTest() const { + return shutdown_button_; +} + +tray::DateView* DateDefaultView::GetDateView() { + return date_view_; +} + +const tray::DateView* DateDefaultView::GetDateView() const { + return date_view_; +} + +void DateDefaultView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + WmShell* shell = WmShell::Get(); + if (sender == help_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_HELP); + shell->system_tray_controller()->ShowHelp(); + } else if (sender == shutdown_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_SHUT_DOWN); + Shell::GetInstance()->lock_state_controller()->RequestShutdown(); + } else if (sender == lock_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_LOCK_SCREEN); + chromeos::DBusThreadManager::Get() + ->GetSessionManagerClient() + ->RequestLockScreen(); + } else { + NOTREACHED(); + } + date_view_->CloseSystemBubble(); +} + +} // namespace ash
diff --git a/ash/common/system/date/date_default_view.h b/ash/common/system/date/date_default_view.h new file mode 100644 index 0000000..6adaee0 --- /dev/null +++ b/ash/common/system/date/date_default_view.h
@@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_DATE_DATE_DEFAULT_VIEW_H_ +#define ASH_COMMON_SYSTEM_DATE_DATE_DEFAULT_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "base/macros.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace ash { +namespace tray { +class DateView; +} // namespace tray + +class SystemTrayItem; +class TrayPopupHeaderButton; + +// The system tray bubble view with the date and buttons for help, lock and +// shutdown. +// TODO(tdanderson): Remove this class once material design is enabled by +// default. See crbug.com/614453. +class ASH_EXPORT DateDefaultView : public views::View, + public views::ButtonListener { + public: + DateDefaultView(SystemTrayItem* owner, LoginStatus login); + + ~DateDefaultView() override; + + views::View* GetHelpButtonView(); + const views::View* GetShutdownButtonViewForTest() const; + + tray::DateView* GetDateView(); + const tray::DateView* GetDateView() const; + + private: + // Overridden from views::ButtonListener. + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + TrayPopupHeaderButton* help_button_; + TrayPopupHeaderButton* shutdown_button_; + TrayPopupHeaderButton* lock_button_; + tray::DateView* date_view_; + + DISALLOW_COPY_AND_ASSIGN(DateDefaultView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_DATE_DATE_DEFAULT_VIEW_H_
diff --git a/ash/common/system/date/date_view.cc b/ash/common/system/date/date_view.cc new file mode 100644 index 0000000..9aa1eb5 --- /dev/null +++ b/ash/common/system/date/date_view.cc
@@ -0,0 +1,408 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/date_view.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/i18n/rtl.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "third_party/icu/source/i18n/unicode/datefmt.h" +#include "third_party/icu/source/i18n/unicode/dtptngen.h" +#include "third_party/icu/source/i18n/unicode/smpdtfmt.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace tray { +namespace { + +// Amount of slop to add into the timer to make sure we're into the next minute +// when the timer goes off. +const int kTimerSlopSeconds = 1; + +// Text color of the vertical clock minutes. +const SkColor kVerticalClockMinuteColor = SkColorSetRGB(0xBA, 0xBA, 0xBA); + +// Padding between the left edge of the shelf and the left edge of the vertical +// clock. +const int kVerticalClockLeftPadding = 9; + +// Offset used to bring the minutes line closer to the hours line in the +// vertical clock. +const int kVerticalClockMinutesTopOffset = -4; +const int kVerticalClockMinutesTopOffsetMD = -2; + +// Leading padding used to draw the tray background to the left of the clock +// when the shelf is vertically aligned. +const int kClockLeadingPadding = 8; + +bool UseMd() { + return MaterialDesignController::IsSystemTrayMenuMaterial(); +} + +base::string16 FormatDateWithPattern(const base::Time& time, + const char* pattern) { + UErrorCode status = U_ZERO_ERROR; + std::unique_ptr<icu::DateTimePatternGenerator> generator( + icu::DateTimePatternGenerator::createInstance(status)); + DCHECK(U_SUCCESS(status)); + icu::UnicodeString generated_pattern = + generator->getBestPattern(icu::UnicodeString(pattern), status); + DCHECK(U_SUCCESS(status)); + icu::SimpleDateFormat simple_formatter(generated_pattern, status); + DCHECK(U_SUCCESS(status)); + icu::UnicodeString date_string; + simple_formatter.format(static_cast<UDate>(time.ToDoubleT() * 1000), + date_string, status); + DCHECK(U_SUCCESS(status)); + return base::string16(date_string.getBuffer(), + static_cast<size_t>(date_string.length())); +} + +base::string16 FormatDate(const base::Time& time) { + if (UseMd()) { + // Use 'short' month format (e.g., "Oct") followed by non-padded day of + // month (e.g., "2", "10"). + return FormatDateWithPattern(time, "LLLd"); + } else { + icu::UnicodeString date_string; + std::unique_ptr<icu::DateFormat> formatter( + icu::DateFormat::createDateInstance(icu::DateFormat::kMedium)); + formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string); + return base::string16(date_string.getBuffer(), + static_cast<size_t>(date_string.length())); + } +} + +base::string16 FormatDayOfWeek(const base::Time& time) { + // Use 'short' day of week format (e.g., "Wed"). + return FormatDateWithPattern(time, "EEE"); +} + +} // namespace + +BaseDateTimeView::~BaseDateTimeView() { + timer_.Stop(); +} + +void BaseDateTimeView::UpdateText() { + base::Time now = base::Time::Now(); + UpdateTextInternal(now); + SchedulePaint(); + SetTimer(now); +} + +void BaseDateTimeView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + ActionableView::GetAccessibleNodeData(node_data); + node_data->role = ui::AX_ROLE_TIME; +} + +BaseDateTimeView::BaseDateTimeView(SystemTrayItem* owner) + : ActionableView(owner, TrayPopupInkDropStyle::INSET_BOUNDS), + hour_type_(WmShell::Get()->system_tray_controller()->hour_clock_type()) { + SetTimer(base::Time::Now()); + SetFocusBehavior(FocusBehavior::NEVER); +} + +void BaseDateTimeView::SetTimer(const base::Time& now) { + // Try to set the timer to go off at the next change of the minute. We don't + // want to have the timer go off more than necessary since that will cause + // the CPU to wake up and consume power. + base::Time::Exploded exploded; + now.LocalExplode(&exploded); + + // Often this will be called at minute boundaries, and we'll actually want + // 60 seconds from now. + int seconds_left = 60 - exploded.second; + if (seconds_left == 0) + seconds_left = 60; + + // Make sure that the timer fires on the next minute. Without this, if it is + // called just a teeny bit early, then it will skip the next minute. + seconds_left += kTimerSlopSeconds; + + timer_.Stop(); + timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(seconds_left), this, + &BaseDateTimeView::UpdateText); +} + +void BaseDateTimeView::UpdateTextInternal(const base::Time& now) { + SetAccessibleName(base::TimeFormatTimeOfDayWithHourClockType( + now, hour_type_, base::kKeepAmPm) + + base::ASCIIToUTF16(", ") + + base::TimeFormatFriendlyDate(now)); + + NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); +} + +void BaseDateTimeView::ChildPreferredSizeChanged(views::View* child) { + PreferredSizeChanged(); +} + +void BaseDateTimeView::OnLocaleChanged() { + UpdateText(); +} + +/////////////////////////////////////////////////////////////////////////////// + +DateView::DateView(SystemTrayItem* owner) + : BaseDateTimeView(owner), action_(DateAction::NONE) { + if (UseMd()) { + // TODO(tdanderson): Tweak spacing and layout for material design. + views::BoxLayout* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + box_layout->set_inside_border_insets(gfx::Insets(0, 12, 0, 0)); + box_layout->set_main_axis_alignment( + views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); + box_layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + SetLayoutManager(box_layout); + } else { + SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); + } + date_label_ = TrayPopupUtils::CreateDefaultLabel(); + date_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + if (!UseMd()) + date_label_->SetEnabledColor(kHeaderTextColorNormal); + UpdateTextInternal(base::Time::Now()); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); + style.SetupLabel(date_label_); + AddChildView(date_label_); +} + +DateView::~DateView() {} + +void DateView::SetAction(DateAction action) { + if (action == action_) + return; + if (IsMouseHovered() && !UseMd()) { + date_label_->SetEnabledColor(action == DateAction::NONE + ? kHeaderTextColorNormal + : kHeaderTextColorHover); + SchedulePaint(); + } + action_ = action; + SetFocusBehavior(action_ != DateAction::NONE ? FocusBehavior::ALWAYS + : FocusBehavior::NEVER); + + // Disable |this| when not clickable so that the material design ripple is + // not shown. + if (UseMd()) { + SetEnabled(action_ != DateAction::NONE); + if (action_ != DateAction::NONE) + SetInkDropMode(views::InkDropHostView::InkDropMode::ON); + } +} + +void DateView::UpdateTimeFormat() { + hour_type_ = WmShell::Get()->system_tray_controller()->hour_clock_type(); + UpdateText(); +} + +base::HourClockType DateView::GetHourTypeForTesting() const { + return hour_type_; +} + +void DateView::SetActive(bool active) { + if (UseMd()) + return; + + date_label_->SetEnabledColor(active ? kHeaderTextColorHover + : kHeaderTextColorNormal); + SchedulePaint(); +} + +void DateView::UpdateTextInternal(const base::Time& now) { + BaseDateTimeView::UpdateTextInternal(now); + date_label_->SetText(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DATE, FormatDayOfWeek(now), FormatDate(now))); +} + +bool DateView::PerformAction(const ui::Event& event) { + if (action_ == DateAction::NONE) + return false; + if (action_ == DateAction::SHOW_DATE_SETTINGS) + WmShell::Get()->system_tray_controller()->ShowDateSettings(); + else if (action_ == DateAction::SET_SYSTEM_TIME) + WmShell::Get()->system_tray_controller()->ShowSetTimeDialog(); + else + return false; + CloseSystemBubble(); + return true; +} + +void DateView::OnMouseEntered(const ui::MouseEvent& event) { + if (action_ == DateAction::NONE) + return; + SetActive(true); +} + +void DateView::OnMouseExited(const ui::MouseEvent& event) { + if (action_ == DateAction::NONE) + return; + SetActive(false); +} + +void DateView::OnGestureEvent(ui::GestureEvent* event) { + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetActive(true); + } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || + event->type() == ui::ET_GESTURE_END) { + SetActive(false); + } + BaseDateTimeView::OnGestureEvent(event); +} + +/////////////////////////////////////////////////////////////////////////////// + +TimeView::TimeView(ClockLayout clock_layout) : BaseDateTimeView(nullptr) { + SetupLabels(); + UpdateTextInternal(base::Time::Now()); + UpdateClockLayout(clock_layout); +} + +TimeView::~TimeView() {} + +void TimeView::UpdateTimeFormat() { + hour_type_ = WmShell::Get()->system_tray_controller()->hour_clock_type(); + UpdateText(); +} + +base::HourClockType TimeView::GetHourTypeForTesting() const { + return hour_type_; +} + +void TimeView::UpdateTextInternal(const base::Time& now) { + // Just in case |now| is null, do NOT update time; otherwise, it will + // crash icu code by calling into base::TimeFormatTimeOfDayWithHourClockType, + // see details in crbug.com/147570. + if (now.is_null()) { + LOG(ERROR) << "Received null value from base::Time |now| in argument"; + return; + } + + BaseDateTimeView::UpdateTextInternal(now); + base::string16 current_time = base::TimeFormatTimeOfDayWithHourClockType( + now, hour_type_, base::kDropAmPm); + horizontal_label_->SetText(current_time); + horizontal_label_->SetTooltipText(base::TimeFormatFriendlyDate(now)); + + // Calculate vertical clock layout labels. + size_t colon_pos = current_time.find(base::ASCIIToUTF16(":")); + base::string16 hour = current_time.substr(0, colon_pos); + base::string16 minute = current_time.substr(colon_pos + 1); + + // Sometimes pad single-digit hours with a zero for aesthetic reasons. + if (hour.length() == 1 && hour_type_ == base::k24HourClock && + !base::i18n::IsRTL()) + hour = base::ASCIIToUTF16("0") + hour; + + vertical_label_hours_->SetText(hour); + vertical_label_minutes_->SetText(minute); + Layout(); +} + +bool TimeView::PerformAction(const ui::Event& event) { + return false; +} + +bool TimeView::OnMousePressed(const ui::MouseEvent& event) { + // Let the event fall through. + return false; +} + +void TimeView::OnGestureEvent(ui::GestureEvent* event) { + // Skip gesture handling happening in CustomButton so that the container views + // receive and handle them properly. + // TODO(mohsen): Refactor TimeView/DateView classes so that they are not + // ActionableView anymore. Create an ActionableView as a container for when + // needed. +} + +void TimeView::UpdateClockLayout(ClockLayout clock_layout) { + SetBorderFromLayout(clock_layout); + if (clock_layout == ClockLayout::HORIZONTAL_CLOCK) { + RemoveChildView(vertical_label_hours_.get()); + RemoveChildView(vertical_label_minutes_.get()); + SetLayoutManager(new views::FillLayout()); + AddChildView(horizontal_label_.get()); + } else { + const bool is_material_design = MaterialDesignController::IsShelfMaterial(); + RemoveChildView(horizontal_label_.get()); + views::GridLayout* layout = new views::GridLayout(this); + SetLayoutManager(layout); + const int kColumnId = 0; + views::ColumnSet* columns = layout->AddColumnSet(kColumnId); + columns->AddPaddingColumn(0, kVerticalClockLeftPadding); + columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, + 0, views::GridLayout::USE_PREF, 0, 0); + layout->AddPaddingRow( + 0, is_material_design ? kClockLeadingPadding + : kTrayLabelItemVerticalPaddingVerticalAlignment); + layout->StartRow(0, kColumnId); + layout->AddView(vertical_label_hours_.get()); + layout->StartRow(0, kColumnId); + layout->AddView(vertical_label_minutes_.get()); + layout->AddPaddingRow( + 0, + is_material_design + ? kTrayImageItemPadding + kVerticalClockMinutesTopOffsetMD + : kTrayLabelItemVerticalPaddingVerticalAlignment); + } + Layout(); +} + +void TimeView::SetBorderFromLayout(ClockLayout clock_layout) { + if (clock_layout == ClockLayout::HORIZONTAL_CLOCK) { + SetBorder(views::CreateEmptyBorder( + gfx::Insets(0, + UseMd() ? kTrayImageItemPadding + : kTrayLabelItemHorizontalPaddingBottomAlignment))); + } else { + SetBorder(views::NullBorder()); + } +} + +void TimeView::SetupLabels() { + horizontal_label_.reset(new views::Label()); + SetupLabel(horizontal_label_.get()); + vertical_label_hours_.reset(new views::Label()); + SetupLabel(vertical_label_hours_.get()); + vertical_label_minutes_.reset(new views::Label()); + SetupLabel(vertical_label_minutes_.get()); + // TODO(estade): this should use the NativeTheme's secondary text color. + vertical_label_minutes_->SetEnabledColor(kVerticalClockMinuteColor); + // Pull the minutes up closer to the hours by using a negative top border. + vertical_label_minutes_->SetBorder( + views::CreateEmptyBorder(MaterialDesignController::IsShelfMaterial() + ? kVerticalClockMinutesTopOffsetMD + : kVerticalClockMinutesTopOffset, + 0, 0, 0)); +} + +void TimeView::SetupLabel(views::Label* label) { + label->set_owned_by_client(); + SetupLabelForTray(label); + label->SetElideBehavior(gfx::NO_ELIDE); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/date/date_view.h b/ash/common/system/date/date_view.h new file mode 100644 index 0000000..39d7afa6 --- /dev/null +++ b/ash/common/system/date/date_view.h
@@ -0,0 +1,158 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_DATE_DATE_VIEW_H_ +#define ASH_COMMON_SYSTEM_DATE_DATE_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/system/date/tray_date.h" +#include "ash/common/system/tray/actionable_view.h" +#include "base/i18n/time_formatting.h" +#include "base/macros.h" +#include "base/timer/timer.h" +#include "ui/views/view.h" + +namespace base { +class Time; +} + +namespace views { +class Label; +} + +namespace ash { +namespace tray { + +// Abstract base class containing common updating and layout code for the +// DateView popup and the TimeView tray icon. Exported for tests. +class ASH_EXPORT BaseDateTimeView : public ActionableView { + public: + ~BaseDateTimeView() override; + + // Updates the displayed text for the current time and calls SetTimer(). + void UpdateText(); + + // views::View: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + protected: + explicit BaseDateTimeView(SystemTrayItem* owner); + + // Updates labels to display the current time. + virtual void UpdateTextInternal(const base::Time& now); + + // Time format (12/24hr) used for accessibility string. + base::HourClockType hour_type_; + + private: + // Starts |timer_| to schedule the next update. + void SetTimer(const base::Time& now); + + // views::View: + void ChildPreferredSizeChanged(views::View* child) override; + void OnLocaleChanged() override; + + // Invokes UpdateText() when the displayed time should change. + base::OneShotTimer timer_; + + DISALLOW_COPY_AND_ASSIGN(BaseDateTimeView); +}; + +// Popup view used to display the date and day of week. +class ASH_EXPORT DateView : public BaseDateTimeView { + public: + enum class DateAction { + NONE, + SET_SYSTEM_TIME, + SHOW_DATE_SETTINGS, + }; + + explicit DateView(SystemTrayItem* owner); + ~DateView() override; + + // Sets the action the view should take. An actionable date view gives visual + // feedback on hover, can be focused by keyboard, and clicking/pressing space + // or enter on the view executes the action. + void SetAction(DateAction action); + + // Updates the format of the displayed time. + void UpdateTimeFormat(); + + base::HourClockType GetHourTypeForTesting() const; + + private: + // Sets active rendering state and updates the color of |date_label_|. + void SetActive(bool active); + + // BaseDateTimeView: + void UpdateTextInternal(const base::Time& now) override; + + // ActionableView: + bool PerformAction(const ui::Event& event) override; + + // views::View: + void OnMouseEntered(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + + views::Label* date_label_; + + DateAction action_; + + DISALLOW_COPY_AND_ASSIGN(DateView); +}; + +// Tray view used to display the current time. +// Exported for tests. +class ASH_EXPORT TimeView : public BaseDateTimeView { + public: + enum class ClockLayout { + HORIZONTAL_CLOCK, + VERTICAL_CLOCK, + }; + + explicit TimeView(ClockLayout clock_layout); + ~TimeView() override; + + // Updates the format of the displayed time. + void UpdateTimeFormat(); + + // Updates clock layout. + void UpdateClockLayout(ClockLayout clock_layout); + + base::HourClockType GetHourTypeForTesting() const; + + private: + friend class TimeViewTest; + + // BaseDateTimeView: + void UpdateTextInternal(const base::Time& now) override; + + // ActionableView: + bool PerformAction(const ui::Event& event) override; + + // views::View: + bool OnMousePressed(const ui::MouseEvent& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + + void SetBorderFromLayout(ClockLayout clock_layout); + void SetupLabels(); + void SetupLabel(views::Label* label); + + // Label text used for the normal horizontal shelf. + std::unique_ptr<views::Label> horizontal_label_; + + // The time label is split into two lines for the vertical shelf. + std::unique_ptr<views::Label> vertical_label_hours_; + std::unique_ptr<views::Label> vertical_label_minutes_; + + DISALLOW_COPY_AND_ASSIGN(TimeView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_DATE_DATE_VIEW_H_
diff --git a/ash/common/system/date/date_view_unittest.cc b/ash/common/system/date/date_view_unittest.cc new file mode 100644 index 0000000..94699a6 --- /dev/null +++ b/ash/common/system/date/date_view_unittest.cc
@@ -0,0 +1,64 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/date_view.h" + +#include "ash/common/test/ash_test.h" +#include "ui/views/controls/label.h" + +namespace ash { +namespace tray { + +class TimeViewTest : public AshTest { + public: + TimeViewTest() {} + ~TimeViewTest() override {} + + TimeView* time_view() { return time_view_.get(); } + + // Access to private fields of |time_view_|. + views::Label* horizontal_label() { + return time_view_->horizontal_label_.get(); + } + views::Label* vertical_label_hours() { + return time_view_->vertical_label_hours_.get(); + } + views::Label* vertical_label_minutes() { + return time_view_->vertical_label_minutes_.get(); + } + + // Creates a time view with horizontal or vertical |clock_layout|. + void CreateTimeView(TimeView::ClockLayout clock_layout) { + time_view_.reset(new TimeView(clock_layout)); + } + + private: + std::unique_ptr<TimeView> time_view_; + + DISALLOW_COPY_AND_ASSIGN(TimeViewTest); +}; + +// Test the basics of the time view, mostly to ensure we don't leak memory. +TEST_F(TimeViewTest, Basics) { + // A newly created horizontal clock only has the horizontal label. + CreateTimeView(TimeView::ClockLayout::HORIZONTAL_CLOCK); + EXPECT_EQ(time_view(), horizontal_label()->parent()); + EXPECT_FALSE(vertical_label_hours()->parent()); + EXPECT_FALSE(vertical_label_minutes()->parent()); + + // Switching the clock to vertical updates the labels. + time_view()->UpdateClockLayout(TimeView::ClockLayout::VERTICAL_CLOCK); + EXPECT_FALSE(horizontal_label()->parent()); + EXPECT_EQ(time_view(), vertical_label_hours()->parent()); + EXPECT_EQ(time_view(), vertical_label_minutes()->parent()); + + // Switching back to horizontal updates the labels again. + time_view()->UpdateClockLayout(TimeView::ClockLayout::HORIZONTAL_CLOCK); + EXPECT_EQ(time_view(), horizontal_label()->parent()); + EXPECT_FALSE(vertical_label_hours()->parent()); + EXPECT_FALSE(vertical_label_minutes()->parent()); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/date/system_info_default_view.cc b/ash/common/system/date/system_info_default_view.cc new file mode 100644 index 0000000..695453e5 --- /dev/null +++ b/ash/common/system/date/system_info_default_view.cc
@@ -0,0 +1,95 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/system_info_default_view.h" + +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/chromeos/power/power_status_view.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "base/memory/ptr_util.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +// The minimum number of menu button widths that the date view should span +// horizontally. +const int kMinNumTileWidths = 2; + +// The maximum number of menu button widths that the date view should span +// horizontally. +const int kMaxNumTileWidths = 3; + +SystemInfoDefaultView::SystemInfoDefaultView(SystemTrayItem* owner, + LoginStatus login) + : date_view_(nullptr), + tri_view_(TrayPopupUtils::CreateMultiTargetRowView()) { + tri_view_->SetMinHeight(kTrayPopupSystemInfoRowHeight); + AddChildView(tri_view_); + SetLayoutManager(new views::FillLayout); + + date_view_ = new tray::DateView(owner); + tri_view_->AddView(TriView::Container::START, date_view_); + + if (PowerStatus::Get()->IsBatteryPresent()) { + power_status_view_ = new ash::PowerStatusView(false); + std::unique_ptr<views::BoxLayout> box_layout = + base::MakeUnique<views::BoxLayout>(views::BoxLayout::kHorizontal, 0, 0, + 0); + box_layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + box_layout->set_inside_border_insets( + gfx::Insets(0, 0, 0, kTrayPopupLabelRightPadding)); + tri_view_->SetContainerLayout(TriView::Container::CENTER, + std::move(box_layout)); + + tri_view_->AddView(TriView::Container::CENTER, + TrayPopupUtils::CreateVerticalSeparator()); + tri_view_->AddView(TriView::Container::CENTER, power_status_view_); + } + tri_view_->SetContainerVisible(TriView::Container::END, false); + + if (TrayPopupUtils::CanOpenWebUISettings(login)) + date_view_->SetAction(tray::DateView::DateAction::SHOW_DATE_SETTINGS); +} + +SystemInfoDefaultView::~SystemInfoDefaultView() {} + +tray::DateView* SystemInfoDefaultView::GetDateView() { + return date_view_; +} + +const tray::DateView* SystemInfoDefaultView::GetDateView() const { + return date_view_; +} + +void SystemInfoDefaultView::Layout() { + gfx::Size min_start_size = tri_view_->GetMinSize(TriView::Container::START); + min_start_size.set_width( + CalculateDateViewWidth(date_view_->GetPreferredSize().width())); + tri_view_->SetMinSize(TriView::Container::START, min_start_size); + + views::View::Layout(); +} + +int SystemInfoDefaultView::CalculateDateViewWidth(int preferred_width) { + const float snap_to_width = kSeparatorWidth + kMenuButtonSize; + int num_extra_tile_widths = 0; + if (preferred_width > kMenuButtonSize) { + const float extra_width = preferred_width - kMenuButtonSize; + const float preferred_width_ratio = extra_width / snap_to_width; + num_extra_tile_widths = std::ceil(preferred_width_ratio); + } + num_extra_tile_widths = + std::max(kMinNumTileWidths - 1, + std::min(num_extra_tile_widths, kMaxNumTileWidths - 1)); + + return kMenuButtonSize + num_extra_tile_widths * snap_to_width; +} + +} // namespace ash
diff --git a/ash/common/system/date/system_info_default_view.h b/ash/common/system/date/system_info_default_view.h new file mode 100644 index 0000000..95fcb010f --- /dev/null +++ b/ash/common/system/date/system_info_default_view.h
@@ -0,0 +1,58 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_DATE_SYSTEM_INFO_DEFAULT_VIEW_H_ +#define ASH_COMMON_SYSTEM_DATE_SYSTEM_INFO_DEFAULT_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "base/macros.h" +#include "ui/views/view.h" + +namespace ash { +class PowerStatusView; +class SystemTrayItem; +class TriView; + +namespace tray { +class DateView; +} // namespace tray + +// The default view for the system info row in the system menu. Contains the +// current date and, if a battery is present, a string showing the current +// power status. +class ASH_EXPORT SystemInfoDefaultView : public views::View { + public: + SystemInfoDefaultView(SystemTrayItem* owner, LoginStatus login); + + ~SystemInfoDefaultView() override; + + tray::DateView* GetDateView(); + const tray::DateView* GetDateView() const; + + // views::View: + void Layout() override; + + private: + friend class SystemInfoDefaultViewTest; + + // Computes and returns the width for |date_view_| so that the separator to + // its right has the same x-position as a separator in the tiles row above. + // Depending on the width of the date string, we align the separator with + // either the second or third separator in the tiles row (|kMinNumTileWidths| + // and |kMaxNumTileWidths| respectively. + static int CalculateDateViewWidth(int preferred_width); + + tray::DateView* date_view_; + + PowerStatusView* power_status_view_ = nullptr; + + TriView* tri_view_; + + DISALLOW_COPY_AND_ASSIGN(SystemInfoDefaultView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_DATE_SYSTEM_INFO_DEFAULT_VIEW_H_
diff --git a/ash/common/system/date/system_info_default_view_unittest.cc b/ash/common/system/date/system_info_default_view_unittest.cc new file mode 100644 index 0000000..79c9577 --- /dev/null +++ b/ash/common/system/date/system_info_default_view_unittest.cc
@@ -0,0 +1,77 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/system_info_default_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/view.h" + +namespace ash { + +class SystemInfoDefaultViewTest : public testing::Test { + public: + SystemInfoDefaultViewTest() {} + + protected: + // Wrapper calls for SystemInfoDefaultView internals. + int CalculateDateViewWidth(int preferred_width) { + return SystemInfoDefaultView::CalculateDateViewWidth(preferred_width); + } + + private: + DISALLOW_COPY_AND_ASSIGN(SystemInfoDefaultViewTest); +}; + +TEST_F(SystemInfoDefaultViewTest, PreferredWidthSmallerThanButtonWidth) { + const int kPreferredWidth = 10; + EXPECT_LT(kPreferredWidth, kMenuButtonSize); + const int effective_width = CalculateDateViewWidth(kPreferredWidth); + + EXPECT_EQ(effective_width, + kMenuButtonSize + kSeparatorWidth + kMenuButtonSize); +} + +TEST_F(SystemInfoDefaultViewTest, PreferredWidthGreaterThanOneButtonWidth) { + const int kPreferredWidth = kMenuButtonSize + 1; + const int effective_width = CalculateDateViewWidth(kPreferredWidth); + + EXPECT_EQ(effective_width, + kMenuButtonSize + kSeparatorWidth + kMenuButtonSize); +} + +TEST_F(SystemInfoDefaultViewTest, PreferredWidthEqualToTwoButtonWidths) { + const int kPreferredWidth = + kMenuButtonSize + kSeparatorWidth + kMenuButtonSize; + const int effective_width = CalculateDateViewWidth(kPreferredWidth); + + EXPECT_EQ(effective_width, kPreferredWidth); +} + +TEST_F(SystemInfoDefaultViewTest, PreferredWidthGreaterThanTwoButtonWidths) { + const int kPreferredWidth = + kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) + 1; + const int effective_width = CalculateDateViewWidth(kPreferredWidth); + + EXPECT_EQ(effective_width, + kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2); +} + +TEST_F(SystemInfoDefaultViewTest, PreferredWidthEqualToThreeButtonWidths) { + const int kPreferredWidth = + kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2; + const int effective_width = CalculateDateViewWidth(kPreferredWidth); + + EXPECT_EQ(effective_width, kPreferredWidth); +} + +TEST_F(SystemInfoDefaultViewTest, PreferredWidthGreaterThanThreeButtonWidths) { + const int kPreferredWidth = + kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2 + 1; + const int effective_width = CalculateDateViewWidth(kPreferredWidth); + + EXPECT_EQ(effective_width, + kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2); +} + +} // namespace ash
diff --git a/ash/common/system/date/tray_date.cc b/ash/common/system/date/tray_date.cc new file mode 100644 index 0000000..2ba6d6d2 --- /dev/null +++ b/ash/common/system/date/tray_date.cc
@@ -0,0 +1,126 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/tray_date.h" + +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/system_clock_observer.h" +#include "ash/common/system/date/date_default_view.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/wm_shell.h" + +namespace ash { + +TrayDate::TrayDate(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_DATE), + time_tray_(NULL), + default_view_(NULL), + login_status_(LoginStatus::NOT_LOGGED_IN), + system_clock_observer_(new SystemClockObserver()) { + WmShell::Get()->system_tray_notifier()->AddClockObserver(this); +} + +TrayDate::~TrayDate() { + WmShell::Get()->system_tray_notifier()->RemoveClockObserver(this); +} + +views::View* TrayDate::GetHelpButtonView() const { + if (!default_view_) + return NULL; + return default_view_->GetHelpButtonView(); +} + +const tray::TimeView* TrayDate::GetTimeTrayForTesting() const { + return time_tray_; +} + +const DateDefaultView* TrayDate::GetDefaultViewForTesting() const { + return default_view_; +} + +views::View* TrayDate::CreateDefaultViewForTesting(LoginStatus status) { + return CreateDefaultView(status); +} + +views::View* TrayDate::CreateTrayView(LoginStatus status) { + CHECK(time_tray_ == NULL); + tray::TimeView::ClockLayout clock_layout = + IsHorizontalAlignment(system_tray()->shelf_alignment()) + ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK + : tray::TimeView::ClockLayout::VERTICAL_CLOCK; + time_tray_ = new tray::TimeView(clock_layout); + views::View* view = new TrayItemView(this); + view->AddChildView(time_tray_); + return view; +} + +views::View* TrayDate::CreateDefaultView(LoginStatus status) { + default_view_ = new DateDefaultView(this, status); + + // Save the login status we created the view with. + login_status_ = status; + + OnSystemClockCanSetTimeChanged(system_clock_observer_->can_set_time()); + return default_view_; +} + +views::View* TrayDate::CreateDetailedView(LoginStatus status) { + return NULL; +} + +void TrayDate::DestroyTrayView() { + time_tray_ = NULL; +} + +void TrayDate::DestroyDefaultView() { + default_view_ = NULL; +} + +void TrayDate::DestroyDetailedView() {} + +void TrayDate::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayDate::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + if (time_tray_) { + tray::TimeView::ClockLayout clock_layout = + IsHorizontalAlignment(alignment) + ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK + : tray::TimeView::ClockLayout::VERTICAL_CLOCK; + time_tray_->UpdateClockLayout(clock_layout); + } +} + +void TrayDate::OnDateFormatChanged() { + if (time_tray_) + time_tray_->UpdateTimeFormat(); + if (default_view_) + default_view_->GetDateView()->UpdateTimeFormat(); +} + +void TrayDate::OnSystemClockTimeUpdated() { + if (time_tray_) + time_tray_->UpdateTimeFormat(); + if (default_view_) + default_view_->GetDateView()->UpdateTimeFormat(); +} + +void TrayDate::OnSystemClockCanSetTimeChanged(bool can_set_time) { + // Outside of a logged-in session, the date button should launch the set time + // dialog if the time can be set. + if (default_view_ && login_status_ == LoginStatus::NOT_LOGGED_IN) { + default_view_->GetDateView()->SetAction( + can_set_time ? tray::DateView::DateAction::SET_SYSTEM_TIME + : tray::DateView::DateAction::NONE); + } +} + +void TrayDate::Refresh() { + if (time_tray_) + time_tray_->UpdateText(); +} + +} // namespace ash
diff --git a/ash/common/system/date/tray_date.h b/ash/common/system/date/tray_date.h new file mode 100644 index 0000000..bf25e61 --- /dev/null +++ b/ash/common/system/date/tray_date.h
@@ -0,0 +1,76 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_DATE_TRAY_DATE_H_ +#define ASH_COMMON_SYSTEM_DATE_TRAY_DATE_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/common/system/date/clock_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { +class DateDefaultView; +class SystemClockObserver; + +namespace tray { +class TimeView; +} + +// System tray item for the time and date. +class ASH_EXPORT TrayDate : public SystemTrayItem, public ClockObserver { + public: + enum ClockLayout { + HORIZONTAL_CLOCK, + VERTICAL_CLOCK, + }; + + enum DateAction { + NONE, + SET_SYSTEM_TIME, + SHOW_DATE_SETTINGS, + }; + + explicit TrayDate(SystemTray* system_tray); + ~TrayDate() override; + + // Returns view for help button if it is exists. Returns NULL otherwise. + views::View* GetHelpButtonView() const; + + const tray::TimeView* GetTimeTrayForTesting() const; + const DateDefaultView* GetDefaultViewForTesting() const; + views::View* CreateDefaultViewForTesting(LoginStatus status); + + private: + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // Overridden from ClockObserver. + void OnDateFormatChanged() override; + void OnSystemClockTimeUpdated() override; + void OnSystemClockCanSetTimeChanged(bool can_set_time) override; + void Refresh() override; + + tray::TimeView* time_tray_; + DateDefaultView* default_view_; + LoginStatus login_status_; + + std::unique_ptr<SystemClockObserver> system_clock_observer_; + + DISALLOW_COPY_AND_ASSIGN(TrayDate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_DATE_TRAY_DATE_H_
diff --git a/ash/common/system/date/tray_system_info.cc b/ash/common/system/date/tray_system_info.cc new file mode 100644 index 0000000..aad34ff --- /dev/null +++ b/ash/common/system/date/tray_system_info.cc
@@ -0,0 +1,113 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/date/tray_system_info.h" + +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/system_clock_observer.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/date/system_info_default_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/wm_shell.h" + +namespace ash { + +TraySystemInfo::TraySystemInfo(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_DATE), + tray_view_(nullptr), + default_view_(nullptr), + login_status_(LoginStatus::NOT_LOGGED_IN), + system_clock_observer_(new SystemClockObserver()) { + WmShell::Get()->system_tray_notifier()->AddClockObserver(this); +} + +TraySystemInfo::~TraySystemInfo() { + WmShell::Get()->system_tray_notifier()->RemoveClockObserver(this); +} + +const tray::TimeView* TraySystemInfo::GetTimeTrayForTesting() const { + return tray_view_; +} + +const SystemInfoDefaultView* TraySystemInfo::GetDefaultViewForTesting() const { + return default_view_; +} + +views::View* TraySystemInfo::CreateDefaultViewForTesting(LoginStatus status) { + return CreateDefaultView(status); +} + +views::View* TraySystemInfo::CreateTrayView(LoginStatus status) { + CHECK(tray_view_ == nullptr); + tray::TimeView::ClockLayout clock_layout = + IsHorizontalAlignment(system_tray()->shelf_alignment()) + ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK + : tray::TimeView::ClockLayout::VERTICAL_CLOCK; + tray_view_ = new tray::TimeView(clock_layout); + views::View* view = new TrayItemView(this); + view->AddChildView(tray_view_); + return view; +} + +views::View* TraySystemInfo::CreateDefaultView(LoginStatus status) { + default_view_ = new SystemInfoDefaultView(this, status); + + // Save the login status we created the view with. + login_status_ = status; + + OnSystemClockCanSetTimeChanged(system_clock_observer_->can_set_time()); + return default_view_; +} + +void TraySystemInfo::DestroyTrayView() { + tray_view_ = nullptr; +} + +void TraySystemInfo::DestroyDefaultView() { + default_view_ = nullptr; +} + +void TraySystemInfo::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + if (tray_view_) { + tray::TimeView::ClockLayout clock_layout = + IsHorizontalAlignment(alignment) + ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK + : tray::TimeView::ClockLayout::VERTICAL_CLOCK; + tray_view_->UpdateClockLayout(clock_layout); + } +} + +void TraySystemInfo::OnDateFormatChanged() { + UpdateTimeFormat(); +} + +void TraySystemInfo::OnSystemClockTimeUpdated() { + UpdateTimeFormat(); +} + +void TraySystemInfo::OnSystemClockCanSetTimeChanged(bool can_set_time) { + // Outside of a logged-in session, the date button should launch the set time + // dialog if the time can be set. + if (default_view_ && login_status_ == LoginStatus::NOT_LOGGED_IN) { + default_view_->GetDateView()->SetAction( + can_set_time ? tray::DateView::DateAction::SET_SYSTEM_TIME + : tray::DateView::DateAction::NONE); + } +} + +void TraySystemInfo::Refresh() { + if (tray_view_) + tray_view_->UpdateText(); +} + +void TraySystemInfo::UpdateTimeFormat() { + if (tray_view_) + tray_view_->UpdateTimeFormat(); + if (default_view_) + default_view_->GetDateView()->UpdateTimeFormat(); +} + +} // namespace ash
diff --git a/ash/common/system/date/tray_system_info.h b/ash/common/system/date/tray_system_info.h new file mode 100644 index 0000000..7d5faa4 --- /dev/null +++ b/ash/common/system/date/tray_system_info.h
@@ -0,0 +1,67 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ +#define ASH_COMMON_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/common/system/date/clock_observer.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace views { +class Label; +} + +namespace ash { +class SystemClockObserver; +class SystemInfoDefaultView; + +namespace tray { +class TimeView; +} + +// The bottom row of the system menu. The default view shows the current date +// and power status. The tray view shows the current time. +class ASH_EXPORT TraySystemInfo : public SystemTrayItem, public ClockObserver { + public: + explicit TraySystemInfo(SystemTray* system_tray); + ~TraySystemInfo() override; + + const tray::TimeView* GetTimeTrayForTesting() const; + const SystemInfoDefaultView* GetDefaultViewForTesting() const; + views::View* CreateDefaultViewForTesting(LoginStatus status); + + private: + // SystemTrayItem: + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // ClockObserver: + void OnDateFormatChanged() override; + void OnSystemClockTimeUpdated() override; + void OnSystemClockCanSetTimeChanged(bool can_set_time) override; + void Refresh() override; + + void SetupLabelForTimeTray(views::Label* label); + void UpdateTimeFormat(); + + tray::TimeView* tray_view_; + SystemInfoDefaultView* default_view_; + LoginStatus login_status_; + + std::unique_ptr<SystemClockObserver> system_clock_observer_; + + DISALLOW_COPY_AND_ASSIGN(TraySystemInfo); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_
diff --git a/ash/common/system/ime/ime_observer.h b/ash/common/system/ime/ime_observer.h new file mode 100644 index 0000000..ed37cd00 --- /dev/null +++ b/ash/common/system/ime/ime_observer.h
@@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_IME_IME_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_IME_IME_OBSERVER_H_ + +namespace ash { + +class IMEObserver { + public: + virtual ~IMEObserver() {} + + // Notify the observer that the IME state has changed, and should be + // refreshed. + virtual void OnIMERefresh() = 0; + + // Notify the observer that the IME menu activation state has changed, and + // should be refreshed. |is_active| represents whether the new IME menu is + // active, and IME related items in system tray should be removed if + // |is_active| is true. + virtual void OnIMEMenuActivationChanged(bool is_active) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_IME_IME_OBSERVER_H_
diff --git a/ash/common/system/ime/tray_ime_chromeos.cc b/ash/common/system/ime/tray_ime_chromeos.cc new file mode 100644 index 0000000..8b2dca5 --- /dev/null +++ b/ash/common/system/ime/tray_ime_chromeos.cc
@@ -0,0 +1,385 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/ime/tray_ime_chromeos.h" + +#include <vector> + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/system/tray_accessibility.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/font.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/keyboard/keyboard_util.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace tray { + +// A |HoverHighlightView| that uses bold or normal font depending on whether +// it is selected. This view exposes itself as a checkbox to the accessibility +// framework. +class SelectableHoverHighlightView : public HoverHighlightView { + public: + SelectableHoverHighlightView(ViewClickListener* listener, + const base::string16& label, + bool selected) + : HoverHighlightView(listener), selected_(selected) { + AddLabel(label, gfx::ALIGN_LEFT, selected); + } + + ~SelectableHoverHighlightView() override {} + + protected: + // Overridden from views::View. + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + HoverHighlightView::GetAccessibleNodeData(node_data); + node_data->role = ui::AX_ROLE_CHECK_BOX; + if (selected_) + node_data->AddStateFlag(ui::AX_STATE_CHECKED); + } + + private: + bool selected_; + + DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView); +}; + +class IMEDefaultView : public TrayItemMore { + public: + IMEDefaultView(SystemTrayItem* owner, const base::string16& label) + : TrayItemMore(owner) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + SetImage(gfx::CreateVectorIcon(kSystemMenuKeyboardIcon, kMenuIconColor)); + } else { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + SetImage(*bundle.GetImageNamed(IDR_AURA_UBER_TRAY_IME).ToImageSkia()); + } + UpdateLabel(label); + } + + ~IMEDefaultView() override {} + + void UpdateLabel(const base::string16& label) { + SetLabel(label); + SetAccessibleName(label); + } + + protected: + // TrayItemMore: + void UpdateStyle() override { + TrayItemMore::UpdateStyle(); + + if (!MaterialDesignController::IsSystemTrayMenuMaterial()) + return; + + std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); + SetImage( + gfx::CreateVectorIcon(kSystemMenuKeyboardIcon, style->GetIconColor())); + } + + private: + DISALLOW_COPY_AND_ASSIGN(IMEDefaultView); +}; + +class IMEDetailedView : public ImeListView { + public: + IMEDetailedView(SystemTrayItem* owner, LoginStatus login) + : ImeListView(owner), + login_(login), + settings_(nullptr), + settings_button_(nullptr) {} + + ~IMEDetailedView() override {} + + void SetImeManagedMessage(base::string16 ime_managed_message) { + ime_managed_message_ = ime_managed_message; + } + + void Update(const IMEInfoList& list, + const IMEPropertyInfoList& property_list, + bool show_keyboard_toggle, + SingleImeBehavior single_ime_behavior) override { + ImeListView::Update(list, property_list, show_keyboard_toggle, + single_ime_behavior); + if (!MaterialDesignController::IsSystemTrayMenuMaterial() && + TrayPopupUtils::CanOpenWebUISettings(login_)) { + AppendSettings(); + } + + CreateTitleRow(IDS_ASH_STATUS_TRAY_IME); + } + + private: + // ImeListView: + void HandleViewClicked(views::View* view) override { + ImeListView::HandleViewClicked(view); + if (view == settings_) + ShowSettings(); + } + + void ResetImeListView() override { + ImeListView::ResetImeListView(); + settings_button_ = nullptr; + controlled_setting_icon_ = nullptr; + } + + void HandleButtonPressed(views::Button* sender, + const ui::Event& event) override { + ImeListView::HandleButtonPressed(sender, event); + if (sender == settings_button_) + ShowSettings(); + } + + void CreateExtraTitleRowButtons() override { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + if (!ime_managed_message_.empty()) { + controlled_setting_icon_ = TrayPopupUtils::CreateMainImageView(); + controlled_setting_icon_->SetImage( + gfx::CreateVectorIcon(kSystemMenuBusinessIcon, kMenuIconColor)); + controlled_setting_icon_->SetTooltipText(ime_managed_message_); + tri_view()->AddView(TriView::Container::END, controlled_setting_icon_); + } + + tri_view()->SetContainerVisible(TriView::Container::END, true); + settings_button_ = + CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_IME_SETTINGS); + tri_view()->AddView(TriView::Container::END, settings_button_); + } + } + + void AppendSettings() { + HoverHighlightView* container = new HoverHighlightView(this); + container->AddLabel( + ui::ResourceBundle::GetSharedInstance().GetLocalizedString( + IDS_ASH_STATUS_TRAY_IME_SETTINGS), + gfx::ALIGN_LEFT, false /* highlight */); + AddChildView(container); + settings_ = container; + } + + void ShowSettings() { + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_IME_SHOW_DETAILED); + WmShell::Get()->system_tray_controller()->ShowIMESettings(); + if (owner()->system_tray()) + owner()->system_tray()->CloseSystemBubble(); + } + + LoginStatus login_; + + // Not used in material design. + views::View* settings_; + + // Only used in material design. + views::Button* settings_button_; + + // This icon says that the IMEs are managed by policy. + views::ImageView* controlled_setting_icon_; + // If non-empty, a controlled setting icon should be displayed with this + // string as tooltip. + base::string16 ime_managed_message_; + + DISALLOW_COPY_AND_ASSIGN(IMEDetailedView); +}; + +} // namespace tray + +TrayIME::TrayIME(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_IME), + tray_label_(NULL), + default_(NULL), + detailed_(NULL), + keyboard_suppressed_(false), + is_visible_(true) { + SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); + tray_notifier->AddVirtualKeyboardObserver(this); + tray_notifier->AddAccessibilityObserver(this); + tray_notifier->AddIMEObserver(this); +} + +TrayIME::~TrayIME() { + SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); + tray_notifier->RemoveIMEObserver(this); + tray_notifier->RemoveAccessibilityObserver(this); + tray_notifier->RemoveVirtualKeyboardObserver(this); +} + +void TrayIME::OnKeyboardSuppressionChanged(bool suppressed) { + keyboard_suppressed_ = suppressed; + Update(); +} + +void TrayIME::OnAccessibilityModeChanged( + AccessibilityNotificationVisibility notify) { + Update(); +} + +void TrayIME::Update() { + UpdateTrayLabel(current_ime_, ime_list_.size()); + if (default_) { + default_->SetVisible(ShouldDefaultViewBeVisible()); + default_->UpdateLabel(GetDefaultViewLabel(ime_list_.size() > 1)); + } + if (detailed_) { + detailed_->SetImeManagedMessage(ime_managed_message_); + detailed_->Update(ime_list_, property_list_, ShouldShowKeyboardToggle(), + GetSingleImeBehavior()); + } +} + +void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) { + if (tray_label_) { + bool visible = ShouldShowImeTrayItem(count) && is_visible_; + tray_label_->SetVisible(visible); + // Do not change label before hiding because this change is noticeable. + if (!visible) + return; + if (current.third_party) { + tray_label_->label()->SetText(current.short_name + + base::UTF8ToUTF16("*")); + } else { + tray_label_->label()->SetText(current.short_name); + } + SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment()); + tray_label_->Layout(); + } +} + +bool TrayIME::ShouldShowKeyboardToggle() { + return keyboard_suppressed_ && + !WmShell::Get()->accessibility_delegate()->IsVirtualKeyboardEnabled(); +} + +base::string16 TrayIME::GetDefaultViewLabel(bool show_ime_label) { + if (show_ime_label) { + IMEInfo current; + WmShell::Get()->system_tray_delegate()->GetCurrentIME(¤t); + return current.name; + } else { + // Display virtual keyboard status instead. + int id = keyboard::IsKeyboardEnabled() + ? IDS_ASH_STATUS_TRAY_KEYBOARD_ENABLED + : IDS_ASH_STATUS_TRAY_KEYBOARD_DISABLED; + return ui::ResourceBundle::GetSharedInstance().GetLocalizedString(id); + } +} + +views::View* TrayIME::CreateTrayView(LoginStatus status) { + CHECK(tray_label_ == NULL); + tray_label_ = new TrayItemView(this); + tray_label_->CreateLabel(); + SetupLabelForTray(tray_label_->label()); + // Hide IME tray when it is created, it will be updated when it is notified + // of the IME refresh event. + tray_label_->SetVisible(false); + return tray_label_; +} + +views::View* TrayIME::CreateDefaultView(LoginStatus status) { + CHECK(default_ == NULL); + default_ = new tray::IMEDefaultView( + this, GetDefaultViewLabel(ShouldShowImeTrayItem(ime_list_.size()))); + default_->SetVisible(ShouldDefaultViewBeVisible()); + return default_; +} + +views::View* TrayIME::CreateDetailedView(LoginStatus status) { + CHECK(detailed_ == NULL); + detailed_ = new tray::IMEDetailedView(this, status); + detailed_->SetImeManagedMessage(ime_managed_message_); + detailed_->Init(ShouldShowKeyboardToggle(), GetSingleImeBehavior()); + return detailed_; +} + +void TrayIME::DestroyTrayView() { + tray_label_ = NULL; +} + +void TrayIME::DestroyDefaultView() { + default_ = NULL; +} + +void TrayIME::DestroyDetailedView() { + detailed_ = NULL; +} + +void TrayIME::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + SetTrayLabelItemBorder(tray_label_, alignment); + tray_label_->Layout(); +} + +void TrayIME::OnIMERefresh() { + // Caches the current ime state. + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + ime_list_.clear(); + property_list_.clear(); + delegate->GetCurrentIME(¤t_ime_); + delegate->GetAvailableIMEList(&ime_list_); + delegate->GetCurrentIMEProperties(&property_list_); + ime_managed_message_ = delegate->GetIMEManagedMessage(); + + Update(); +} + +void TrayIME::OnIMEMenuActivationChanged(bool is_active) { + is_visible_ = !is_active; + if (is_visible_) + OnIMERefresh(); + else + Update(); +} + +bool TrayIME::IsIMEManaged() { + return !ime_managed_message_.empty(); +} + +bool TrayIME::ShouldDefaultViewBeVisible() { + return is_visible_ && + (ShouldShowImeTrayItem(ime_list_.size()) || + property_list_.size() > 1 || ShouldShowKeyboardToggle()); +} + +bool TrayIME::ShouldShowImeTrayItem(size_t ime_count) { + // If managed, we want to show the tray icon even if there's only one input + // method to choose from. + size_t threshold = IsIMEManaged() ? 1 : 2; + return ime_count >= threshold; +} + +ImeListView::SingleImeBehavior TrayIME::GetSingleImeBehavior() { + // If managed, we also want to show a single IME. + return IsIMEManaged() ? ImeListView::SHOW_SINGLE_IME + : ImeListView::HIDE_SINGLE_IME; +} + +} // namespace ash
diff --git a/ash/common/system/ime/tray_ime_chromeos.h b/ash/common/system/ime/tray_ime_chromeos.h new file mode 100644 index 0000000..bce373e --- /dev/null +++ b/ash/common/system/ime/tray_ime_chromeos.h
@@ -0,0 +1,102 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_IME_TRAY_IME_CHROMEOS_H_ +#define ASH_COMMON_SYSTEM_IME_TRAY_IME_CHROMEOS_H_ + +#include <stddef.h> + +#include "ash/common/system/accessibility_observer.h" +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" +#include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h" +#include "ash/common/system/ime/ime_observer.h" +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { + +namespace tray { +class IMEDefaultView; +class IMEDetailedView; +} + +class TrayItemView; + +class ASH_EXPORT TrayIME : public SystemTrayItem, + public IMEObserver, + public AccessibilityObserver, + public VirtualKeyboardObserver { + public: + explicit TrayIME(SystemTray* system_tray); + ~TrayIME() override; + + // Overridden from VirtualKeyboardObserver. + void OnKeyboardSuppressionChanged(bool suppressed) override; + + // Overridden from AccessibilityObserver: + void OnAccessibilityModeChanged( + AccessibilityNotificationVisibility notify) override; + + private: + friend class TrayIMETest; + + // Repopulates the DefaultView and DetailedView. + void Update(); + // Updates the System Tray label. + void UpdateTrayLabel(const IMEInfo& info, size_t count); + // Returns whether the virtual keyboard toggle should be shown in the + // detailed view. + bool ShouldShowKeyboardToggle(); + // Returns the appropriate label for the detailed view. + base::string16 GetDefaultViewLabel(bool show_ime_label); + + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // Overridden from IMEObserver. + void OnIMERefresh() override; + void OnIMEMenuActivationChanged(bool is_active) override; + + // Returns true input methods are managed by policy. + bool IsIMEManaged(); + + // Whether the default view should be shown. + bool ShouldDefaultViewBeVisible(); + + // Decides if a tray icon should be shown. + bool ShouldShowImeTrayItem(size_t ime_count); + // Mandates behavior for the single IME case for the detailed IME list + // sub-view. + ImeListView::SingleImeBehavior GetSingleImeBehavior(); + + TrayItemView* tray_label_; + tray::IMEDefaultView* default_; + tray::IMEDetailedView* detailed_; + // Whether the virtual keyboard is suppressed. + bool keyboard_suppressed_; + // Cached IME info. + IMEInfoList ime_list_; + IMEInfo current_ime_; + IMEPropertyInfoList property_list_; + // If non-empty, a controlled-setting icon should be displayed with a tooltip + // text defined by this string. + base::string16 ime_managed_message_; + + // Whether the IME label and tray items should be visible. + bool is_visible_; + + DISALLOW_COPY_AND_ASSIGN(TrayIME); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_IME_TRAY_IME_CHROMEOS_H_
diff --git a/ash/common/system/ime/tray_ime_chromeos_unittest.cc b/ash/common/system/ime/tray_ime_chromeos_unittest.cc new file mode 100644 index 0000000..fb6e8bc0 --- /dev/null +++ b/ash/common/system/ime/tray_ime_chromeos_unittest.cc
@@ -0,0 +1,204 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/ime/tray_ime_chromeos.h" + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/accessibility_types.h" +#include "ash/common/system/chromeos/ime_menu/ime_list_view.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/events/devices/device_data_manager.h" +#include "ui/keyboard/keyboard_util.h" + +namespace ash { + +class TrayIMETest : public test::AshTestBase { + public: + TrayIMETest() {} + ~TrayIMETest() override {} + + views::View* default_view() const { return default_view_.get(); } + + views::View* detailed_view() const { return detailed_view_.get(); } + + // Mocks enabling the a11y virtual keyboard since the actual a11y manager + // is not created in ash tests. + void SetAccessibilityKeyboardEnabled(bool enabled); + + // Sets the current number of active IMEs. + void SetIMELength(int length); + + // Returns the view responsible for toggling virtual keyboard. + views::View* GetToggleView() const; + + // Sets the managed IMEs tooltip message (and thus also if IMEs are managed = + // non-empty or not = empty) + void SetManagedMessage(base::string16 managed_message); + + void SuppressKeyboard(); + void RestoreKeyboard(); + + // test::AshTestBase: + void SetUp() override; + void TearDown() override; + + private: + std::unique_ptr<TrayIME> tray_; + std::unique_ptr<views::View> default_view_; + std::unique_ptr<views::View> detailed_view_; + + bool keyboard_suppressed_ = false; + std::vector<ui::TouchscreenDevice> touchscreen_devices_to_restore_; + std::vector<ui::InputDevice> keyboard_devices_to_restore_; + + DISALLOW_COPY_AND_ASSIGN(TrayIMETest); +}; + +void TrayIMETest::SetAccessibilityKeyboardEnabled(bool enabled) { + WmShell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(enabled); + keyboard::SetAccessibilityKeyboardEnabled(enabled); + AccessibilityNotificationVisibility notification = + enabled ? A11Y_NOTIFICATION_SHOW : A11Y_NOTIFICATION_NONE; + WmShell::Get()->system_tray_notifier()->NotifyAccessibilityModeChanged( + notification); +} + +void TrayIMETest::SetIMELength(int length) { + tray_->ime_list_.clear(); + IMEInfo ime; + for (int i = 0; i < length; i++) { + tray_->ime_list_.push_back(ime); + } + tray_->Update(); +} + +views::View* TrayIMETest::GetToggleView() const { + ImeListViewTestApi test_api(static_cast<ImeListView*>(detailed_view())); + return test_api.GetToggleView(); +} + +void TrayIMETest::SetManagedMessage(base::string16 managed_message) { + tray_->ime_managed_message_ = managed_message; + tray_->Update(); +} + +void TrayIMETest::SuppressKeyboard() { + DCHECK(!keyboard_suppressed_); + keyboard_suppressed_ = true; + + ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); + touchscreen_devices_to_restore_ = device_manager->GetTouchscreenDevices(); + keyboard_devices_to_restore_ = device_manager->GetKeyboardDevices(); + + ui::DeviceHotplugEventObserver* manager = + ui::DeviceDataManager::GetInstance(); + std::vector<ui::TouchscreenDevice> screens; + screens.push_back( + ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, + "Touchscreen", gfx::Size(1024, 768), 0)); + manager->OnTouchscreenDevicesUpdated(screens); + + std::vector<ui::InputDevice> keyboards; + keyboards.push_back(ui::InputDevice( + 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); + manager->OnKeyboardDevicesUpdated(keyboards); +} + +void TrayIMETest::RestoreKeyboard() { + DCHECK(keyboard_suppressed_); + ui::DeviceHotplugEventObserver* manager = + ui::DeviceDataManager::GetInstance(); + manager->OnTouchscreenDevicesUpdated(touchscreen_devices_to_restore_); + manager->OnKeyboardDevicesUpdated(keyboard_devices_to_restore_); +} + +void TrayIMETest::SetUp() { + test::AshTestBase::SetUp(); + tray_.reset(new TrayIME(GetPrimarySystemTray())); + default_view_.reset(tray_->CreateDefaultView(LoginStatus::USER)); + detailed_view_.reset(tray_->CreateDetailedView(LoginStatus::USER)); +} + +void TrayIMETest::TearDown() { + if (keyboard_suppressed_) + RestoreKeyboard(); + SetAccessibilityKeyboardEnabled(false); + tray_.reset(); + default_view_.reset(); + detailed_view_.reset(); + test::AshTestBase::TearDown(); +} + +// Tests that if the keyboard is not suppressed the default view is hidden +// if less than 2 IMEs are present. +TEST_F(TrayIMETest, HiddenWithNoIMEs) { + SetIMELength(0); + EXPECT_FALSE(default_view()->visible()); + SetIMELength(1); + EXPECT_FALSE(default_view()->visible()); + SetIMELength(2); + EXPECT_TRUE(default_view()->visible()); +} + +// Tests that if IMEs are managed, the default view is displayed even for a +// single IME. +TEST_F(TrayIMETest, ShownWithSingleIMEWhenManaged) { + SetManagedMessage(base::ASCIIToUTF16("managed")); + SetIMELength(0); + EXPECT_FALSE(default_view()->visible()); + SetIMELength(1); + EXPECT_TRUE(default_view()->visible()); + SetIMELength(2); + EXPECT_TRUE(default_view()->visible()); +} + +// Tests that if no IMEs are present the default view is hidden when a11y is +// enabled. +TEST_F(TrayIMETest, HidesOnA11yEnabled) { + // TODO: investigate failure in mash. http://crbug.com/695561. + if (WmShell::Get()->IsRunningInMash()) + return; + + SetIMELength(0); + SuppressKeyboard(); + EXPECT_TRUE(default_view()->visible()); + // Enable a11y keyboard. + SetAccessibilityKeyboardEnabled(true); + EXPECT_FALSE(default_view()->visible()); + // Disable the a11y keyboard. + SetAccessibilityKeyboardEnabled(false); + EXPECT_TRUE(default_view()->visible()); +} + +// Tests that clicking on the keyboard toggle causes the virtual keyboard +// to toggle between enabled and disabled. +TEST_F(TrayIMETest, PerformActionOnDetailedView) { + // TODO: investigate failure in mash. http://crbug.com/695561. + if (WmShell::Get()->IsRunningInMash()) + return; + + SetIMELength(0); + SuppressKeyboard(); + EXPECT_FALSE(keyboard::IsKeyboardEnabled()); + views::View* toggle = GetToggleView(); + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + // Enable the keyboard. + toggle->OnGestureEvent(&tap); + EXPECT_TRUE(keyboard::IsKeyboardEnabled()); + EXPECT_TRUE(default_view()->visible()); + + // Clicking again should disable the keyboard. + toggle = GetToggleView(); + tap = ui::GestureEvent(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + toggle->OnGestureEvent(&tap); + EXPECT_FALSE(keyboard::IsKeyboardEnabled()); + EXPECT_TRUE(default_view()->visible()); +} + +} // namespace ash
diff --git a/ash/common/system/keyboard_brightness_control_delegate.h b/ash/common/system/keyboard_brightness_control_delegate.h new file mode 100644 index 0000000..98c00676 --- /dev/null +++ b/ash/common/system/keyboard_brightness_control_delegate.h
@@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROL_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROL_DELEGATE_H_ + +namespace ui { +class Accelerator; +} // namespace ui + +namespace ash { + +// Delegate for controlling the keyboard brightness. +class KeyboardBrightnessControlDelegate { + public: + virtual ~KeyboardBrightnessControlDelegate() {} + + // Handles an accelerator-driven request to decrease or increase the keyboard + // brightness. + virtual void HandleKeyboardBrightnessDown( + const ui::Accelerator& accelerator) = 0; + virtual void HandleKeyboardBrightnessUp( + const ui::Accelerator& accelerator) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROL_DELEGATE_H_
diff --git a/ash/common/system/locale/locale_notification_controller.cc b/ash/common/system/locale/locale_notification_controller.cc new file mode 100644 index 0000000..2db2f89a --- /dev/null +++ b/ash/common/system/locale/locale_notification_controller.cc
@@ -0,0 +1,132 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/locale/locale_notification_controller.h" + +#include <memory> +#include <utility> + +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/string16.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" +#include "ui/message_center/notification_types.h" + +using message_center::Notification; + +namespace ash { +namespace { + +const char kLocaleChangeNotificationId[] = "chrome://settings/locale"; + +class LocaleNotificationDelegate : public message_center::NotificationDelegate { + public: + explicit LocaleNotificationDelegate( + const base::Callback<void(ash::mojom::LocaleNotificationResult)>& + callback); + + protected: + ~LocaleNotificationDelegate() override; + + // message_center::NotificationDelegate overrides: + void Close(bool by_user) override; + bool HasClickedListener() override; + void Click() override; + void ButtonClick(int button_index) override; + + private: + base::Callback<void(ash::mojom::LocaleNotificationResult)> callback_; + + DISALLOW_COPY_AND_ASSIGN(LocaleNotificationDelegate); +}; + +LocaleNotificationDelegate::LocaleNotificationDelegate( + const base::Callback<void(ash::mojom::LocaleNotificationResult)>& callback) + : callback_(callback) {} + +LocaleNotificationDelegate::~LocaleNotificationDelegate() { + if (callback_) { + // We're being destroyed but the user didn't click on anything. Run the + // callback so that we don't crash. + callback_.Run(ash::mojom::LocaleNotificationResult::ACCEPT); + } +} + +void LocaleNotificationDelegate::Close(bool by_user) { + if (callback_) { + callback_.Run(ash::mojom::LocaleNotificationResult::ACCEPT); + callback_.Reset(); + } +} + +bool LocaleNotificationDelegate::HasClickedListener() { + return true; +} + +void LocaleNotificationDelegate::Click() { + if (callback_) { + callback_.Run(ash::mojom::LocaleNotificationResult::ACCEPT); + callback_.Reset(); + } +} + +void LocaleNotificationDelegate::ButtonClick(int button_index) { + DCHECK_EQ(0, button_index); + + if (callback_) { + callback_.Run(ash::mojom::LocaleNotificationResult::REVERT); + callback_.Reset(); + } +} + +} // namespace + +LocaleNotificationController::LocaleNotificationController() {} + +LocaleNotificationController::~LocaleNotificationController() {} + +void LocaleNotificationController::BindRequest( + mojom::LocaleNotificationControllerRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void LocaleNotificationController::OnLocaleChanged( + const std::string& cur_locale, + const std::string& from_locale, + const std::string& to_locale, + const OnLocaleChangedCallback& callback) { + base::string16 from = + l10n_util::GetDisplayNameForLocale(from_locale, cur_locale, true); + base::string16 to = + l10n_util::GetDisplayNameForLocale(to_locale, cur_locale, true); + + message_center::RichNotificationData optional; + optional.buttons.push_back( + message_center::ButtonInfo(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_LOCALE_REVERT_MESSAGE, from))); + optional.never_timeout = true; + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kLocaleChangeNotificationId, + base::string16() /* title */, + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_MESSAGE, + from, to), + bundle.GetImageNamed(IDR_AURA_UBER_TRAY_LOCALE), + base::string16() /* display_source */, GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierLocale), + optional, new LocaleNotificationDelegate(callback))); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +} // namespace ash
diff --git a/ash/common/system/locale/locale_notification_controller.h b/ash/common/system/locale/locale_notification_controller.h new file mode 100644 index 0000000..b97c7ed --- /dev/null +++ b/ash/common/system/locale/locale_notification_controller.h
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_LOCALE_LOCALE_NOTIFICATION_CONTROLLER_H_ +#define ASH_COMMON_SYSTEM_LOCALE_LOCALE_NOTIFICATION_CONTROLLER_H_ + +#include <string> + +#include "ash/public/interfaces/locale.mojom.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding_set.h" + +namespace ash { + +// Observes the locale change and creates rich notification for the change. +class LocaleNotificationController + : public mojom::LocaleNotificationController { + public: + LocaleNotificationController(); + ~LocaleNotificationController() override; + + // Binds the mojom::LocaleNotificationController interface request to this + // object. + void BindRequest(mojom::LocaleNotificationControllerRequest request); + + private: + // Overridden from mojom::LocaleNotificationController: + void OnLocaleChanged(const std::string& cur_locale, + const std::string& from_locale, + const std::string& to_locale, + const OnLocaleChangedCallback& callback) override; + + std::string cur_locale_; + std::string from_locale_; + std::string to_locale_; + + // Bindings for the LocaleNotificationController interface. + mojo::BindingSet<mojom::LocaleNotificationController> bindings_; + + DISALLOW_COPY_AND_ASSIGN(LocaleNotificationController); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_LOCALE_LOCALE_NOTIFICATION_CONTROLLER_H_
diff --git a/ash/common/system/networking_config_delegate.cc b/ash/common/system/networking_config_delegate.cc new file mode 100644 index 0000000..f8235f0a --- /dev/null +++ b/ash/common/system/networking_config_delegate.cc
@@ -0,0 +1,15 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/networking_config_delegate.h" + +namespace ash { + +NetworkingConfigDelegate::ExtensionInfo::ExtensionInfo(const std::string& id, + const std::string& name) + : extension_id(id), extension_name(name) {} + +NetworkingConfigDelegate::ExtensionInfo::~ExtensionInfo() {} + +} // namespace ash
diff --git a/ash/common/system/networking_config_delegate.h b/ash/common/system/networking_config_delegate.h new file mode 100644 index 0000000..e701bf66 --- /dev/null +++ b/ash/common/system/networking_config_delegate.h
@@ -0,0 +1,47 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_ + +#include <memory> +#include <string> + +#include "ash/ash_export.h" +#include "base/macros.h" + +namespace ash { + +// This delegate allows the UI code in ash, e.g. |NetworkStateListDetailedView|, +// to access the |NetworkingConfigService| in order to determine whether the +// configuration of a network identified by its |guid| is controlled by +// an extension. +// TODO(crbug.com/651157): Eliminate this delegate. Information about extension +// controlled networks should be provided by a mojo service that caches data at +// the NetworkState level. +class NetworkingConfigDelegate { + public: + // A struct that provides information about the extension controlling the + // configuration of a network. + struct ASH_EXPORT ExtensionInfo { + ExtensionInfo(const std::string& id, const std::string& name); + ~ExtensionInfo(); + std::string extension_id; + std::string extension_name; + }; + + virtual ~NetworkingConfigDelegate() {} + + // Returns information about the extension registered to control configuration + // of the network |guid|. Returns null if no extension is registered. + virtual std::unique_ptr<const ExtensionInfo> LookUpExtensionForNetwork( + const std::string& guid) = 0; + + private: + DISALLOW_ASSIGN(NetworkingConfigDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_
diff --git a/ash/common/system/overview/overview_button_tray.cc b/ash/common/system/overview/overview_button_tray.cc new file mode 100644 index 0000000..c28d814d --- /dev/null +++ b/ash/common/system/overview/overview_button_tray.cc
@@ -0,0 +1,128 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/overview/overview_button_tray.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" + +namespace ash { + +OverviewButtonTray::OverviewButtonTray(WmShelf* wm_shelf) + : TrayBackgroundView(wm_shelf), icon_(new views::ImageView()) { + SetInkDropMode(InkDropMode::ON); + SetContentsBackground(false); + + icon_->SetImage(CreateVectorIcon(kShelfOverviewIcon, kShelfIconColor)); + SetIconBorderForShelfAlignment(); + tray_container()->AddChildView(icon_); + + // Since OverviewButtonTray is located on the rightmost position of a + // horizontal shelf, no separator is required. + set_separator_visibility(false); + + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->GetSessionStateDelegate()->AddSessionStateObserver(this); +} + +OverviewButtonTray::~OverviewButtonTray() { + WmShell::Get()->RemoveShellObserver(this); + WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); +} + +void OverviewButtonTray::UpdateAfterLoginStatusChange(LoginStatus status) { + UpdateIconVisibility(); +} + +bool OverviewButtonTray::PerformAction(const ui::Event& event) { + WindowSelectorController* controller = + WmShell::Get()->window_selector_controller(); + // Toggling overview mode will fail if there is no window to show. + bool performed = controller->ToggleOverview(); + WmShell::Get()->RecordUserMetricsAction(UMA_TRAY_OVERVIEW); + return performed; +} + +void OverviewButtonTray::SessionStateChanged( + session_manager::SessionState state) { + UpdateIconVisibility(); +} + +void OverviewButtonTray::OnMaximizeModeStarted() { + UpdateIconVisibility(); +} + +void OverviewButtonTray::OnMaximizeModeEnded() { + UpdateIconVisibility(); +} + +void OverviewButtonTray::OnOverviewModeStarting() { + SetIsActive(true); +} + +void OverviewButtonTray::OnOverviewModeEnded() { + SetIsActive(false); +} + +void OverviewButtonTray::ClickedOutsideBubble() {} + +base::string16 OverviewButtonTray::GetAccessibleNameForTray() { + return l10n_util::GetStringUTF16(IDS_ASH_OVERVIEW_BUTTON_ACCESSIBLE_NAME); +} + +void OverviewButtonTray::HideBubbleWithView( + const views::TrayBubbleView* bubble_view) { + // This class has no bubbles to hide. +} + +void OverviewButtonTray::SetShelfAlignment(ShelfAlignment alignment) { + if (alignment == shelf_alignment()) + return; + + TrayBackgroundView::SetShelfAlignment(alignment); + SetIconBorderForShelfAlignment(); +} + +void OverviewButtonTray::SetIconBorderForShelfAlignment() { + // Pad button size to align with other controls in the system tray. + const gfx::ImageSkia& image = icon_->GetImage(); + const int vertical_padding = (kTrayItemSize - image.height()) / 2; + const int horizontal_padding = (kTrayItemSize - image.width()) / 2; + icon_->SetBorder(views::CreateEmptyBorder( + gfx::Insets(vertical_padding, horizontal_padding))); +} + +void OverviewButtonTray::UpdateIconVisibility() { + // The visibility of the OverviewButtonTray has diverged from + // WindowSelectorController::CanSelect. The visibility of the button should + // not change during transient times in which CanSelect is false. Such as when + // a modal dialog is present. + WmShell* shell = WmShell::Get(); + SessionStateDelegate* session_state_delegate = + shell->GetSessionStateDelegate(); + + SetVisible( + shell->maximize_mode_controller()->IsMaximizeModeWindowManagerEnabled() && + session_state_delegate->IsActiveUserSessionStarted() && + !session_state_delegate->IsScreenLocked() && + session_state_delegate->GetSessionState() == + session_manager::SessionState::ACTIVE && + shell->system_tray_delegate()->GetUserLoginStatus() != + LoginStatus::KIOSK_APP && + shell->system_tray_delegate()->GetUserLoginStatus() != + LoginStatus::ARC_KIOSK_APP); +} + +} // namespace ash
diff --git a/ash/common/system/overview/overview_button_tray.h b/ash/common/system/overview/overview_button_tray.h new file mode 100644 index 0000000..c0f71dc --- /dev/null +++ b/ash/common/system/overview/overview_button_tray.h
@@ -0,0 +1,73 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_ +#define ASH_COMMON_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_ + +#include "ash/ash_export.h" +#include "ash/common/session/session_state_observer.h" +#include "ash/common/shell_observer.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "base/macros.h" + +namespace views { +class ImageView; +} + +namespace ash { + +// Status area tray for showing a toggle for Overview Mode. Overview Mode +// is equivalent to WindowSelectorController being in selection mode. +// This hosts a ShellObserver that listens for the activation of Maximize Mode +// This tray will only be visible while in this state. This tray does not +// provide any bubble view windows. +class ASH_EXPORT OverviewButtonTray : public TrayBackgroundView, + public SessionStateObserver, + public ShellObserver { + public: + explicit OverviewButtonTray(WmShelf* wm_shelf); + ~OverviewButtonTray() override; + + // Updates the tray's visibility based on the LoginStatus and the current + // state of MaximizeMode + virtual void UpdateAfterLoginStatusChange(LoginStatus status); + + // ActionableView: + bool PerformAction(const ui::Event& event) override; + + // SessionStateObserver: + void SessionStateChanged(session_manager::SessionState state) override; + + // ShellObserver: + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + void OnOverviewModeStarting() override; + void OnOverviewModeEnded() override; + + // TrayBackgroundView: + void ClickedOutsideBubble() override; + base::string16 GetAccessibleNameForTray() override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void SetShelfAlignment(ShelfAlignment alignment) override; + + private: + friend class OverviewButtonTrayTest; + + // Creates a new border for the icon. The padding is determined based on the + // alignment of the shelf. + void SetIconBorderForShelfAlignment(); + + // Sets the icon to visible if maximize mode is enabled and + // WindowSelectorController::CanSelect. + void UpdateIconVisibility(); + + // Weak pointer, will be parented by TrayContainer for its lifetime. + views::ImageView* icon_; + + DISALLOW_COPY_AND_ASSIGN(OverviewButtonTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_
diff --git a/ash/common/system/status_area_layout_manager.cc b/ash/common/system/status_area_layout_manager.cc new file mode 100644 index 0000000..ea622b22 --- /dev/null +++ b/ash/common/system/status_area_layout_manager.cc
@@ -0,0 +1,63 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/status_area_layout_manager.h" + +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/wm_window.h" +#include "base/auto_reset.h" + +namespace ash { + +//////////////////////////////////////////////////////////////////////////////// +// StatusAreaLayoutManager, public: + +StatusAreaLayoutManager::StatusAreaLayoutManager(ShelfWidget* shelf_widget) + : in_layout_(false), shelf_widget_(shelf_widget) {} + +StatusAreaLayoutManager::~StatusAreaLayoutManager() {} + +//////////////////////////////////////////////////////////////////////////////// +// StatusAreaLayoutManager, aura::LayoutManager implementation: + +void StatusAreaLayoutManager::OnWindowResized() { + LayoutStatusArea(); +} + +void StatusAreaLayoutManager::SetChildBounds( + WmWindow* child, + const gfx::Rect& requested_bounds) { + // Only need to have the shelf do a layout if the child changing is the status + // area and the shelf isn't in the process of doing a layout. + if (child != WmWindow::Get( + shelf_widget_->status_area_widget()->GetNativeWindow()) || + in_layout_) { + wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); + return; + } + + // If the bounds match, no need to do anything. Check for target bounds to + // ensure any active animation is retargeted. + if (requested_bounds == child->GetTargetBounds()) + return; + + wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); + LayoutStatusArea(); +} + +//////////////////////////////////////////////////////////////////////////////// +// StatusAreaLayoutManager, private: + +void StatusAreaLayoutManager::LayoutStatusArea() { + // Shelf layout manager may be already doing layout. + if (shelf_widget_->shelf_layout_manager()->updating_bounds()) + return; + + base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); + shelf_widget_->shelf_layout_manager()->LayoutShelf(); +} + +} // namespace ash
diff --git a/ash/common/system/status_area_layout_manager.h b/ash/common/system/status_area_layout_manager.h new file mode 100644 index 0000000..c4e70581 --- /dev/null +++ b/ash/common/system/status_area_layout_manager.h
@@ -0,0 +1,44 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_STATUS_AREA_LAYOUT_MANAGER_H_ +#define ASH_COMMON_SYSTEM_STATUS_AREA_LAYOUT_MANAGER_H_ + +#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h" +#include "base/macros.h" + +namespace ash { + +class ShelfWidget; + +// StatusAreaLayoutManager is a layout manager responsible for the status area. +// In any case when status area needs relayout it redirects this call to +// ShelfLayoutManager. +class StatusAreaLayoutManager : public wm::WmSnapToPixelLayoutManager { + public: + explicit StatusAreaLayoutManager(ShelfWidget* shelf_widget); + ~StatusAreaLayoutManager() override; + + // Overridden from wm::WmSnapToPixelLayoutManager: + void OnWindowResized() override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + private: + // Updates layout of the status area. Effectively calls ShelfLayoutManager + // to update layout of the shelf. + void LayoutStatusArea(); + + // True when inside LayoutStatusArea method. + // Used to prevent calling itself again from SetChildBounds(). + bool in_layout_; + + ShelfWidget* shelf_widget_; + + DISALLOW_COPY_AND_ASSIGN(StatusAreaLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_STATUS_AREA_LAYOUT_MANAGER_H_
diff --git a/ash/common/system/status_area_widget.cc b/ash/common/system/status_area_widget.cc new file mode 100644 index 0000000..3c66000c --- /dev/null +++ b/ash/common/system/status_area_widget.cc
@@ -0,0 +1,234 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/status_area_widget.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/chromeos/ime_menu/ime_menu_tray.h" +#include "ash/common/system/chromeos/palette/palette_tray.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" +#include "ash/common/system/chromeos/session/logout_button_tray.h" +#include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.h" +#include "ash/common/system/overview/overview_button_tray.h" +#include "ash/common/system/status_area_widget_delegate.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/web_notification/web_notification_tray.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/i18n/time_formatting.h" +#include "ui/display/display.h" +#include "ui/native_theme/native_theme_dark_aura.h" + +namespace ash { + +StatusAreaWidget::StatusAreaWidget(WmWindow* status_container, + WmShelf* wm_shelf) + : status_area_widget_delegate_(new StatusAreaWidgetDelegate), + overview_button_tray_(nullptr), + system_tray_(nullptr), + web_notification_tray_(nullptr), + logout_button_tray_(nullptr), + palette_tray_(nullptr), + virtual_keyboard_tray_(nullptr), + ime_menu_tray_(nullptr), + login_status_(LoginStatus::NOT_LOGGED_IN), + wm_shelf_(wm_shelf) { + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.delegate = status_area_widget_delegate_; + params.name = "StatusAreaWidget"; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + status_container->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + this, status_container->GetShellWindowId(), ¶ms); + Init(params); + set_focus_on_creation(false); + SetContentsView(status_area_widget_delegate_); +} + +StatusAreaWidget::~StatusAreaWidget() {} + +void StatusAreaWidget::CreateTrayViews() { + AddOverviewButtonTray(); + AddSystemTray(); + AddWebNotificationTray(); + AddPaletteTray(); + AddVirtualKeyboardTray(); + AddImeMenuTray(); + AddLogoutButtonTray(); + + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + DCHECK(delegate); + // Initialize after all trays have been created. + system_tray_->InitializeTrayItems(delegate, web_notification_tray_); + web_notification_tray_->Initialize(); + logout_button_tray_->Initialize(); + if (palette_tray_) + palette_tray_->Initialize(); + virtual_keyboard_tray_->Initialize(); + ime_menu_tray_->Initialize(); + overview_button_tray_->Initialize(); + SetShelfAlignment(system_tray_->shelf_alignment()); + UpdateAfterLoginStatusChange(delegate->GetUserLoginStatus()); +} + +void StatusAreaWidget::Shutdown() { + system_tray_->Shutdown(); + // Destroy the trays early, causing them to be removed from the view + // hierarchy. Do not used scoped pointers since we don't want to destroy them + // in the destructor if Shutdown() is not called (e.g. in tests). + delete web_notification_tray_; + web_notification_tray_ = nullptr; + // Must be destroyed after |web_notification_tray_|. + delete system_tray_; + system_tray_ = nullptr; + delete ime_menu_tray_; + ime_menu_tray_ = nullptr; + delete virtual_keyboard_tray_; + virtual_keyboard_tray_ = nullptr; + delete logout_button_tray_; + logout_button_tray_ = nullptr; + delete overview_button_tray_; + overview_button_tray_ = nullptr; +} + +void StatusAreaWidget::SetShelfAlignment(ShelfAlignment alignment) { + status_area_widget_delegate_->set_alignment(alignment); + if (system_tray_) + system_tray_->SetShelfAlignment(alignment); + if (web_notification_tray_) + web_notification_tray_->SetShelfAlignment(alignment); + if (logout_button_tray_) + logout_button_tray_->SetShelfAlignment(alignment); + if (virtual_keyboard_tray_) + virtual_keyboard_tray_->SetShelfAlignment(alignment); + if (ime_menu_tray_) + ime_menu_tray_->SetShelfAlignment(alignment); + if (palette_tray_) + palette_tray_->SetShelfAlignment(alignment); + if (overview_button_tray_) + overview_button_tray_->SetShelfAlignment(alignment); + status_area_widget_delegate_->UpdateLayout(); +} + +void StatusAreaWidget::UpdateAfterLoginStatusChange(LoginStatus login_status) { + if (login_status_ == login_status) + return; + login_status_ = login_status; + if (system_tray_) + system_tray_->UpdateAfterLoginStatusChange(login_status); + if (web_notification_tray_) + web_notification_tray_->UpdateAfterLoginStatusChange(login_status); + if (logout_button_tray_) + logout_button_tray_->UpdateAfterLoginStatusChange(login_status); + if (overview_button_tray_) + overview_button_tray_->UpdateAfterLoginStatusChange(login_status); +} + +bool StatusAreaWidget::ShouldShowShelf() const { + if ((system_tray_ && system_tray_->ShouldShowShelf()) || + (web_notification_tray_ && + web_notification_tray_->ShouldBlockShelfAutoHide())) + return true; + + if (palette_tray_ && palette_tray_->ShouldBlockShelfAutoHide()) + return true; + + if (ime_menu_tray_ && ime_menu_tray_->ShouldBlockShelfAutoHide()) + return true; + + return false; +} + +bool StatusAreaWidget::IsMessageBubbleShown() const { + return ((system_tray_ && system_tray_->IsSystemBubbleVisible()) || + (web_notification_tray_ && + web_notification_tray_->IsMessageCenterBubbleVisible())); +} + +void StatusAreaWidget::SchedulePaint() { + status_area_widget_delegate_->SchedulePaint(); + web_notification_tray_->SchedulePaint(); + system_tray_->SchedulePaint(); + virtual_keyboard_tray_->SchedulePaint(); + logout_button_tray_->SchedulePaint(); + ime_menu_tray_->SchedulePaint(); + if (palette_tray_) + palette_tray_->SchedulePaint(); + overview_button_tray_->SchedulePaint(); +} + +const ui::NativeTheme* StatusAreaWidget::GetNativeTheme() const { + return MaterialDesignController::IsShelfMaterial() + ? ui::NativeThemeDarkAura::instance() + : Widget::GetNativeTheme(); +} + +void StatusAreaWidget::OnNativeWidgetActivationChanged(bool active) { + Widget::OnNativeWidgetActivationChanged(active); + if (active) + status_area_widget_delegate_->SetPaneFocusAndFocusDefault(); +} + +void StatusAreaWidget::UpdateShelfItemBackground(SkColor color) { + web_notification_tray_->UpdateShelfItemBackground(color); + system_tray_->UpdateShelfItemBackground(color); + virtual_keyboard_tray_->UpdateShelfItemBackground(color); + logout_button_tray_->UpdateShelfItemBackground(color); + ime_menu_tray_->UpdateShelfItemBackground(color); + if (palette_tray_) + palette_tray_->UpdateShelfItemBackground(color); + overview_button_tray_->UpdateShelfItemBackground(color); +} + +void StatusAreaWidget::AddSystemTray() { + system_tray_ = new SystemTray(wm_shelf_); + status_area_widget_delegate_->AddTray(system_tray_); +} + +void StatusAreaWidget::AddWebNotificationTray() { + DCHECK(system_tray_); + web_notification_tray_ = new WebNotificationTray( + wm_shelf_, WmWindow::Get(this->GetNativeWindow()), system_tray_); + status_area_widget_delegate_->AddTray(web_notification_tray_); +} + +void StatusAreaWidget::AddLogoutButtonTray() { + logout_button_tray_ = new LogoutButtonTray(wm_shelf_); + status_area_widget_delegate_->AddTray(logout_button_tray_); +} + +void StatusAreaWidget::AddPaletteTray() { + const display::Display& display = + WmWindow::Get(this->GetNativeWindow())->GetDisplayNearestWindow(); + + // Create the palette only on the internal display, where the stylus is + // available. We also create a palette on every display if requested from the + // command line. + if (display.IsInternal() || palette_utils::IsPaletteEnabledOnEveryDisplay()) { + palette_tray_ = new PaletteTray(wm_shelf_); + status_area_widget_delegate_->AddTray(palette_tray_); + } +} + +void StatusAreaWidget::AddVirtualKeyboardTray() { + virtual_keyboard_tray_ = new VirtualKeyboardTray(wm_shelf_); + status_area_widget_delegate_->AddTray(virtual_keyboard_tray_); +} + +void StatusAreaWidget::AddImeMenuTray() { + ime_menu_tray_ = new ImeMenuTray(wm_shelf_); + status_area_widget_delegate_->AddTray(ime_menu_tray_); +} + +void StatusAreaWidget::AddOverviewButtonTray() { + overview_button_tray_ = new OverviewButtonTray(wm_shelf_); + status_area_widget_delegate_->AddTray(overview_button_tray_); +} + +} // namespace ash
diff --git a/ash/common/system/status_area_widget.h b/ash/common/system/status_area_widget.h new file mode 100644 index 0000000..acea237 --- /dev/null +++ b/ash/common/system/status_area_widget.h
@@ -0,0 +1,111 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_STATUS_AREA_WIDGET_H_ +#define ASH_COMMON_SYSTEM_STATUS_AREA_WIDGET_H_ + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "ui/views/widget/widget.h" + +namespace ash { +class ImeMenuTray; +class LogoutButtonTray; +class OverviewButtonTray; +class PaletteTray; +class StatusAreaWidgetDelegate; +class SystemTray; +class VirtualKeyboardTray; +class WebNotificationTray; +class WmShelf; +class WmWindow; + +class ASH_EXPORT StatusAreaWidget : public views::Widget, + public ShelfBackgroundAnimatorObserver { + public: + StatusAreaWidget(WmWindow* status_container, WmShelf* wm_shelf); + ~StatusAreaWidget() override; + + // Creates the SystemTray, WebNotificationTray and LogoutButtonTray. + void CreateTrayViews(); + + // Destroys the system tray and web notification tray. Called before + // tearing down the windows to avoid shutdown ordering issues. + void Shutdown(); + + // Update the alignment of the widget and tray views. + void SetShelfAlignment(ShelfAlignment alignment); + + // Called by the client when the login status changes. Caches login_status + // and calls UpdateAfterLoginStatusChange for the system tray and the web + // notification tray. + void UpdateAfterLoginStatusChange(LoginStatus login_status); + + StatusAreaWidgetDelegate* status_area_widget_delegate() { + return status_area_widget_delegate_; + } + SystemTray* system_tray() { return system_tray_; } + WebNotificationTray* web_notification_tray() { + return web_notification_tray_; + } + OverviewButtonTray* overview_button_tray() { return overview_button_tray_; } + + PaletteTray* palette_tray() { return palette_tray_; } + + ImeMenuTray* ime_menu_tray() { return ime_menu_tray_; } + + WmShelf* wm_shelf() { return wm_shelf_; } + + LoginStatus login_status() const { return login_status_; } + + // Returns true if the shelf should be visible. This is used when the + // shelf is configured to auto-hide and test if the shelf should force + // the shelf to remain visible. + bool ShouldShowShelf() const; + + // True if any message bubble is shown. + bool IsMessageBubbleShown() const; + + // Notifies child trays, and the |status_area_widget_delegate_| to schedule a + // paint. + void SchedulePaint(); + + // Overridden from views::Widget: + const ui::NativeTheme* GetNativeTheme() const override; + void OnNativeWidgetActivationChanged(bool active) override; + + // ShelfBackgroundAnimatorObserver: + void UpdateShelfItemBackground(SkColor color) override; + + private: + void AddSystemTray(); + void AddWebNotificationTray(); + void AddLogoutButtonTray(); + void AddPaletteTray(); + void AddVirtualKeyboardTray(); + void AddImeMenuTray(); + void AddOverviewButtonTray(); + + // Weak pointers to View classes that are parented to StatusAreaWidget: + StatusAreaWidgetDelegate* status_area_widget_delegate_; + OverviewButtonTray* overview_button_tray_; + SystemTray* system_tray_; + WebNotificationTray* web_notification_tray_; + LogoutButtonTray* logout_button_tray_; + PaletteTray* palette_tray_; + VirtualKeyboardTray* virtual_keyboard_tray_; + ImeMenuTray* ime_menu_tray_; + LoginStatus login_status_; + + WmShelf* wm_shelf_; + + DISALLOW_COPY_AND_ASSIGN(StatusAreaWidget); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_STATUS_AREA_WIDGET_H_
diff --git a/ash/common/system/status_area_widget_delegate.cc b/ash/common/system/status_area_widget_delegate.cc new file mode 100644 index 0000000..57354918 --- /dev/null +++ b/ash/common/system/status_area_widget_delegate.cc
@@ -0,0 +1,199 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/status_area_widget_delegate.h" + +#include "ash/common/focus_cycler.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/animation/tween.h" +#include "ui/views/accessible_pane_view.h" +#include "ui/views/border.h" +#include "ui/views/layout/grid_layout.h" + +namespace { + +constexpr int kAnimationDurationMs = 250; + +constexpr int kPaddingFromEdgeOfShelf = 3; + +class StatusAreaWidgetDelegateAnimationSettings + : public ui::ScopedLayerAnimationSettings { + public: + explicit StatusAreaWidgetDelegateAnimationSettings(ui::Layer* layer) + : ui::ScopedLayerAnimationSettings(layer->GetAnimator()) { + SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); + SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + SetTweenType(gfx::Tween::EASE_IN_OUT); + } + + ~StatusAreaWidgetDelegateAnimationSettings() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(StatusAreaWidgetDelegateAnimationSettings); +}; + +} // namespace + +namespace ash { + +StatusAreaWidgetDelegate::StatusAreaWidgetDelegate() + : focus_cycler_for_testing_(nullptr), alignment_(SHELF_ALIGNMENT_BOTTOM) { + // Allow the launcher to surrender the focus to another window upon + // navigation completion by the user. + set_allow_deactivate_on_esc(true); + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); +} + +StatusAreaWidgetDelegate::~StatusAreaWidgetDelegate() {} + +void StatusAreaWidgetDelegate::SetFocusCyclerForTesting( + const FocusCycler* focus_cycler) { + focus_cycler_for_testing_ = focus_cycler; +} + +views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() { + return child_at(0); +} + +views::Widget* StatusAreaWidgetDelegate::GetWidget() { + return View::GetWidget(); +} + +const views::Widget* StatusAreaWidgetDelegate::GetWidget() const { + return View::GetWidget(); +} + +void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) { + views::Widget* target_widget = + static_cast<views::View*>(event->target())->GetWidget(); + WmWindow* target_window = WmWindow::Get(target_widget->GetNativeWindow()); + WmShelf* shelf = target_window->GetRootWindowController()->GetShelf(); + if (shelf->ProcessGestureEvent(*event)) + event->StopPropagation(); + else + views::AccessiblePaneView::OnGestureEvent(event); +} + +bool StatusAreaWidgetDelegate::CanActivate() const { + // We don't want mouse clicks to activate us, but we need to allow + // activation when the user is using the keyboard (FocusCycler). + const FocusCycler* focus_cycler = focus_cycler_for_testing_ + ? focus_cycler_for_testing_ + : WmShell::Get()->focus_cycler(); + return focus_cycler->widget_activating() == GetWidget(); +} + +void StatusAreaWidgetDelegate::DeleteDelegate() {} + +void StatusAreaWidgetDelegate::AddTray(views::View* tray) { + SetLayoutManager(NULL); // Reset layout manager before adding a child. + AddChildView(tray); + // Set the layout manager with the new list of children. + UpdateLayout(); +} + +void StatusAreaWidgetDelegate::UpdateLayout() { + // Use a grid layout so that the trays can be centered in each cell, and + // so that the widget gets laid out correctly when tray sizes change. + views::GridLayout* layout = new views::GridLayout(this); + SetLayoutManager(layout); + + // Update tray border based on layout. + bool is_child_on_edge = true; + for (int c = 0; c < child_count(); ++c) { + views::View* child = child_at(c); + if (!child->visible()) + continue; + SetBorderOnChild(child, is_child_on_edge); + is_child_on_edge = false; + } + + views::ColumnSet* columns = layout->AddColumnSet(0); + + if (IsHorizontalAlignment(alignment_)) { + for (int c = child_count() - 1; c >= 0; --c) { + views::View* child = child_at(c); + if (!child->visible()) + continue; + columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, + 0, /* resize percent */ + views::GridLayout::USE_PREF, 0, 0); + } + layout->StartRow(0, 0); + for (int c = child_count() - 1; c >= 0; --c) { + views::View* child = child_at(c); + if (child->visible()) + layout->AddView(child); + } + } else { + columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, + 0, /* resize percent */ + views::GridLayout::USE_PREF, 0, 0); + for (int c = child_count() - 1; c >= 0; --c) { + views::View* child = child_at(c); + if (!child->visible()) + continue; + layout->StartRow(0, 0); + layout->AddView(child); + } + } + + layer()->GetAnimator()->StopAnimating(); + StatusAreaWidgetDelegateAnimationSettings settings(layer()); + + Layout(); + UpdateWidgetSize(); +} + +void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) { + // Need to resize the window when trays or items are added/removed. + StatusAreaWidgetDelegateAnimationSettings settings(layer()); + UpdateWidgetSize(); +} + +void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) { + UpdateLayout(); +} + +void StatusAreaWidgetDelegate::UpdateWidgetSize() { + if (GetWidget()) + GetWidget()->SetSize(GetPreferredSize()); +} + +void StatusAreaWidgetDelegate::SetBorderOnChild(views::View* child, + bool extend_border_to_edge) { + // Tray views are laid out right-to-left or bottom-to-top. + const bool horizontal_alignment = IsHorizontalAlignment(alignment_); + const int padding = (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2; + + const int top_edge = horizontal_alignment ? padding : 0; + const int left_edge = horizontal_alignment ? 0 : padding; + const int bottom_edge = + horizontal_alignment + ? padding + : (extend_border_to_edge ? kPaddingFromEdgeOfShelf : 0); + const int right_edge = + horizontal_alignment + ? (extend_border_to_edge ? kPaddingFromEdgeOfShelf : 0) + : padding; + child->SetBorder( + views::CreateEmptyBorder(top_edge, left_edge, bottom_edge, right_edge)); + + // Layout on |child| needs to be updated based on new border value before + // displaying; otherwise |child| will be showing with old border size. + // Fix for crbug.com/623438. + child->Layout(); +} + +} // namespace ash
diff --git a/ash/common/system/status_area_widget_delegate.h b/ash/common/system/status_area_widget_delegate.h new file mode 100644 index 0000000..781c8c6 --- /dev/null +++ b/ash/common/system/status_area_widget_delegate.h
@@ -0,0 +1,73 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_STATUS_AREA_WIDGET_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_STATUS_AREA_WIDGET_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/accessible_pane_view.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { +class FocusCycler; + +// The View for the status area widget. +class ASH_EXPORT StatusAreaWidgetDelegate : public views::AccessiblePaneView, + public views::WidgetDelegate { + public: + StatusAreaWidgetDelegate(); + ~StatusAreaWidgetDelegate() override; + + // Add a tray view to the widget (e.g. system tray, web notifications). + void AddTray(views::View* tray); + + // Called whenever layout might change (e.g. alignment changed). + void UpdateLayout(); + + // Sets the focus cycler. + void SetFocusCyclerForTesting(const FocusCycler* focus_cycler); + + void set_alignment(ShelfAlignment alignment) { alignment_ = alignment; } + + // Overridden from views::AccessiblePaneView. + View* GetDefaultFocusableChild() override; + + // Overridden from views::View: + views::Widget* GetWidget() override; + const views::Widget* GetWidget() const override; + + // Overridden from ui::EventHandler: + void OnGestureEvent(ui::GestureEvent* event) override; + + // views::WidgetDelegate overrides: + bool CanActivate() const override; + void DeleteDelegate() override; + + protected: + // Overridden from views::View: + void ChildPreferredSizeChanged(views::View* child) override; + void ChildVisibilityChanged(views::View* child) override; + + private: + void UpdateWidgetSize(); + + // Sets a border on |child|. If |extend_border_to_edge| is true, then an extra + // wide border is added to extend the view's hit region to the edge of the + // screen. + void SetBorderOnChild(views::View* child, bool extend_border_to_edge); + + const FocusCycler* focus_cycler_for_testing_; + + // TODO(jamescook): Get this from WmShelf. + ShelfAlignment alignment_; + + DISALLOW_COPY_AND_ASSIGN(StatusAreaWidgetDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_STATUS_AREA_WIDGET_DELEGATE_H_
diff --git a/ash/common/system/system_notifier.cc b/ash/common/system/system_notifier.cc new file mode 100644 index 0000000..d36e4e1 --- /dev/null +++ b/ash/common/system/system_notifier.cc
@@ -0,0 +1,89 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/system_notifier.h" + +#include "base/logging.h" + +namespace ash { +namespace system_notifier { + +namespace { + +// See http://dev.chromium.org/chromium-os/chromiumos-design-docs/ +// system-notifications for the reasoning. + +// |kAlwaysShownSystemNotifierIds| is the list of system notification sources +// which can appear regardless of the situation, such like login screen or lock +// screen. +const char* kAlwaysShownSystemNotifierIds[] = { + kNotifierAccessibility, kNotifierDeprecatedAccelerator, kNotifierBattery, + kNotifierDisplay, kNotifierDisplayError, kNotifierNetworkError, + kNotifierPower, + // Note: Order doesn't matter here, so keep this in alphabetic order, don't + // just add your stuff at the end! + NULL}; + +// |kAshSystemNotifiers| is the list of normal system notification sources for +// ash events. These notifications can be hidden in some context. +const char* kAshSystemNotifiers[] = { + kNotifierBluetooth, kNotifierDisplayResolutionChange, kNotifierDisk, + kNotifierLocale, kNotifierMultiProfileFirstRun, kNotifierNetwork, + kNotifierNetworkPortalDetector, kNotifierScreenshot, kNotifierScreenCapture, + kNotifierScreenShare, kNotifierSessionLengthTimeout, + kNotifierSupervisedUser, kNotifierWebUsb, kNotifierSms, + // Note: Order doesn't matter here, so keep this in alphabetic order, don't + // just add your stuff at the end! + NULL}; + +bool MatchSystemNotifierId(const message_center::NotifierId& notifier_id, + const char* id_list[]) { + if (notifier_id.type != message_center::NotifierId::SYSTEM_COMPONENT) + return false; + + for (size_t i = 0; id_list[i] != NULL; ++i) { + if (notifier_id.id == id_list[i]) + return true; + } + return false; +} + +} // namespace + +const char kNotifierAccessibility[] = "ash.accessibility"; +const char kNotifierBattery[] = "ash.battery"; +const char kNotifierBluetooth[] = "ash.bluetooth"; +const char kNotifierDeprecatedAccelerator[] = "ash.accelerator-controller"; +const char kNotifierDisk[] = "ash.disk"; +const char kNotifierDisplay[] = "ash.display"; +const char kNotifierDisplayError[] = "ash.display.error"; +const char kNotifierDisplayResolutionChange[] = "ash.display.resolution-change"; +const char kNotifierDualRole[] = "ash.dual-role"; +const char kNotifierHats[] = "ash.hats"; +const char kNotifierLocale[] = "ash.locale"; +const char kNotifierMultiProfileFirstRun[] = "ash.multi-profile.first-run"; +const char kNotifierNetwork[] = "ash.network"; +const char kNotifierNetworkError[] = "ash.network.error"; +const char kNotifierNetworkPortalDetector[] = "ash.network.portal-detector"; +const char kNotifierPower[] = "ash.power"; +const char kNotifierQuickUnlock[] = "ash.quickunlock"; +const char kNotifierScreenshot[] = "ash.screenshot"; +const char kNotifierScreenCapture[] = "ash.screen-capture"; +const char kNotifierScreenShare[] = "ash.screen-share"; +const char kNotifierSessionLengthTimeout[] = "ash.session-length-timeout"; +const char kNotifierSms[] = "ash.sms"; +const char kNotifierSupervisedUser[] = "ash.locally-managed-user"; +const char kNotifierWebUsb[] = "ash.webusb"; + +bool ShouldAlwaysShowPopups(const message_center::NotifierId& notifier_id) { + return MatchSystemNotifierId(notifier_id, kAlwaysShownSystemNotifierIds); +} + +bool IsAshSystemNotifier(const message_center::NotifierId& notifier_id) { + return ShouldAlwaysShowPopups(notifier_id) || + MatchSystemNotifierId(notifier_id, kAshSystemNotifiers); +} + +} // namespace system_notifier +} // namespace ash
diff --git a/ash/common/system/system_notifier.h b/ash/common/system/system_notifier.h new file mode 100644 index 0000000..706347e --- /dev/null +++ b/ash/common/system/system_notifier.h
@@ -0,0 +1,55 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_SYSTEM_NOTIFIER_H_ +#define ASH_COMMON_SYSTEM_SYSTEM_NOTIFIER_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "ui/message_center/notifier_settings.h" + +namespace ash { +namespace system_notifier { + +// The list of ash system notifier IDs. Alphabetical order. +ASH_EXPORT extern const char kNotifierAccessibility[]; +ASH_EXPORT extern const char kNotifierBattery[]; +ASH_EXPORT extern const char kNotifierBluetooth[]; +ASH_EXPORT extern const char kNotifierDeprecatedAccelerator[]; +ASH_EXPORT extern const char kNotifierDisk[]; +ASH_EXPORT extern const char kNotifierDisplay[]; +ASH_EXPORT extern const char kNotifierDisplayResolutionChange[]; +ASH_EXPORT extern const char kNotifierDisplayError[]; +ASH_EXPORT extern const char kNotifierDualRole[]; +ASH_EXPORT extern const char kNotifierHats[]; +ASH_EXPORT extern const char kNotifierLocale[]; +ASH_EXPORT extern const char kNotifierMultiProfileFirstRun[]; +ASH_EXPORT extern const char kNotifierNetwork[]; +ASH_EXPORT extern const char kNotifierNetworkError[]; +ASH_EXPORT extern const char kNotifierNetworkPortalDetector[]; +ASH_EXPORT extern const char kNotifierPower[]; +ASH_EXPORT extern const char kNotifierQuickUnlock[]; +ASH_EXPORT extern const char kNotifierScreenshot[]; +ASH_EXPORT extern const char kNotifierScreenCapture[]; +ASH_EXPORT extern const char kNotifierScreenShare[]; +ASH_EXPORT extern const char kNotifierSessionLengthTimeout[]; +ASH_EXPORT extern const char kNotifierSms[]; +ASH_EXPORT extern const char kNotifierSupervisedUser[]; +ASH_EXPORT extern const char kNotifierWebUsb[]; + +// Returns true if notifications from |notifier_id| should always appear as +// popups. "Always appear" means the popups should appear even in login screen, +// lock screen, or fullscreen state. +ASH_EXPORT bool ShouldAlwaysShowPopups( + const message_center::NotifierId& notifier_id); + +// Returns true if |notifier_id| is the system notifier from Ash. +ASH_EXPORT bool IsAshSystemNotifier( + const message_center::NotifierId& notifier_id); + +} // namespace system_notifier +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_SYSTEM_NOTIFIER_H_
diff --git a/ash/common/system/tiles/tiles_default_view.cc b/ash/common/system/tiles/tiles_default_view.cc new file mode 100644 index 0000000..cdf7bf8 --- /dev/null +++ b/ash/common/system/tiles/tiles_default_view.cc
@@ -0,0 +1,141 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tiles/tiles_default_view.h" + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shutdown_controller.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/wm/lock_state_controller.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/session_manager_client.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/custom_button.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" + +namespace { + +// The ISO-639 code for the Hebrew locale. The help icon asset is a '?' which is +// not mirrored in this locale. +const char kHebrewLocale[] = "he"; + +} // namespace + +namespace ash { + +TilesDefaultView::TilesDefaultView(SystemTrayItem* owner, LoginStatus login) + : owner_(owner), + login_(login), + settings_button_(nullptr), + help_button_(nullptr), + lock_button_(nullptr), + power_button_(nullptr) {} + +TilesDefaultView::~TilesDefaultView() {} + +void TilesDefaultView::Init() { + WmShell* shell = WmShell::Get(); + views::BoxLayout* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 4, 0, 0); + box_layout->set_main_axis_alignment( + views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); + box_layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + SetLayoutManager(box_layout); + + // Show the buttons in this row as disabled if the user is at the login + // screen, lock screen, or in a secondary account flow. The exception is + // |power_button_| which is always shown as enabled. + const bool disable_buttons = !TrayPopupUtils::CanOpenWebUISettings(login_); + + settings_button_ = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, + IDS_ASH_STATUS_TRAY_SETTINGS); + if (disable_buttons || !shell->system_tray_delegate()->ShouldShowSettings()) + settings_button_->SetEnabled(false); + AddChildView(settings_button_); + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + + help_button_ = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); + if (base::i18n::IsRTL() && + base::i18n::GetConfiguredLocale() == kHebrewLocale) { + // The asset for the help button is a question mark '?'. Normally this asset + // is flipped in RTL locales, however Hebrew uses the LTR '?'. So the + // flipping must be disabled. (crbug.com/475237) + help_button_->EnableCanvasFlippingForRTLUI(false); + } + if (disable_buttons) + help_button_->SetEnabled(false); + AddChildView(help_button_); + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + + lock_button_ = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + kSystemMenuLockIcon, IDS_ASH_STATUS_TRAY_LOCK); + if (disable_buttons || !shell->GetSessionStateDelegate()->CanLockScreen()) + lock_button_->SetEnabled(false); + + AddChildView(lock_button_); + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + + power_button_ = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + kSystemMenuPowerIcon, IDS_ASH_STATUS_TRAY_SHUTDOWN); + AddChildView(power_button_); + // This object is recreated every time the menu opens. Don't bother updating + // the tooltip if the shutdown policy changes while the menu is open. + bool reboot = WmShell::Get()->shutdown_controller()->reboot_on_shutdown(); + power_button_->SetTooltipText(l10n_util::GetStringUTF16( + reboot ? IDS_ASH_STATUS_TRAY_REBOOT : IDS_ASH_STATUS_TRAY_SHUTDOWN)); +} + +void TilesDefaultView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + DCHECK(sender); + WmShell* shell = WmShell::Get(); + if (sender == settings_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_SETTINGS); + shell->system_tray_controller()->ShowSettings(); + } else if (sender == help_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_HELP); + shell->system_tray_controller()->ShowHelp(); + } else if (sender == lock_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_LOCK_SCREEN); + chromeos::DBusThreadManager::Get() + ->GetSessionManagerClient() + ->RequestLockScreen(); + } else if (sender == power_button_) { + shell->RecordUserMetricsAction(UMA_TRAY_SHUT_DOWN); + Shell::GetInstance()->lock_state_controller()->RequestShutdown(); + } + + owner_->system_tray()->CloseSystemBubble(); +} + +views::View* TilesDefaultView::GetHelpButtonView() const { + return help_button_; +} + +const views::CustomButton* TilesDefaultView::GetShutdownButtonViewForTest() + const { + return power_button_; +} + +} // namespace ash
diff --git a/ash/common/system/tiles/tiles_default_view.h b/ash/common/system/tiles/tiles_default_view.h new file mode 100644 index 0000000..deab47a --- /dev/null +++ b/ash/common/system/tiles/tiles_default_view.h
@@ -0,0 +1,61 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TILES_TILES_DEFAULT_VIEW_H_ +#define ASH_COMMON_SYSTEM_TILES_TILES_DEFAULT_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "base/macros.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace views { +class CustomButton; +} + +namespace ash { +class SystemTrayItem; + +// The container view for the tiles in the bottom row of the system menu +// (settings, help, lock, and power). +class ASH_EXPORT TilesDefaultView : public views::View, + public views::ButtonListener { + public: + TilesDefaultView(SystemTrayItem* owner, LoginStatus login); + ~TilesDefaultView() override; + + // Sets the layout manager and child views of |this|. + // TODO(tdanderson|bruthig): Consider moving the layout manager + // setup code to a location which can be shared by other system menu rows. + void Init(); + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + // Accessor needed to obtain the help button view for the first-run flow. + views::View* GetHelpButtonView() const; + + const views::CustomButton* GetShutdownButtonViewForTest() const; + + private: + friend class TrayTilesTest; + + SystemTrayItem* owner_; + LoginStatus login_; + + // Pointers to the child buttons of |this|. Note that some buttons may not + // exist (depending on the user's current login status, for instance), in + // which case the corresponding pointer will be null. + views::CustomButton* settings_button_; + views::CustomButton* help_button_; + views::CustomButton* lock_button_; + views::CustomButton* power_button_; + + DISALLOW_COPY_AND_ASSIGN(TilesDefaultView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TILES_TILES_DEFAULT_VIEW_H_
diff --git a/ash/common/system/tiles/tray_tiles.cc b/ash/common/system/tiles/tray_tiles.cc new file mode 100644 index 0000000..227a4c9 --- /dev/null +++ b/ash/common/system/tiles/tray_tiles.cc
@@ -0,0 +1,44 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tiles/tray_tiles.h" + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tiles/tiles_default_view.h" +#include "ash/common/wm_shell.h" + +namespace ash { + +TrayTiles::TrayTiles(SystemTray* system_tray) + : SystemTrayItem(system_tray, UMA_NOT_RECORDED), default_view_(nullptr) {} + +TrayTiles::~TrayTiles() {} + +views::View* TrayTiles::GetHelpButtonView() const { + if (!default_view_) + return nullptr; + return default_view_->GetHelpButtonView(); +} + +TilesDefaultView* TrayTiles::GetDefaultViewForTesting() const { + return default_view_; +} + +views::View* TrayTiles::CreateDefaultViewForTesting(LoginStatus status) { + return CreateDefaultView(status); +} + +views::View* TrayTiles::CreateDefaultView(LoginStatus status) { + CHECK(default_view_ == nullptr); + default_view_ = new TilesDefaultView(this, status); + default_view_->Init(); + return default_view_; +} + +void TrayTiles::DestroyDefaultView() { + default_view_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/system/tiles/tray_tiles.h b/ash/common/system/tiles/tray_tiles.h new file mode 100644 index 0000000..be8bc8b --- /dev/null +++ b/ash/common/system/tiles/tray_tiles.h
@@ -0,0 +1,44 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TILES_TRAY_TILES_H_ +#define ASH_COMMON_SYSTEM_TILES_TRAY_TILES_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" + +namespace ash { +class SystemTray; +class TilesDefaultView; + +// The tray item for the 'tiles' at the bottom of the system menu. Each tile is +// an image button which does not reqire explanatory text, and thus does not +// require its own dedicated row in the system menu. +class ASH_EXPORT TrayTiles : public SystemTrayItem { + public: + explicit TrayTiles(SystemTray* system_tray); + ~TrayTiles() override; + + // Accessor needed to obtain the help button view for the first-run flow. + views::View* GetHelpButtonView() const; + + TilesDefaultView* GetDefaultViewForTesting() const; + views::View* CreateDefaultViewForTesting(LoginStatus status); + + private: + friend class TrayTilesTest; + + // SystemTrayItem: + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyDefaultView() override; + + TilesDefaultView* default_view_; + + DISALLOW_COPY_AND_ASSIGN(TrayTiles); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TILES_TRAY_TILES_H_
diff --git a/ash/common/system/tiles/tray_tiles_unittest.cc b/ash/common/system/tiles/tray_tiles_unittest.cc new file mode 100644 index 0000000..39308bd --- /dev/null +++ b/ash/common/system/tiles/tray_tiles_unittest.cc
@@ -0,0 +1,92 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tiles/tray_tiles.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tiles/tiles_default_view.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "ui/views/controls/button/custom_button.h" +#include "ui/views/view.h" + +namespace ash { + +class TrayTilesTest : public test::AshTestBase { + public: + TrayTilesTest() {} + ~TrayTilesTest() override {} + + void SetUp() override { + test::AshTestBase::SetUp(); + tray_tiles_.reset(new TrayTiles(GetPrimarySystemTray())); + } + + void TearDown() override { + tray_tiles_.reset(); + test::AshTestBase::TearDown(); + } + + views::CustomButton* GetSettingsButton() { + return tray_tiles()->default_view_->settings_button_; + } + + views::CustomButton* GetHelpButton() { + return tray_tiles()->default_view_->help_button_; + } + + views::CustomButton* GetLockButton() { + return tray_tiles()->default_view_->lock_button_; + } + + views::CustomButton* GetPowerButton() { + return tray_tiles()->default_view_->power_button_; + } + + TrayTiles* tray_tiles() { return tray_tiles_.get(); } + + private: + std::unique_ptr<TrayTiles> tray_tiles_; + + DISALLOW_COPY_AND_ASSIGN(TrayTilesTest); +}; + +TEST_F(TrayTilesTest, ButtonStatesWithAddingUser) { + SetUserAddingScreenRunning(true); + std::unique_ptr<views::View> default_view( + tray_tiles()->CreateDefaultViewForTesting(LoginStatus::USER)); + EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); +} + +TEST_F(TrayTilesTest, ButtonStatesWithLoginStatusNotLoggedIn) { + std::unique_ptr<views::View> default_view( + tray_tiles()->CreateDefaultViewForTesting(LoginStatus::NOT_LOGGED_IN)); + EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); +} + +TEST_F(TrayTilesTest, ButtonStatesWithLoginStatusLocked) { + std::unique_ptr<views::View> default_view( + tray_tiles()->CreateDefaultViewForTesting(LoginStatus::LOCKED)); + EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_DISABLED); + EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); +} + +TEST_F(TrayTilesTest, ButtonStatesWithLoginStatusUser) { + std::unique_ptr<views::View> default_view( + tray_tiles()->CreateDefaultViewForTesting(LoginStatus::USER)); + EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_NORMAL); + EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_NORMAL); + EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_NORMAL); + EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); +} + +} // namespace ash
diff --git a/ash/system/toast/OWNERS b/ash/common/system/toast/OWNERS similarity index 100% rename from ash/system/toast/OWNERS rename to ash/common/system/toast/OWNERS
diff --git a/ash/common/system/toast/toast_data.cc b/ash/common/system/toast/toast_data.cc new file mode 100644 index 0000000..5390b781 --- /dev/null +++ b/ash/common/system/toast/toast_data.cc
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/toast/toast_data.h" + +#include <utility> + +namespace ash { + +ToastData::ToastData(std::string id, + const base::string16& text, + int32_t duration_ms, + const base::Optional<base::string16>& dismiss_text) + : id(std::move(id)), + text(text), + duration_ms(duration_ms), + dismiss_text(dismiss_text) {} + +ToastData::ToastData(const ToastData& other) = default; + +ToastData::~ToastData() = default; + +} // namespace ash
diff --git a/ash/common/system/toast/toast_data.h b/ash/common/system/toast/toast_data.h new file mode 100644 index 0000000..a12e073 --- /dev/null +++ b/ash/common/system/toast/toast_data.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TOAST_TOAST_DATA_H_ +#define ASH_COMMON_SYSTEM_TOAST_TOAST_DATA_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "base/optional.h" +#include "base/strings/string16.h" + +namespace ash { + +struct ASH_EXPORT ToastData { + // "|duration_ms| == -1" means the toast view should be displayed until the + // dismiss button is clicked. + static const int32_t kInfiniteDuration = -1; + + ToastData(std::string id, + const base::string16& text, + int32_t duration_ms, + const base::Optional<base::string16>& dismiss_text); + ToastData(const ToastData& other); + ~ToastData(); + + std::string id; + base::string16 text; + int32_t duration_ms; + base::Optional<base::string16> dismiss_text; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TOAST_TOAST_DATA_H_
diff --git a/ash/common/system/toast/toast_manager.cc b/ash/common/system/toast/toast_manager.cc new file mode 100644 index 0000000..37a9ea2 --- /dev/null +++ b/ash/common/system/toast/toast_manager.cc
@@ -0,0 +1,97 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/toast/toast_manager.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/location.h" +#include "base/threading/thread_task_runner_handle.h" + +namespace ash { + +namespace { + +// Minimum duration for a toast to be visible (in millisecond). +const int32_t kMinimumDurationMs = 200; + +} // anonymous namespace + +ToastManager::ToastManager() : weak_ptr_factory_(this) {} + +ToastManager::~ToastManager() {} + +void ToastManager::Show(const ToastData& data) { + const std::string& id = data.id; + DCHECK(!id.empty()); + + if (current_toast_id_ == id) { + // TODO(yoshiki): Replaces the visible toast. + return; + } + + auto existing_toast = + std::find_if(queue_.begin(), queue_.end(), + [&id](const ToastData& data) { return data.id == id; }); + + if (existing_toast == queue_.end()) { + queue_.emplace_back(data); + } else { + *existing_toast = data; + } + + if (queue_.size() == 1 && overlay_ == nullptr) + ShowLatest(); +} + +void ToastManager::Cancel(const std::string& id) { + if (id == current_toast_id_) { + overlay_->Show(false); + return; + } + + auto cancelled_toast = + std::find_if(queue_.begin(), queue_.end(), + [&id](const ToastData& data) { return data.id == id; }); + if (cancelled_toast != queue_.end()) + queue_.erase(cancelled_toast); +} + +void ToastManager::OnClosed() { + overlay_.reset(); + current_toast_id_.clear(); + + // Show the next toast if available. + if (!queue_.empty()) + ShowLatest(); +} + +void ToastManager::ShowLatest() { + DCHECK(!overlay_); + + const ToastData data = std::move(queue_.front()); + queue_.pop_front(); + + current_toast_id_ = data.id; + serial_++; + + overlay_.reset(new ToastOverlay(this, data.text, data.dismiss_text)); + overlay_->Show(true); + + if (data.duration_ms != ToastData::kInfiniteDuration) { + int32_t duration_ms = std::max(data.duration_ms, kMinimumDurationMs); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&ToastManager::OnDurationPassed, + weak_ptr_factory_.GetWeakPtr(), serial_), + base::TimeDelta::FromMilliseconds(duration_ms)); + } +} + +void ToastManager::OnDurationPassed(int toast_number) { + if (overlay_ && serial_ == toast_number) + overlay_->Show(false); +} + +} // namespace ash
diff --git a/ash/common/system/toast/toast_manager.h b/ash/common/system/toast/toast_manager.h new file mode 100644 index 0000000..26b72a68 --- /dev/null +++ b/ash/common/system/toast/toast_manager.h
@@ -0,0 +1,58 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TOAST_TOAST_MANAGER_H_ +#define ASH_COMMON_SYSTEM_TOAST_TOAST_MANAGER_H_ + +#include <deque> +#include <memory> +#include <string> + +#include "ash/ash_export.h" +#include "ash/common/system/toast/toast_data.h" +#include "ash/common/system/toast/toast_overlay.h" +#include "base/memory/weak_ptr.h" + +namespace ash { + +// Class managing toast requests. +class ASH_EXPORT ToastManager : public ToastOverlay::Delegate { + public: + ToastManager(); + ~ToastManager() override; + + // Show a toast. If there are queued toasts, succeeding toasts are queued as + // well, and are shown one by one. + void Show(const ToastData& data); + + void Cancel(const std::string& id); + + // ToastOverlay::Delegate overrides: + void OnClosed() override; + + private: + friend class ToastManagerTest; + + void ShowLatest(); + void OnDurationPassed(int toast_number); + + ToastOverlay* GetCurrentOverlayForTesting() { return overlay_.get(); } + int serial_for_testing() const { return serial_; } + void ResetSerialForTesting() { serial_ = 0; } + + // ID of the toast which is currently shown. Empty if no toast is visible. + std::string current_toast_id_; + + int serial_ = 0; + std::deque<ToastData> queue_; + std::unique_ptr<ToastOverlay> overlay_; + + base::WeakPtrFactory<ToastManager> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ToastManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TOAST_TOAST_MANAGER_H_
diff --git a/ash/common/system/toast/toast_overlay.cc b/ash/common/system/toast/toast_overlay.cc new file mode 100644 index 0000000..5bebb73 --- /dev/null +++ b/ash/common/system/toast/toast_overlay.cc
@@ -0,0 +1,310 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/toast/toast_overlay.h" + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/font_list.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/wm/core/window_animations.h" + +namespace ash { + +namespace { + +// Offset of the overlay from the edge of the work area. +const int kOffset = 5; + +// Font style used for modifier key labels. +const ui::ResourceBundle::FontStyle kTextFontStyle = + ui::ResourceBundle::MediumFont; + +// Duration of slide animation when overlay is shown or hidden. +const int kSlideAnimationDurationMs = 100; + +// Colors for the dismiss button. +const SkColor kButtonBackgroundColor = SkColorSetARGB(0xFF, 0x32, 0x32, 0x32); +const SkColor kButtonTextColor = SkColorSetARGB(0xFF, 0x7B, 0xAA, 0xF7); + +// These values are in DIP. +const int kToastHorizontalSpacing = 16; +const int kToastVerticalSpacing = 16; +const int kToastMaximumWidth = 568; +const int kToastMinimumWidth = 288; + +// Returns the work area bounds for the root window where new windows are added +// (including new toasts). +gfx::Rect GetUserWorkAreaBounds() { + return WmShelf::ForWindow(WmShell::Get()->GetRootWindowForNewWindows()) + ->GetUserWorkAreaBounds(); +} + +} // anonymous namespace + +/////////////////////////////////////////////////////////////////////////////// +// ToastOverlayLabel +class ToastOverlayLabel : public views::Label { + public: + explicit ToastOverlayLabel(const base::string16& label); + ~ToastOverlayLabel() override; + + private: + DISALLOW_COPY_AND_ASSIGN(ToastOverlayLabel); +}; + +ToastOverlayLabel::ToastOverlayLabel(const base::string16& label) { + ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); + + SetText(label); + SetHorizontalAlignment(gfx::ALIGN_LEFT); + SetFontList(rb->GetFontList(kTextFontStyle)); + SetAutoColorReadabilityEnabled(false); + SetMultiLine(true); + SetEnabledColor(SK_ColorWHITE); + SetDisabledColor(SK_ColorWHITE); + SetSubpixelRenderingEnabled(false); + + int verticalSpacing = + kToastVerticalSpacing - (GetPreferredSize().height() - GetBaseline()); + SetBorder(views::CreateEmptyBorder(verticalSpacing, kToastHorizontalSpacing, + verticalSpacing, kToastHorizontalSpacing)); +} + +ToastOverlayLabel::~ToastOverlayLabel() {} + +/////////////////////////////////////////////////////////////////////////////// +// ToastOverlayButton +class ToastOverlayButton : public views::LabelButton { + public: + explicit ToastOverlayButton(views::ButtonListener* listener, + const base::string16& label); + ~ToastOverlayButton() override {} + + private: + friend class ToastOverlay; // for ToastOverlay::ClickDismissButtonForTesting. + + DISALLOW_COPY_AND_ASSIGN(ToastOverlayButton); +}; + +ToastOverlayButton::ToastOverlayButton(views::ButtonListener* listener, + const base::string16& text) + : views::LabelButton(listener, text) { + SetInkDropMode(InkDropMode::ON); + set_has_ink_drop_action_on_click(true); + set_ink_drop_base_color(SK_ColorWHITE); + + ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); + + SetEnabledTextColors(kButtonTextColor); + SetFontList(rb->GetFontList(kTextFontStyle)); + + // Treat the space below the baseline as a margin. + int verticalSpacing = kToastVerticalSpacing - + (GetPreferredSize().height() - label()->GetBaseline()); + SetBorder(views::CreateEmptyBorder(verticalSpacing, kToastHorizontalSpacing, + verticalSpacing, kToastHorizontalSpacing)); +} + +/////////////////////////////////////////////////////////////////////////////// +// ToastOverlayView +class ToastOverlayView : public views::View, public views::ButtonListener { + public: + // This object is not owned by the views hierarchy or by the widget. + ToastOverlayView(ToastOverlay* overlay, + const base::string16& text, + const base::Optional<base::string16>& dismiss_text); + ~ToastOverlayView() override; + + // views::View overrides: + void OnPaint(gfx::Canvas* canvas) override; + + ToastOverlayButton* button() { return button_; } + + private: + // views::View overrides: + gfx::Size GetMaximumSize() const override; + gfx::Size GetMinimumSize() const override; + + // views::ButtonListener overrides: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + ToastOverlay* overlay_ = nullptr; // weak + ToastOverlayButton* button_ = nullptr; // weak + + DISALLOW_COPY_AND_ASSIGN(ToastOverlayView); +}; + +ToastOverlayView::ToastOverlayView( + ToastOverlay* overlay, + const base::string16& text, + const base::Optional<base::string16>& dismiss_text) + : overlay_(overlay) { + auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + SetLayoutManager(layout); + + if (dismiss_text.has_value()) { + button_ = new ToastOverlayButton( + this, dismiss_text.value().empty() + ? l10n_util::GetStringUTF16(IDS_ASH_TOAST_DISMISS_BUTTON) + : dismiss_text.value()); + } + + ToastOverlayLabel* label = new ToastOverlayLabel(text); + AddChildView(label); + layout->SetFlexForView(label, 1); + + if (button_) { + label->SetMaximumWidth( + GetMaximumSize().width() - button_->GetPreferredSize().width() - + kToastHorizontalSpacing * 2 - kToastHorizontalSpacing * 2); + AddChildView(button_); + } +} + +ToastOverlayView::~ToastOverlayView() {} + +void ToastOverlayView::OnPaint(gfx::Canvas* canvas) { + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(kButtonBackgroundColor); + canvas->DrawRoundRect(GetLocalBounds(), 2, flags); + views::View::OnPaint(canvas); +} + +gfx::Size ToastOverlayView::GetMinimumSize() const { + return gfx::Size(kToastMinimumWidth, 0); +} + +gfx::Size ToastOverlayView::GetMaximumSize() const { + gfx::Rect work_area_bounds = GetUserWorkAreaBounds(); + return gfx::Size(kToastMaximumWidth, work_area_bounds.height() - kOffset * 2); +} + +void ToastOverlayView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + DCHECK_EQ(button_, sender); + overlay_->Show(false); +} + +/////////////////////////////////////////////////////////////////////////////// +// ToastOverlay +ToastOverlay::ToastOverlay(Delegate* delegate, + const base::string16& text, + base::Optional<base::string16> dismiss_text) + : delegate_(delegate), + text_(text), + dismiss_text_(dismiss_text), + overlay_widget_(new views::Widget), + overlay_view_(new ToastOverlayView(this, text, dismiss_text)), + widget_size_(overlay_view_->GetPreferredSize()) { + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.name = "ToastOverlay"; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.accept_events = true; + params.keep_on_top = true; + params.remove_standard_frame = true; + params.bounds = CalculateOverlayBounds(); + // Show toasts above the app list and below the lock screen. + WmShell::Get() + ->GetRootWindowForNewWindows() + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + overlay_widget_.get(), kShellWindowId_SystemModalContainer, ¶ms); + overlay_widget_->Init(params); + overlay_widget_->SetVisibilityChangedAnimationsEnabled(true); + overlay_widget_->SetContentsView(overlay_view_.get()); + overlay_widget_->SetBounds(CalculateOverlayBounds()); + + WmWindow* overlay_window = WmWindow::Get(overlay_widget_->GetNativeWindow()); + overlay_window->SetVisibilityAnimationType( + ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); + overlay_window->SetVisibilityAnimationDuration( + base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs)); +} + +ToastOverlay::~ToastOverlay() { + overlay_widget_->Close(); +} + +void ToastOverlay::Show(bool visible) { + if (overlay_widget_->GetLayer()->GetTargetVisibility() == visible) + return; + + ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); + DCHECK(animator); + if (animator->is_animating()) { + // Showing during hiding animation doesn't happen since, ToastOverlay should + // be one-time-use and not be reused. + DCHECK(!visible); + + return; + } + + base::TimeDelta original_duration = animator->GetTransitionDuration(); + ui::ScopedLayerAnimationSettings animation_settings(animator); + // ScopedLayerAnimationSettings ctor chanes the transition duration, so change + // back it to the original value (should be zero). + animation_settings.SetTransitionDuration(original_duration); + + animation_settings.AddObserver(this); + + if (visible) { + overlay_widget_->Show(); + + // Notify accessibility about the overlay. + overlay_view_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false); + } else { + overlay_widget_->Hide(); + } +} + +gfx::Rect ToastOverlay::CalculateOverlayBounds() { + gfx::Rect bounds = GetUserWorkAreaBounds(); + int target_y = bounds.bottom() - widget_size_.height() - kOffset; + bounds.ClampToCenteredSize(widget_size_); + bounds.set_y(target_y); + return bounds; +} + +void ToastOverlay::OnImplicitAnimationsScheduled() {} + +void ToastOverlay::OnImplicitAnimationsCompleted() { + if (!overlay_widget_->GetLayer()->GetTargetVisibility()) + delegate_->OnClosed(); +} + +views::Widget* ToastOverlay::widget_for_testing() { + return overlay_widget_.get(); +} + +ToastOverlayButton* ToastOverlay::dismiss_button_for_testing() { + return overlay_view_->button(); +} + +void ToastOverlay::ClickDismissButtonForTesting(const ui::Event& event) { + DCHECK(overlay_view_->button()); + overlay_view_->button()->NotifyClick(event); +} + +} // namespace ash
diff --git a/ash/common/system/toast/toast_overlay.h b/ash/common/system/toast/toast_overlay.h new file mode 100644 index 0000000..4d3fe97 --- /dev/null +++ b/ash/common/system/toast/toast_overlay.h
@@ -0,0 +1,79 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TOAST_TOAST_OVERLAY_H_ +#define ASH_COMMON_SYSTEM_TOAST_TOAST_OVERLAY_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/optional.h" +#include "base/strings/string16.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" +#include "ui/gfx/geometry/size.h" + +namespace gfx { +class Rect; +} + +namespace views { +class Widget; +} + +namespace ash { + +class ToastManagerTest; +class ToastOverlayView; +class ToastOverlayButton; + +class ASH_EXPORT ToastOverlay : public ui::ImplicitAnimationObserver { + public: + class ASH_EXPORT Delegate { + public: + virtual ~Delegate() {} + virtual void OnClosed() = 0; + }; + + // Creates the Toast overlay UI. |text| is the message to be shown, and + // |dismiss_text| is the message for the button to dismiss the toast message. + // If |dismiss_text| is null, no dismiss button will be shown. If + // |dismiss_text| has a value but the string is empty, the default text is + // used. + ToastOverlay(Delegate* delegate, + const base::string16& text, + base::Optional<base::string16> dismiss_text); + ~ToastOverlay() override; + + // Shows or hides the overlay. + void Show(bool visible); + + private: + friend class ToastManagerTest; + + // Returns the current bounds of the overlay, which is based on visibility. + gfx::Rect CalculateOverlayBounds(); + + // ui::ImplicitAnimationObserver: + void OnImplicitAnimationsScheduled() override; + void OnImplicitAnimationsCompleted() override; + + views::Widget* widget_for_testing(); + ToastOverlayButton* dismiss_button_for_testing(); + void ClickDismissButtonForTesting(const ui::Event& event); + + Delegate* const delegate_; + const base::string16 text_; + const base::Optional<base::string16> dismiss_text_; + std::unique_ptr<views::Widget> overlay_widget_; + std::unique_ptr<ToastOverlayView> overlay_view_; + gfx::Size widget_size_; + + DISALLOW_COPY_AND_ASSIGN(ToastOverlay); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TOAST_TOAST_OVERLAY_H_
diff --git a/ash/common/system/tray/actionable_view.cc b/ash/common/system/tray/actionable_view.cc new file mode 100644 index 0000000..bc97b678 --- /dev/null +++ b/ash/common/system/tray/actionable_view.cc
@@ -0,0 +1,141 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/actionable_view.h" + +#include "ash/common/ash_constants.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_highlight.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" + +namespace ash { + +// static +const char ActionableView::kViewClassName[] = "tray/ActionableView"; + +ActionableView::ActionableView(SystemTrayItem* owner, + TrayPopupInkDropStyle ink_drop_style) + : views::CustomButton(this), + destroyed_(nullptr), + owner_(owner), + ink_drop_style_(ink_drop_style) { + SetFocusBehavior(FocusBehavior::ALWAYS); + set_ink_drop_base_color(kTrayPopupInkDropBaseColor); + set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); + set_has_ink_drop_action_on_click(false); + set_notify_enter_exit_on_child(true); +} + +ActionableView::~ActionableView() { + if (destroyed_) + *destroyed_ = true; +} + +void ActionableView::OnPaintFocus(gfx::Canvas* canvas) { + gfx::RectF rect(GetLocalBounds()); + canvas->DrawSolidFocusRect(rect, kFocusBorderColor, kFocusBorderThickness); +} + +void ActionableView::HandlePerformActionResult(bool action_performed, + const ui::Event& event) { + AnimateInkDrop(action_performed ? views::InkDropState::ACTION_TRIGGERED + : views::InkDropState::HIDDEN, + ui::LocatedEvent::FromIfValid(&event)); +} + +const char* ActionableView::GetClassName() const { + return kViewClassName; +} + +bool ActionableView::OnKeyPressed(const ui::KeyEvent& event) { + if (state() != STATE_DISABLED && event.key_code() == ui::VKEY_SPACE) { + NotifyClick(event); + return true; + } + return CustomButton::OnKeyPressed(event); +} + +void ActionableView::SetAccessibleName(const base::string16& name) { + accessible_name_ = name; +} + +void ActionableView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_BUTTON; + node_data->SetName(accessible_name_); +} + +void ActionableView::OnPaint(gfx::Canvas* canvas) { + CustomButton::OnPaint(canvas); + if (HasFocus()) + OnPaintFocus(canvas); +} + +void ActionableView::OnFocus() { + CustomButton::OnFocus(); + // We render differently when focused. + SchedulePaint(); +} + +void ActionableView::OnBlur() { + CustomButton::OnBlur(); + // We render differently when focused. + SchedulePaint(); +} + +std::unique_ptr<views::InkDrop> ActionableView::CreateInkDrop() { + return TrayPopupUtils::CreateInkDrop(ink_drop_style_, this); +} + +std::unique_ptr<views::InkDropRipple> ActionableView::CreateInkDropRipple() + const { + return TrayPopupUtils::CreateInkDropRipple( + ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent()); +} + +std::unique_ptr<views::InkDropHighlight> +ActionableView::CreateInkDropHighlight() const { + return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this); +} + +std::unique_ptr<views::InkDropMask> ActionableView::CreateInkDropMask() const { + return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this); +} + +void ActionableView::CloseSystemBubble() { + DCHECK(owner_); + owner_->system_tray()->CloseSystemBubble(); +} + +void ActionableView::ButtonPressed(Button* sender, const ui::Event& event) { + bool destroyed = false; + destroyed_ = &destroyed; + const bool action_performed = PerformAction(event); + if (destroyed) + return; + destroyed_ = nullptr; + + HandlePerformActionResult(action_performed, event); +} + +ButtonListenerActionableView::ButtonListenerActionableView( + SystemTrayItem* owner, + TrayPopupInkDropStyle ink_drop_style, + views::ButtonListener* listener) + : ActionableView(owner, ink_drop_style), listener_(listener) {} + +bool ButtonListenerActionableView::PerformAction(const ui::Event& event) { + listener_->ButtonPressed(this, event); + return true; +} + +} // namespace ash
diff --git a/ash/common/system/tray/actionable_view.h b/ash/common/system/tray/actionable_view.h new file mode 100644 index 0000000..91819120 --- /dev/null +++ b/ash/common/system/tray/actionable_view.h
@@ -0,0 +1,115 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_ACTIONABLE_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_ACTIONABLE_VIEW_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/tray_popup_ink_drop_style.h" +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/controls/button/custom_button.h" + +namespace ash { +class SystemTrayItem; + +// A focusable view that performs an action when user clicks on it, or presses +// enter or space when focused. Note that the action is triggered on mouse-up, +// instead of on mouse-down. So if user presses the mouse on the view, then +// moves the mouse out of the view and then releases, then the action will not +// be performed. +// Exported for SystemTray. +// +// TODO(bruthig): Consider removing ActionableView and make clients use +// CustomButtons instead. (See crbug.com/614453) +class ASH_EXPORT ActionableView : public views::ButtonListener, + public views::CustomButton { + public: + static const char kViewClassName[]; + + // The owner is used to close the system tray bubble. Can be null if + // the action will not close the bubble. + ActionableView(SystemTrayItem* owner, TrayPopupInkDropStyle ink_drop_style); + + ~ActionableView() override; + + void SetAccessibleName(const base::string16& name); + const base::string16& accessible_name() const { return accessible_name_; } + + // Closes the system tray bubble. The |owner_| must not be nullptr. + void CloseSystemBubble(); + + protected: + SystemTrayItem* owner() { return owner_; } + + // Draws focus rectangle on the canvas. + // Default implementation draws the focus rectangle with certain inset and + // color. Subclasses can override to change the default settings. + virtual void OnPaintFocus(gfx::Canvas* canvas); + + // Performs an action when user clicks on the view (on mouse-press event), or + // presses a key when this view is in focus. Returns true if the event has + // been handled and an action was performed. Returns false otherwise. + virtual bool PerformAction(const ui::Event& event) = 0; + + // Called after PerformAction() to act upon its result, including showing + // appropriate ink drop ripple. This will not get called if the view is + // destroyed during PerformAction(). Default implementation shows triggered + // ripple if action is performed or hides existing ripple if no action is + // performed. Subclasses can override to change the default behavior. + virtual void HandlePerformActionResult(bool action_performed, + const ui::Event& event); + + // Overridden from views::CustomButton. + const char* GetClassName() const override; + bool OnKeyPressed(const ui::KeyEvent& event) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void OnPaint(gfx::Canvas* canvas) override; + void OnFocus() override; + void OnBlur() override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + + // Overridden from views::ButtonListener. + void ButtonPressed(Button* sender, const ui::Event& event) override; + + private: + // Used by ButtonPressed() to determine whether |this| has been destroyed as a + // result of performing the associated action. This is necessary because in + // the not-destroyed case ButtonPressed() uses member variables. + bool* destroyed_; + + SystemTrayItem* owner_; + + base::string16 accessible_name_; + + // Defines the flavor of ink drop ripple/highlight that should be constructed. + TrayPopupInkDropStyle ink_drop_style_; + + DISALLOW_COPY_AND_ASSIGN(ActionableView); +}; + +// An ActionableView that can be used with a ButtonListener instead of having to +// extend ActionableView and override PerformAction(). +class ASH_EXPORT ButtonListenerActionableView : public ActionableView { + public: + ButtonListenerActionableView(SystemTrayItem* owner, + TrayPopupInkDropStyle ink_drop_style, + views::ButtonListener* listener); + + // ActionableView: + bool PerformAction(const ui::Event& event) override; + + private: + views::ButtonListener* listener_; + + DISALLOW_COPY_AND_ASSIGN(ButtonListenerActionableView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_ACTIONABLE_VIEW_H_
diff --git a/ash/common/system/tray/default_system_tray_delegate.cc b/ash/common/system/tray/default_system_tray_delegate.cc new file mode 100644 index 0000000..91f3a330 --- /dev/null +++ b/ash/common/system/tray/default_system_tray_delegate.cc
@@ -0,0 +1,63 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/default_system_tray_delegate.h" + +#include <string> + +namespace ash { + +DefaultSystemTrayDelegate::DefaultSystemTrayDelegate() + : bluetooth_enabled_(true) {} + +DefaultSystemTrayDelegate::~DefaultSystemTrayDelegate() {} + +LoginStatus DefaultSystemTrayDelegate::GetUserLoginStatus() const { + return LoginStatus::USER; +} + +std::string DefaultSystemTrayDelegate::GetSupervisedUserManager() const { + if (!IsUserSupervised()) + return std::string(); + return "manager@chrome.com"; +} + +bool DefaultSystemTrayDelegate::IsUserSupervised() const { + return GetUserLoginStatus() == LoginStatus::SUPERVISED; +} + +bool DefaultSystemTrayDelegate::ShouldShowSettings() const { + return true; +} + +bool DefaultSystemTrayDelegate::ShouldShowNotificationTray() const { + return true; +} + +void DefaultSystemTrayDelegate::ToggleBluetooth() { + bluetooth_enabled_ = !bluetooth_enabled_; +} + +bool DefaultSystemTrayDelegate::IsBluetoothDiscovering() const { + return false; +} + +bool DefaultSystemTrayDelegate::GetBluetoothAvailable() { + return true; +} + +bool DefaultSystemTrayDelegate::GetBluetoothEnabled() { + return bluetooth_enabled_; +} + +bool DefaultSystemTrayDelegate::GetBluetoothDiscovering() { + return false; +} + +int DefaultSystemTrayDelegate::GetSystemTrayMenuWidth() { + // This is the default width for English languages. + return 300; +} + +} // namespace ash
diff --git a/ash/common/system/tray/default_system_tray_delegate.h b/ash/common/system/tray/default_system_tray_delegate.h new file mode 100644 index 0000000..fc892679 --- /dev/null +++ b/ash/common/system/tray/default_system_tray_delegate.h
@@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_DEFAULT_SYSTEM_TRAY_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_TRAY_DEFAULT_SYSTEM_TRAY_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "base/macros.h" + +namespace ash { + +class ASH_EXPORT DefaultSystemTrayDelegate : public SystemTrayDelegate { + public: + DefaultSystemTrayDelegate(); + ~DefaultSystemTrayDelegate() override; + + // SystemTrayDelegate: + LoginStatus GetUserLoginStatus() const override; + std::string GetSupervisedUserManager() const override; + bool IsUserSupervised() const override; + bool ShouldShowSettings() const override; + bool ShouldShowNotificationTray() const override; + void ToggleBluetooth() override; + bool IsBluetoothDiscovering() const override; + bool GetBluetoothAvailable() override; + bool GetBluetoothEnabled() override; + bool GetBluetoothDiscovering() override; + int GetSystemTrayMenuWidth() override; + + private: + bool bluetooth_enabled_; + + DISALLOW_COPY_AND_ASSIGN(DefaultSystemTrayDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_DEFAULT_SYSTEM_TRAY_DELEGATE_H_
diff --git a/ash/common/system/tray/fixed_sized_image_view.cc b/ash/common/system/tray/fixed_sized_image_view.cc new file mode 100644 index 0000000..5284be0 --- /dev/null +++ b/ash/common/system/tray/fixed_sized_image_view.cc
@@ -0,0 +1,20 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/fixed_sized_image_view.h" + +namespace ash { + +FixedSizedImageView::FixedSizedImageView(int width, int height) + : width_(width), height_(height) {} + +FixedSizedImageView::~FixedSizedImageView() {} + +gfx::Size FixedSizedImageView::GetPreferredSize() const { + gfx::Size size = views::ImageView::GetPreferredSize(); + return gfx::Size(width_ ? width_ : size.width(), + height_ ? height_ : size.height()); +} + +} // namespace ash
diff --git a/ash/common/system/tray/fixed_sized_image_view.h b/ash/common/system/tray/fixed_sized_image_view.h new file mode 100644 index 0000000..7f00613 --- /dev/null +++ b/ash/common/system/tray/fixed_sized_image_view.h
@@ -0,0 +1,32 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_FIXED_SIZED_IMAGE_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_FIXED_SIZED_IMAGE_VIEW_H_ + +#include "base/macros.h" +#include "ui/views/controls/image_view.h" + +namespace ash { + +// An image view with a specified width and height (kTrayPopupDetailsIconWidth). +// If the specified width or height is zero, then the image size is used for +// that dimension. +class FixedSizedImageView : public views::ImageView { + public: + FixedSizedImageView(int width, int height); + ~FixedSizedImageView() override; + + private: + gfx::Size GetPreferredSize() const override; + + int width_; + int height_; + + DISALLOW_COPY_AND_ASSIGN(FixedSizedImageView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_FIXED_SIZED_IMAGE_VIEW_H_
diff --git a/ash/common/system/tray/hover_highlight_view.cc b/ash/common/system/tray/hover_highlight_view.cc new file mode 100644 index 0000000..7eb36f27 --- /dev/null +++ b/ash/common/system/tray/hover_highlight_view.cc
@@ -0,0 +1,396 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/hover_highlight_view.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/resources/grit/ui_resources.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/resources/grit/views_resources.h" + +namespace { + +const gfx::FontList& GetFontList(bool highlight) { + return ui::ResourceBundle::GetSharedInstance().GetFontList( + highlight ? ui::ResourceBundle::BoldFont : ui::ResourceBundle::BaseFont); +} + +} // namespace + +namespace ash { + +HoverHighlightView::HoverHighlightView(ViewClickListener* listener) + : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), + listener_(listener), + highlight_color_(kHoverBackgroundColor) { + set_notify_enter_exit_on_child(true); + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + SetInkDropMode(InkDropHostView::InkDropMode::ON); +} + +HoverHighlightView::~HoverHighlightView() {} + +bool HoverHighlightView::GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const { + if (tooltip_.empty()) + return false; + *tooltip = tooltip_; + return true; +} + +void HoverHighlightView::AddRightIcon(const gfx::ImageSkia& image, + int icon_size) { + DCHECK(!right_view_); + + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + views::ImageView* right_icon = TrayPopupUtils::CreateMainImageView(); + right_icon->SetImage(image); + AddRightView(right_icon); + return; + } + + views::ImageView* right_icon = new FixedSizedImageView(icon_size, icon_size); + right_icon->SetImage(image); + AddRightView(right_icon); +} + +void HoverHighlightView::AddRightView(views::View* view) { + DCHECK(!right_view_); + + right_view_ = view; + right_view_->SetEnabled(enabled()); + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + DCHECK(tri_view_); + tri_view_->AddView(TriView::Container::END, right_view_); + tri_view_->SetContainerVisible(TriView::Container::END, true); + return; + } + DCHECK(box_layout_); + AddChildView(right_view_); +} + +// TODO(tdanderson): Ensure all checkable detailed view rows use this +// mechanism, and share the code that sets the accessible state for +// a checkbox. See crbug.com/652674. +void HoverHighlightView::SetRightViewVisible(bool visible) { + if (!right_view_) + return; + + right_view_->SetVisible(visible); + Layout(); +} + +void HoverHighlightView::AddIconAndLabel(const gfx::ImageSkia& image, + const base::string16& text, + bool highlight) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + DoAddIconAndLabelMd(image, text, + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + return; + } + + box_layout_ = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 3, + kTrayPopupPaddingBetweenItems); + SetLayoutManager(box_layout_); + DoAddIconAndLabel(image, kTrayPopupDetailsIconWidth, text, highlight); +} + +void HoverHighlightView::AddIconAndLabels(const gfx::ImageSkia& image, + const base::string16& text, + const base::string16& sub_text) { + DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); + DoAddIconAndLabelsMd(image, text, + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL, + sub_text); +} + +void HoverHighlightView::AddIconAndLabelCustomSize(const gfx::ImageSkia& image, + const base::string16& text, + bool highlight, + int icon_size, + int indent, + int space_between_items) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + DoAddIconAndLabelMd(image, text, + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + return; + } + + box_layout_ = new views::BoxLayout(views::BoxLayout::kHorizontal, indent, 0, + space_between_items); + SetLayoutManager(box_layout_); + DoAddIconAndLabel(image, icon_size, text, highlight); +} + +void HoverHighlightView::AddIconAndLabelForDefaultView( + const gfx::ImageSkia& image, + const base::string16& text, + bool highlight) { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + DoAddIconAndLabelMd(image, text, + TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + return; + } + + // For non-MD, call AddIconAndLabel() so that |box_layout_| is instantiated + // and installed as the layout manager. + AddIconAndLabel(image, text, highlight); +} + +void HoverHighlightView::DoAddIconAndLabel(const gfx::ImageSkia& image, + int icon_size, + const base::string16& text, + bool highlight) { + DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); + DCHECK(box_layout_); + + views::ImageView* image_view = new FixedSizedImageView(icon_size, 0); + image_view->SetImage(image); + image_view->SetEnabled(enabled()); + AddChildView(image_view); + + text_label_ = new views::Label(text); + text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + text_label_->SetFontList(GetFontList(highlight)); + if (text_default_color_) + text_label_->SetEnabledColor(text_default_color_); + text_label_->SetEnabled(enabled()); + AddChildView(text_label_); + box_layout_->SetFlexForView(text_label_, 1); + + SetAccessibleName(text); +} + +void HoverHighlightView::DoAddIconAndLabelMd( + const gfx::ImageSkia& image, + const base::string16& text, + TrayPopupItemStyle::FontStyle font_style) { + DoAddIconAndLabelsMd(image, text, font_style, base::string16()); +} + +void HoverHighlightView::DoAddIconAndLabelsMd( + const gfx::ImageSkia& image, + const base::string16& text, + TrayPopupItemStyle::FontStyle font_style, + const base::string16& sub_text) { + DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); + + SetLayoutManager(new views::FillLayout); + tri_view_ = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view_); + + left_icon_ = TrayPopupUtils::CreateMainImageView(); + left_icon_->SetImage(image); + left_icon_->SetEnabled(enabled()); + tri_view_->AddView(TriView::Container::START, left_icon_); + + text_label_ = TrayPopupUtils::CreateDefaultLabel(); + text_label_->SetText(text); + text_label_->SetEnabled(enabled()); + TrayPopupItemStyle style(font_style); + style.SetupLabel(text_label_); + + tri_view_->AddView(TriView::Container::CENTER, text_label_); + if (!sub_text.empty()) { + sub_text_label_ = TrayPopupUtils::CreateDefaultLabel(); + sub_text_label_->SetText(sub_text); + TrayPopupItemStyle sub_style(TrayPopupItemStyle::FontStyle::CAPTION); + sub_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); + sub_style.SetupLabel(sub_text_label_); + tri_view_->AddView(TriView::Container::CENTER, sub_text_label_); + } + + tri_view_->SetContainerVisible(TriView::Container::END, false); + + SetAccessibleName(text); +} + +views::Label* HoverHighlightView::AddLabel(const base::string16& text, + gfx::HorizontalAlignment alignment, + bool highlight) { + box_layout_ = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + SetLayoutManager(box_layout_); + text_label_ = new views::Label(text); + int left_margin = kTrayPopupPaddingHorizontal; + int right_margin = kTrayPopupPaddingHorizontal; + if (alignment != gfx::ALIGN_CENTER) { + if (base::i18n::IsRTL()) + right_margin += kTrayPopupDetailsLabelExtraLeftMargin; + else + left_margin += kTrayPopupDetailsLabelExtraLeftMargin; + } + text_label_->SetBorder( + views::CreateEmptyBorder(5, left_margin, 5, right_margin)); + text_label_->SetHorizontalAlignment(alignment); + text_label_->SetFontList(GetFontList(highlight)); + // Do not set alpha value in disable color. It will have issue with elide + // blending filter in disabled state for rendering label text color. + text_label_->SetDisabledColor(SkColorSetARGB(255, 127, 127, 127)); + if (text_default_color_) + text_label_->SetEnabledColor(text_default_color_); + text_label_->SetEnabled(enabled()); + AddChildView(text_label_); + box_layout_->SetFlexForView(text_label_, 1); + + SetAccessibleName(text); + return text_label_; +} + +void HoverHighlightView::AddLabelRowMd(const base::string16& text) { + DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); + + SetLayoutManager(new views::FillLayout); + tri_view_ = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view_); + + text_label_ = TrayPopupUtils::CreateDefaultLabel(); + text_label_->SetText(text); + + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + style.SetupLabel(text_label_); + tri_view_->AddView(TriView::Container::CENTER, text_label_); + + SetAccessibleName(text); +} + +void HoverHighlightView::SetExpandable(bool expandable) { + if (expandable != expandable_) { + expandable_ = expandable; + InvalidateLayout(); + } +} + +void HoverHighlightView::SetHighlight(bool highlight) { + // Do not change the font styling for a highlighted row in material design. + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + return; + + DCHECK(text_label_); + text_label_->SetFontList(GetFontList(highlight)); + text_label_->InvalidateLayout(); +} + +void HoverHighlightView::SetAccessiblityState( + AccessibilityState accessibility_state) { + accessibility_state_ = accessibility_state; + if (accessibility_state_ != AccessibilityState::DEFAULT) + NotifyAccessibilityEvent(ui::AX_EVENT_CHECKED_STATE_CHANGED, true); +} + +void HoverHighlightView::SetHoverHighlight(bool hover) { + // We do not show any hover effects for material design. + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + return; + + if (!enabled() && hover) + return; + if (hover_ == hover) + return; + hover_ = hover; + if (!text_label_) + return; + if (hover_ && text_highlight_color_) + text_label_->SetEnabledColor(text_highlight_color_); + if (!hover_ && text_default_color_) + text_label_->SetEnabledColor(text_default_color_); + SchedulePaint(); +} + +bool HoverHighlightView::PerformAction(const ui::Event& event) { + if (!listener_) + return false; + listener_->OnViewClicked(this); + return true; +} + +void HoverHighlightView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + ActionableView::GetAccessibleNodeData(node_data); + + if (accessibility_state_ == AccessibilityState::CHECKED_CHECKBOX || + accessibility_state_ == AccessibilityState::UNCHECKED_CHECKBOX) { + node_data->role = ui::AX_ROLE_CHECK_BOX; + } + + if (accessibility_state_ == AccessibilityState::CHECKED_CHECKBOX) + node_data->AddStateFlag(ui::AX_STATE_CHECKED); +} + +gfx::Size HoverHighlightView::GetPreferredSize() const { + gfx::Size size = ActionableView::GetPreferredSize(); + + if (custom_height_) + size.set_height(custom_height_); + else if (!expandable_ || size.height() < kTrayPopupItemMinHeight) + size.set_height(kTrayPopupItemMinHeight); + + return size; +} + +int HoverHighlightView::GetHeightForWidth(int width) const { + return GetPreferredSize().height(); +} + +void HoverHighlightView::OnMouseEntered(const ui::MouseEvent& event) { + SetHoverHighlight(true); +} + +void HoverHighlightView::OnMouseExited(const ui::MouseEvent& event) { + SetHoverHighlight(false); +} + +void HoverHighlightView::OnGestureEvent(ui::GestureEvent* event) { + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetHoverHighlight(true); + } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || + event->type() == ui::ET_GESTURE_TAP) { + SetHoverHighlight(false); + } + ActionableView::OnGestureEvent(event); +} + +void HoverHighlightView::OnBoundsChanged(const gfx::Rect& previous_bounds) { + SetHoverHighlight(IsMouseHovered()); +} + +void HoverHighlightView::OnEnabledChanged() { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) { + if (left_icon_) + left_icon_->SetEnabled(enabled()); + if (text_label_) + text_label_->SetEnabled(enabled()); + if (right_view_) + right_view_->SetEnabled(enabled()); + } else { + if (!enabled()) + SetHoverHighlight(false); + for (int i = 0; i < child_count(); ++i) + child_at(i)->SetEnabled(enabled()); + } +} + +void HoverHighlightView::OnPaintBackground(gfx::Canvas* canvas) { + canvas->DrawColor(hover_ ? highlight_color_ : default_color_); +} + +void HoverHighlightView::OnFocus() { + ScrollRectToVisible(gfx::Rect(gfx::Point(), size())); + ActionableView::OnFocus(); +} + +} // namespace ash
diff --git a/ash/common/system/tray/hover_highlight_view.h b/ash/common/system/tray/hover_highlight_view.h new file mode 100644 index 0000000..87033b6 --- /dev/null +++ b/ash/common/system/tray/hover_highlight_view.h
@@ -0,0 +1,195 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_ + +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "base/macros.h" +#include "ui/gfx/font.h" +#include "ui/gfx/text_constants.h" + +namespace views { +class ImageView; +class Label; +class BoxLayout; +} + +namespace ash { +class TriView; +class ViewClickListener; + +// A view that changes background color on hover, and triggers a callback in the +// associated ViewClickListener on click. The view can also be forced to +// maintain a fixed height. +class HoverHighlightView : public ActionableView { + public: + enum class AccessibilityState { + // The default accessibility view. + DEFAULT, + // This view is a checked checkbox. + CHECKED_CHECKBOX, + // This view is an unchecked checkbox. + UNCHECKED_CHECKBOX + }; + + explicit HoverHighlightView(ViewClickListener* listener); + ~HoverHighlightView() override; + + // views::View + bool GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const override; + + // Convenience function for adding an icon and a label. This also sets the + // accessible name. Primarily used for scrollable rows in detailed views. + void AddIconAndLabel(const gfx::ImageSkia& image, + const base::string16& text, + bool highlight); + + // Convenience function for adding an icon, a main label, and a sub label. + // This also sets the accessible name besed on the main label. Used for + // scrollable rows in detailed views in material design. + void AddIconAndLabels(const gfx::ImageSkia& image, + const base::string16& text, + const base::string16& sub_text); + + // Convenience function for adding an icon and a label. This also sets the + // accessible name. This method allows the indent and spacing between elements + // to be set by the caller. |icon_size| is the size of the icon. |indent| is + // the distance between the edges of the view and the icons, and + // |space_between_items| is the minimum distance between any two child views. + // All distances are in DP. Primarily used for scrollable rows in detailed + // views. + void AddIconAndLabelCustomSize(const gfx::ImageSkia& image, + const base::string16& text, + bool highlight, + int icon_size, + int indent, + int space_between_items); + + // A convenience function for adding an icon and label for a system menu + // default view row. + void AddIconAndLabelForDefaultView(const gfx::ImageSkia& image, + const base::string16& text, + bool highlight); + + // Convenience function for adding a label with padding on the left for a + // blank icon. This also sets the accessible name. Returns label after + // parenting it. + views::Label* AddLabel(const base::string16& text, + gfx::HorizontalAlignment alignment, + bool highlight); + + // Adds a row containing only a text label, inset on the left by the + // horizontal space that would normally be occupied by an icon. + void AddLabelRowMd(const base::string16& text); + + // Add an optional right icon to an already established view (call one of + // the other Add* functions first). |icon_size| is the size of the icon in DP. + void AddRightIcon(const gfx::ImageSkia& image, int icon_size); + + // Add an optional right view to an already established view (call one of + // the other Add* functions first). + void AddRightView(views::View* view); + + // Hide or show the right view. + void SetRightViewVisible(bool visible); + + // Allows view to expand its height. + // Size of unexapandable view is fixed and equals to kTrayPopupItemHeight. + void SetExpandable(bool expandable); + + // Enables or disable highlighting on the label, where a highlighted label + // just uses a bold font. + void SetHighlight(bool hightlight); + + // Set a custom height for the view. A value of 0 means that no custom height + // is set. + void set_custom_height(int custom_height) { custom_height_ = custom_height; } + + // Changes the view's current accessibility state. This will fire an + // accessibility event if needed. + void SetAccessiblityState(AccessibilityState accessibility_state); + + void set_highlight_color(SkColor color) { highlight_color_ = color; } + void set_default_color(SkColor color) { default_color_ = color; } + void set_text_highlight_color(SkColor c) { text_highlight_color_ = c; } + void set_text_default_color(SkColor color) { text_default_color_ = color; } + + views::Label* text_label() { return text_label_; } + views::Label* sub_text_label() { return sub_text_label_; } + + bool hover() const { return hover_; } + + void set_tooltip(const base::string16& tooltip) { tooltip_ = tooltip; } + + protected: + // Overridden from views::View. + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + // Sets the highlighted color on a text label if |hover| is set. + void SetHoverHighlight(bool hover); + + TriView* tri_view() { return tri_view_; } + + private: + // Actually adds the icon and label but does not set the layout manager. + // Not used in material design. + void DoAddIconAndLabel(const gfx::ImageSkia& image, + int icon_size, + const base::string16& text, + bool highlight); + + // Adds the image and label to the row with the label being styled using + // |font_style|. Only used in material design. + void DoAddIconAndLabelMd(const gfx::ImageSkia& image, + const base::string16& text, + TrayPopupItemStyle::FontStyle font_style); + + // Adds the image, main label and sub label to the row with the main label + // being styled using |font_style| and the sub label being styled using + // FontStyle::CAPTION and ColorStyle::INACTIVE. Only used in material design. + void DoAddIconAndLabelsMd(const gfx::ImageSkia& image, + const base::string16& text, + TrayPopupItemStyle::FontStyle font_style, + const base::string16& sub_text); + + // Overridden from ActionableView: + bool PerformAction(const ui::Event& event) override; + + // Overridden from views::View. + gfx::Size GetPreferredSize() const override; + int GetHeightForWidth(int width) const override; + void OnMouseEntered(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + void OnBoundsChanged(const gfx::Rect& previous_bounds) override; + void OnEnabledChanged() override; + void OnPaintBackground(gfx::Canvas* canvas) override; + void OnFocus() override; + + ViewClickListener* listener_ = nullptr; + views::Label* text_label_ = nullptr; + views::Label* sub_text_label_ = nullptr; + views::BoxLayout* box_layout_ = nullptr; // Not used in material design. + views::ImageView* left_icon_ = nullptr; + views::View* right_view_ = nullptr; + TriView* tri_view_ = nullptr; // Only used in material design. + SkColor highlight_color_ = 0; // Not used in material design. + SkColor default_color_ = 0; + SkColor text_highlight_color_ = 0; // Not used in material design. + SkColor text_default_color_ = 0; // Not used in material design. + bool hover_ = false; // Not used in material design. + bool expandable_ = false; + int custom_height_ = 0; // Not used in material design. + AccessibilityState accessibility_state_ = AccessibilityState::DEFAULT; + base::string16 tooltip_; + + DISALLOW_COPY_AND_ASSIGN(HoverHighlightView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_
diff --git a/ash/common/system/tray/ime_info.cc b/ash/common/system/tray/ime_info.cc new file mode 100644 index 0000000..fc1966d --- /dev/null +++ b/ash/common/system/tray/ime_info.cc
@@ -0,0 +1,19 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/ime_info.h" + +namespace ash { + +IMEInfo::IMEInfo() : selected(false), third_party(false) {} + +IMEInfo::IMEInfo(const IMEInfo& other) = default; + +IMEInfo::~IMEInfo() {} + +IMEPropertyInfo::IMEPropertyInfo() : selected(false) {} + +IMEPropertyInfo::~IMEPropertyInfo() {} + +} // namespace ash
diff --git a/ash/common/system/tray/ime_info.h b/ash/common/system/tray/ime_info.h new file mode 100644 index 0000000..d250fd66 --- /dev/null +++ b/ash/common/system/tray/ime_info.h
@@ -0,0 +1,64 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_IME_INFO_H_ +#define ASH_COMMON_SYSTEM_TRAY_IME_INFO_H_ + +#include <string> +#include <vector> + +#include "ash/ash_export.h" +#include "base/strings/string16.h" + +namespace ash { + +struct ASH_EXPORT IMEInfo { + IMEInfo(); + IMEInfo(const IMEInfo& other); + ~IMEInfo(); + + // True if the IME the current IME. + bool selected; + + // True if the IME is a third-party extension. + bool third_party; + + // ID that identifies the IME (e.g., "t:latn-post", "pinyin", "hangul"). + std::string id; + + // Long name of the IME, which is used to specify the user-visible name. + base::string16 name; + + // Medium name of the IME, which is same with short name in most cases, unless + // find in a table for medium length names. + base::string16 medium_name; + + // Indicator of the IME (e.g., "US"). If indicator is empty, use the first two + // character in its preferred keyboard layout or language code (e.g., "ko", + // "ja", "en-US"). + base::string16 short_name; +}; + +using IMEInfoList = std::vector<IMEInfo>; + +struct ASH_EXPORT IMEPropertyInfo { + IMEPropertyInfo(); + ~IMEPropertyInfo(); + + // True if the property is a selection item. + bool selected; + + // The key which identifies the property, e.g. "InputMode.HalfWidthKatakana". + std::string key; + + // The description of the property, e.g. "Switch to full punctuation mode", + // "Hiragana". + base::string16 name; +}; + +using IMEPropertyInfoList = std::vector<IMEPropertyInfo>; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_IME_INFO_H_
diff --git a/ash/common/system/tray/label_tray_view.cc b/ash/common/system/tray/label_tray_view.cc new file mode 100644 index 0000000..0f2c943 --- /dev/null +++ b/ash/common/system/tray/label_tray_view.cc
@@ -0,0 +1,99 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/label_tray_view.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/font.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +namespace { + +// Maps a non-MD PNG resource id to its corresponding MD vector icon. +// TODO(tdanderson): Remove this once material design is enabled by +// default. See crbug.com/614453. +const gfx::VectorIcon& ResourceIdToVectorIcon(int resource_id) { + switch (resource_id) { + case IDR_AURA_UBER_TRAY_ENTERPRISE: + return kSystemMenuBusinessIcon; + case IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT: + return kSystemMenuTimerIcon; + case IDR_AURA_UBER_TRAY_CHILD_USER: + return kSystemMenuChildUserIcon; + case IDR_AURA_UBER_TRAY_SUPERVISED_USER: + return kSystemMenuSupervisedUserIcon; + default: + NOTREACHED(); + break; + } + return gfx::kNoneIcon; +} + +} // namespace + +LabelTrayView::LabelTrayView(ViewClickListener* click_listener, + int icon_resource_id) + : click_listener_(click_listener), icon_resource_id_(icon_resource_id) { + SetLayoutManager(new views::FillLayout()); + SetVisible(false); +} + +LabelTrayView::~LabelTrayView() {} + +void LabelTrayView::SetMessage(const base::string16& message) { + if (message_ == message) + return; + + message_ = message; + RemoveAllChildViews(true); + + if (!message_.empty()) { + AddChildView(CreateChildView(message_)); + SetVisible(true); + } else { + SetVisible(false); + } +} + +views::View* LabelTrayView::CreateChildView( + const base::string16& message) const { + HoverHighlightView* child = new HoverHighlightView(click_listener_); + if (icon_resource_id_) { + const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial(); + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + gfx::ImageSkia icon = + use_md ? gfx::CreateVectorIcon( + ResourceIdToVectorIcon(icon_resource_id_), kMenuIconColor) + : *rb.GetImageSkiaNamed(icon_resource_id_); + child->AddIconAndLabelForDefaultView(icon, message, false /* highlight */); + child->text_label()->SetMultiLine(true); + if (!use_md) { + child->SetBorder(views::CreateEmptyBorder( + 0, kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingHorizontal)); + child->text_label()->SizeToFit(kTrayNotificationContentsWidth); + } + } else { + child->AddLabel(message, gfx::ALIGN_LEFT, false /* highlight */); + child->text_label()->SetMultiLine(true); + child->text_label()->SizeToFit(kTrayNotificationContentsWidth + + kNotificationIconWidth); + } + child->text_label()->SetAllowCharacterBreak(true); + child->SetExpandable(true); + child->SetVisible(true); + return child; +} + +} // namespace ash
diff --git a/ash/common/system/tray/label_tray_view.h b/ash/common/system/tray/label_tray_view.h new file mode 100644 index 0000000..f0781cbe --- /dev/null +++ b/ash/common/system/tray/label_tray_view.h
@@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_LABEL_TRAY_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_LABEL_TRAY_VIEW_H_ + +#include "base/macros.h" +#include "base/strings/string16.h" +#include "ui/views/view.h" + +namespace ash { + +class ViewClickListener; + +// View for simple information in tray. Automatically hides when message is +// empty. Supports multiline messages. + +class LabelTrayView : public views::View { + public: + LabelTrayView(ViewClickListener* click_listener, int icon_resource_id); + ~LabelTrayView() override; + void SetMessage(const base::string16& message); + + private: + views::View* CreateChildView(const base::string16& message) const; + + ViewClickListener* click_listener_; + int icon_resource_id_; + base::string16 message_; + + DISALLOW_COPY_AND_ASSIGN(LabelTrayView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_LABEL_TRAY_VIEW_H_
diff --git a/ash/common/system/tray/size_range_layout.cc b/ash/common/system/tray/size_range_layout.cc new file mode 100644 index 0000000..7405490 --- /dev/null +++ b/ash/common/system/tray/size_range_layout.cc
@@ -0,0 +1,97 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <limits> + +#include "ash/common/system/tray/size_range_layout.h" + +#include "base/logging.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +// static + +const int SizeRangeLayout::kAbsoluteMinSize = 0; +const int SizeRangeLayout::kAbsoluteMaxSize = std::numeric_limits<int>::max(); + +// Non static + +SizeRangeLayout::SizeRangeLayout() + : SizeRangeLayout(gfx::Size(kAbsoluteMinSize, kAbsoluteMinSize), + gfx::Size(kAbsoluteMaxSize, kAbsoluteMaxSize)) {} + +SizeRangeLayout::SizeRangeLayout(const gfx::Size& min_size, + const gfx::Size& max_size) + : layout_manager_(new views::FillLayout()), + min_size_(gfx::Size(kAbsoluteMinSize, kAbsoluteMinSize)), + max_size_(gfx::Size(kAbsoluteMaxSize, kAbsoluteMaxSize)) { + SetMinSize(min_size); + SetMaxSize(max_size); +} + +SizeRangeLayout::~SizeRangeLayout() {} + +void SizeRangeLayout::SetSize(const gfx::Size& size) { + SetMinSize(size); + SetMaxSize(size); +} + +void SizeRangeLayout::SetMinSize(const gfx::Size& size) { + min_size_ = size; + min_size_.SetToMax(gfx::Size()); + max_size_.SetToMax(min_size_); +} + +void SizeRangeLayout::SetMaxSize(const gfx::Size& size) { + max_size_ = size; + max_size_.SetToMax(gfx::Size()); + min_size_.SetToMin(max_size_); +} + +void SizeRangeLayout::SetLayoutManager( + std::unique_ptr<LayoutManager> layout_manager) { + DCHECK(layout_manager_); + layout_manager_ = std::move(layout_manager); + layout_manager_->Installed(host_); +} + +void SizeRangeLayout::Installed(views::View* host) { + DCHECK(!host_); + host_ = host; + layout_manager_->Installed(host); +} + +void SizeRangeLayout::Layout(views::View* host) { + layout_manager_->Layout(host); +} + +gfx::Size SizeRangeLayout::GetPreferredSize(const views::View* host) const { + gfx::Size preferred_size = layout_manager_->GetPreferredSize(host); + ClampSizeToRange(&preferred_size); + return preferred_size; +} + +int SizeRangeLayout::GetPreferredHeightForWidth(const views::View* host, + int width) const { + const int height = layout_manager_->GetPreferredHeightForWidth(host, width); + gfx::Size size(0, height); + ClampSizeToRange(&size); + return size.height(); +} + +void SizeRangeLayout::ViewAdded(views::View* host, views::View* view) { + layout_manager_->ViewAdded(host, view); +} + +void SizeRangeLayout::ViewRemoved(views::View* host, views::View* view) { + layout_manager_->ViewRemoved(host, view); +} + +void SizeRangeLayout::ClampSizeToRange(gfx::Size* size) const { + size->SetToMax(min_size_); + size->SetToMin(max_size_); +} + +} // namespace ash
diff --git a/ash/common/system/tray/size_range_layout.h b/ash/common/system/tray/size_range_layout.h new file mode 100644 index 0000000..f8bd34a2 --- /dev/null +++ b/ash/common/system/tray/size_range_layout.h
@@ -0,0 +1,116 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_ +#define ASH_COMMON_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/layout/layout_manager.h" + +namespace views { +class View; +} // namespace views + +namespace ash { + +// A LayoutManager adapter that allows clients to specify a minimum and/or a +// maximum preferred size. The actual layout will be delegated to the +// LayoutManager owned by this. i.e. |this| can be used to override the +// preferred size returned by a View. +// +// By default the SizeRangeLayout is configured to own a FillLayout but this can +// be overridden with SetLayoutManager(). +// +// Example use case : +// +// Suppose you wanted a Label to take up a specific size of (50, 50) even +// though the label's preferred size was (25, 25). +// +// Example code: +// +// Label* label = new Label(kSomeDummyText); +// View* container = new View(); +// container->AddChildView(label); +// SizeRangeLayout* layout = new SizeRangeLayout(); +// layout->SetSize(gfx::Size(50, 50)); +// container->SetLayoutManager(layout); +// +class ASH_EXPORT SizeRangeLayout : public views::LayoutManager { + public: + // Create a layout with no minimum or maximum preferred size. + SizeRangeLayout(); + + // Create a layout with the given minimum and maximum preferred sizes. If + // |max_size| is smaller than |min_size| then |min_size| will be set to the + // smaller |max_size| value. + SizeRangeLayout(const gfx::Size& min_size, const gfx::Size& max_size); + + ~SizeRangeLayout() override; + + // The absolute minimum possible width/height. Use this with SetMinSize() to + // effectively unset the minimum preferred size. + static const int kAbsoluteMinSize; + + // Tthe absolute maximum possible width/height. Use this with SetMaxSize() to + // effectively unset the maximum preferred size. + static const int kAbsoluteMaxSize; + + // Sets both the minimum and maximum preferred size. + void SetSize(const gfx::Size& size); + void SetSize(int width, int height); + + // Set the minimum preferred size that GetPreferredSize() will round up to. If + // |size| is larger than the current |max_size_| then |max_size_| will set to + // |size| as well. + void SetMinSize(const gfx::Size& size); + void SetMinSize(int width, int height); + + gfx::Size min_size() const { return min_size_; } + + // Set the minimum preferred size that GetPreferredSize() will round down to. + // If |size| is smaller than the current |min_size_| then |min_size_| will set + // to |size| as well. + void SetMaxSize(const gfx::Size& size); + + // Sets the layout manager that actually performs the layout once the bounds + // have been defined. + void SetLayoutManager(std::unique_ptr<LayoutManager> layout_manager); + + // LayoutManager: + void Installed(views::View* host) override; + void Layout(views::View* host) override; + gfx::Size GetPreferredSize(const views::View* host) const override; + int GetPreferredHeightForWidth(const views::View* host, + int width) const override; + void ViewAdded(views::View* host, views::View* view) override; + void ViewRemoved(views::View* host, views::View* view) override; + + private: + friend class SizeRangeLayoutTest; + + // Clamps |size| to be within the minimum and maximum preferred sizes. + void ClampSizeToRange(gfx::Size* size) const; + + // The host View that this has been installed on. + views::View* host_ = nullptr; + + // The layout manager that actually performs the layout. + std::unique_ptr<views::LayoutManager> layout_manager_; + + // The minimum preferred size. + gfx::Size min_size_; + + // The maximum preferred size. + gfx::Size max_size_; + + DISALLOW_COPY_AND_ASSIGN(SizeRangeLayout); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_
diff --git a/ash/common/system/tray/size_range_layout_unittest.cc b/ash/common/system/tray/size_range_layout_unittest.cc new file mode 100644 index 0000000..b04ce58 --- /dev/null +++ b/ash/common/system/tray/size_range_layout_unittest.cc
@@ -0,0 +1,189 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/size_range_layout.h" +#include "base/memory/ptr_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/test/test_layout_manager.h" +#include "ui/views/view.h" + +namespace ash { + +class SizeRangeLayoutTest : public testing::Test { + public: + SizeRangeLayoutTest(); + + // Wrapper function to access the minimum preferred size of |layout|. + gfx::Size GetMinSize(const SizeRangeLayout* layout) const; + + // Wrapper function to access the maximum preferred size of |layout|. + gfx::Size GetMaxSize(const SizeRangeLayout* layout) const; + + protected: + views::View host_; + + const gfx::Size kAbsoluteMinSize; + const gfx::Size kAbsoluteMaxSize; + + private: + DISALLOW_COPY_AND_ASSIGN(SizeRangeLayoutTest); +}; + +SizeRangeLayoutTest::SizeRangeLayoutTest() + : kAbsoluteMinSize(SizeRangeLayout::kAbsoluteMinSize, + SizeRangeLayout::kAbsoluteMinSize), + kAbsoluteMaxSize(SizeRangeLayout::kAbsoluteMaxSize, + SizeRangeLayout::kAbsoluteMaxSize) {} + +gfx::Size SizeRangeLayoutTest::GetMinSize(const SizeRangeLayout* layout) const { + return layout->min_size_; +} + +gfx::Size SizeRangeLayoutTest::GetMaxSize(const SizeRangeLayout* layout) const { + return layout->max_size_; +} + +TEST_F(SizeRangeLayoutTest, SizeRangeForDefaultConstruction) { + SizeRangeLayout layout; + EXPECT_EQ(kAbsoluteMinSize, GetMinSize(&layout)); + EXPECT_EQ(kAbsoluteMaxSize, GetMaxSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, SizeRangeForExplicitConstruction) { + const gfx::Size kSmallSize = gfx::Size(13, 14); + const gfx::Size kLargeSize = gfx::Size(25, 26); + + SizeRangeLayout layout(kSmallSize, kLargeSize); + EXPECT_EQ(kSmallSize, GetMinSize(&layout)); + EXPECT_EQ(kLargeSize, GetMaxSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, InvalidMinSizeForExplicitConstruction) { + const gfx::Size kInvalidSmallSize(-1, 2); + const gfx::Size kExpectedMinSize(0, 2); + + SizeRangeLayout layout(kInvalidSmallSize, kAbsoluteMaxSize); + EXPECT_EQ(kExpectedMinSize, GetMinSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, InvalidMaxSizeForExplicitConstruction) { + const gfx::Size kInvalidSmallSize(-1, 2); + const gfx::Size kExpectedMinSize(0, 2); + + SizeRangeLayout layout(kInvalidSmallSize, kAbsoluteMaxSize); + EXPECT_EQ(kExpectedMinSize, GetMinSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, MaxSizeSmallerThanMinSizeConstruction) { + const gfx::Size kMinSize(10, 11); + const gfx::Size kMaxSize(5, 6); + + SizeRangeLayout layout(kMinSize, kMaxSize); + EXPECT_EQ(kMaxSize, GetMinSize(&layout)); + EXPECT_EQ(kMaxSize, GetMaxSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, SizeRangeForExplicitSetSize) { + const gfx::Size kSize = gfx::Size(13, 14); + + SizeRangeLayout layout; + EXPECT_NE(kSize, GetMinSize(&layout)); + EXPECT_NE(kSize, GetMaxSize(&layout)); + + layout.SetSize(kSize); + EXPECT_EQ(kSize, GetMinSize(&layout)); + EXPECT_EQ(kSize, GetMaxSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, InvalidSizeRangesForExplicitSetSize) { + const gfx::Size kInvalidSize(-7, 8); + const gfx::Size kExpectedSize(0, 8); + + SizeRangeLayout layout; + layout.SetSize(kInvalidSize); + EXPECT_EQ(kExpectedSize, GetMinSize(&layout)); + EXPECT_EQ(kExpectedSize, GetMaxSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, InternalLayoutManagerPreferredSizeIsUsed) { + const gfx::Size kSize(7, 8); + std::unique_ptr<views::test::TestLayoutManager> child_layout = + base::MakeUnique<views::test::TestLayoutManager>(); + child_layout->set_preferred_size(kSize); + + SizeRangeLayout layout; + EXPECT_NE(kSize, layout.GetPreferredSize(&host_)); + + layout.SetLayoutManager(std::move(child_layout)); + EXPECT_EQ(kSize, layout.GetPreferredSize(&host_)); +} + +TEST_F(SizeRangeLayoutTest, SmallPreferredSizeIsClamped) { + const gfx::Size kMinSize(10, 10); + const gfx::Size kMaxSize(20, 20); + const gfx::Size kLayoutPreferredSize(5, 5); + std::unique_ptr<views::test::TestLayoutManager> child_layout = + base::MakeUnique<views::test::TestLayoutManager>(); + child_layout->set_preferred_size(kLayoutPreferredSize); + + SizeRangeLayout layout; + layout.SetLayoutManager(std::move(child_layout)); + layout.SetMinSize(kMinSize); + layout.SetMaxSize(kMaxSize); + EXPECT_EQ(kMinSize, layout.GetPreferredSize(&host_)); +} + +TEST_F(SizeRangeLayoutTest, LargePreferredSizeIsClamped) { + const gfx::Size kMinSize(10, 10); + const gfx::Size kMaxSize(20, 20); + const gfx::Size kLayoutPreferredSize(25, 25); + std::unique_ptr<views::test::TestLayoutManager> child_layout = + base::MakeUnique<views::test::TestLayoutManager>(); + child_layout->set_preferred_size(kLayoutPreferredSize); + + SizeRangeLayout layout; + layout.SetLayoutManager(std::move(child_layout)); + layout.SetMinSize(kMinSize); + layout.SetMaxSize(kMaxSize); + EXPECT_EQ(kMaxSize, layout.GetPreferredSize(&host_)); +} + +TEST_F(SizeRangeLayoutTest, MaxSizeLargerThanMinSizeUpdatesMinSize) { + const gfx::Size kMinSize(10, 10); + const gfx::Size kMaxSize(5, 5); + + SizeRangeLayout layout; + layout.SetMinSize(kMinSize); + EXPECT_EQ(kMinSize, GetMinSize(&layout)); + layout.SetMaxSize(kMaxSize); + EXPECT_EQ(kMaxSize, GetMinSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, MinSizeSmallerThanMaxSizeUpdatesMaxSize) { + const gfx::Size kMinSize(10, 10); + const gfx::Size kMaxSize(5, 5); + + SizeRangeLayout layout; + layout.SetMaxSize(kMaxSize); + EXPECT_EQ(kMaxSize, GetMaxSize(&layout)); + layout.SetMinSize(kMinSize); + EXPECT_EQ(kMinSize, GetMaxSize(&layout)); +} + +TEST_F(SizeRangeLayoutTest, + InternalLayoutManagerPreferredHeightForWidthIsUsed) { + const int kWidth = 5; + const int kHeight = 9; + std::unique_ptr<views::test::TestLayoutManager> child_layout = + base::MakeUnique<views::test::TestLayoutManager>(); + child_layout->set_preferred_height_for_width(kHeight); + + SizeRangeLayout layout; + EXPECT_NE(kHeight, layout.GetPreferredHeightForWidth(&host_, kWidth)); + + layout.SetLayoutManager(std::move(child_layout)); + EXPECT_EQ(kHeight, layout.GetPreferredHeightForWidth(&host_, kWidth)); +} + +} // namespace ash
diff --git a/ash/common/system/tray/special_popup_row.cc b/ash/common/system/tray/special_popup_row.cc new file mode 100644 index 0000000..7332fb36 --- /dev/null +++ b/ash/common/system/tray/special_popup_row.cc
@@ -0,0 +1,155 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/special_popup_row.h" + +#include "ash/common/ash_constants.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/throbber_view.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_header_button.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/custom_button.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/painter.h" + +namespace ash { +namespace { + +const int kIconPaddingLeft = 5; +const int kSeparatorInset = 10; +const int kSpecialPopupRowHeight = 55; +const int kBorderHeight = 1; +const SkColor kBorderColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); + +views::View* CreateViewContainer() { + views::View* view = new views::View; + view->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); + view->SetBorder(views::CreateEmptyBorder(4, 0, 4, 5)); + return view; +} + +} // namespace + +SpecialPopupRow::SpecialPopupRow() + : content_(nullptr), views_after_content_container_(nullptr) { + DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); + set_background( + views::Background::CreateSolidBackground(kHeaderBackgroundColor)); + SetBorder( + views::CreateSolidSidedBorder(kBorderHeight, 0, 0, 0, kBorderColor)); +} + +SpecialPopupRow::~SpecialPopupRow() {} + +void SpecialPopupRow::SetTextLabel(int string_id, ViewClickListener* listener) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + HoverHighlightView* container = new HoverHighlightView(listener); + container->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kHorizontal, 0, 3, kIconPaddingLeft)); + + container->set_highlight_color(SkColorSetARGB(0, 0, 0, 0)); + container->set_default_color(SkColorSetARGB(0, 0, 0, 0)); + container->set_text_highlight_color(kHeaderTextColorHover); + container->set_text_default_color(kHeaderTextColorNormal); + + container->AddIconAndLabel( + *rb.GetImageNamed(IDR_AURA_UBER_TRAY_LESS).ToImageSkia(), + rb.GetLocalizedString(string_id), true /* highlight */); + + container->SetBorder( + views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); + + container->SetAccessibleName( + rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_PREVIOUS_MENU)); + SetContent(container); +} + +void SpecialPopupRow::SetContent(views::View* view) { + CHECK(!content_); + views::BoxLayout* box_layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + SetLayoutManager(box_layout); + content_ = view; + AddChildViewAt(content_, 0); +} + +void SpecialPopupRow::AddViewToTitleRow(views::View* view) { + AddViewAfterContent(view); +} + +void SpecialPopupRow::AddViewToRowNonMd(views::View* view, bool add_separator) { + AddViewAfterContent(view, add_separator); +} + +gfx::Size SpecialPopupRow::GetPreferredSize() const { + gfx::Size size = views::View::GetPreferredSize(); + size.set_height(kSpecialPopupRowHeight); + return size; +} + +int SpecialPopupRow::GetHeightForWidth(int width) const { + return kSpecialPopupRowHeight; +} + +void SpecialPopupRow::Layout() { + views::View::Layout(); + + const gfx::Rect content_bounds = GetContentsBounds(); + if (content_bounds.IsEmpty()) + return; + + if (!views_after_content_container_) { + content_->SetBoundsRect(GetContentsBounds()); + return; + } + + gfx::Rect bounds(views_after_content_container_->GetPreferredSize()); + bounds.set_height(content_bounds.height()); + + gfx::Rect container_bounds = content_bounds; + container_bounds.ClampToCenteredSize(bounds.size()); + container_bounds.set_x(content_bounds.width() - container_bounds.width()); + views_after_content_container_->SetBoundsRect(container_bounds); + + bounds = content_->bounds(); + bounds.set_width(views_after_content_container_->x()); + content_->SetBoundsRect(bounds); +} + +void SpecialPopupRow::AddViewAfterContent(views::View* view) { + AddViewAfterContent(view, false); +} + +void SpecialPopupRow::AddViewAfterContent(views::View* view, + bool add_separator) { + if (!views_after_content_container_) { + views_after_content_container_ = CreateViewContainer(); + AddChildView(views_after_content_container_); + } + + if (add_separator) { + views::Separator* separator = new views::Separator(); + separator->SetColor(ash::kBorderDarkColor); + separator->SetBorder( + views::CreateEmptyBorder(kSeparatorInset, 0, kSeparatorInset, 0)); + views_after_content_container_->AddChildView(separator); + } + + views_after_content_container_->AddChildView(view); +} + +} // namespace ash
diff --git a/ash/common/system/tray/special_popup_row.h b/ash/common/system/tray/special_popup_row.h new file mode 100644 index 0000000..29d66b4 --- /dev/null +++ b/ash/common/system/tray/special_popup_row.h
@@ -0,0 +1,67 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SPECIAL_POPUP_ROW_H_ +#define ASH_COMMON_SYSTEM_TRAY_SPECIAL_POPUP_ROW_H_ + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/macros.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/view.h" + +namespace ash { +class ViewClickListener; + +// Not used in material design. This class represents the bottom row of +// detailed views and the bottom row of the system menu (date, help, power, +// and lock). This row has a fixed height. +// TODO(tdanderson): Remove this class when material design is enabled by +// default. See crbug.com/614453. +class ASH_EXPORT SpecialPopupRow : public views::View { + public: + SpecialPopupRow(); + ~SpecialPopupRow() override; + + // Creates a text label corresponding to |string_id| and sets it as the + // content of this row. + void SetTextLabel(int string_id, ViewClickListener* listener); + + // Sets |content_| to be |view| and adds |content_| as a child view of this + // row. This should only be called once, upon initialization of the row. + void SetContent(views::View* view); + + // Adds |view| after this row's content. + void AddViewToTitleRow(views::View* view); + + // Adds |view| after this row's content, optionally with a separator. Only + // used for non-MD. + void AddViewToRowNonMd(views::View* view, bool add_separator); + + views::View* content() const { return content_; } + + private: + // views::View: + gfx::Size GetPreferredSize() const override; + int GetHeightForWidth(int width) const override; + void Layout() override; + + // Used to add views to |views_after_content_container_|, respectively. Views + // are added in a left-to-right order. + void AddViewAfterContent(views::View* view); + void AddViewAfterContent(views::View* view, bool add_separator); + + // The main content of this row, typically a label. + views::View* content_; + + // The container for the views positioned after |content_|. + views::View* views_after_content_container_; + + DISALLOW_COPY_AND_ASSIGN(SpecialPopupRow); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SPECIAL_POPUP_ROW_H_
diff --git a/ash/common/system/tray/system_menu_button.cc b/ash/common/system/tray/system_menu_button.cc new file mode 100644 index 0000000..d0cca16 --- /dev/null +++ b/ash/common/system/tray/system_menu_button.cc
@@ -0,0 +1,89 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_menu_button.h" + +#include "ash/common/ash_constants.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_highlight.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/animation/square_ink_drop_ripple.h" +#include "ui/views/border.h" +#include "ui/views/painter.h" + +namespace ash { + +SystemMenuButton::SystemMenuButton(views::ButtonListener* listener, + TrayPopupInkDropStyle ink_drop_style, + gfx::ImageSkia normal_icon, + gfx::ImageSkia disabled_icon, + int accessible_name_id) + : views::ImageButton(listener), ink_drop_style_(ink_drop_style) { + DCHECK_EQ(normal_icon.width(), disabled_icon.width()); + DCHECK_EQ(normal_icon.height(), disabled_icon.height()); + + SetImage(views::Button::STATE_NORMAL, &normal_icon); + SetImage(views::Button::STATE_DISABLED, &disabled_icon); + + const int horizontal_padding = (kMenuButtonSize - normal_icon.width()) / 2; + const int vertical_padding = (kMenuButtonSize - normal_icon.height()) / 2; + SetBorder(views::CreateEmptyBorder(vertical_padding, horizontal_padding, + vertical_padding, horizontal_padding)); + + SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id)); + + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + TrayPopupUtils::ConfigureTrayPopupButton(this); +} + +SystemMenuButton::SystemMenuButton(views::ButtonListener* listener, + TrayPopupInkDropStyle ink_drop_style, + const gfx::VectorIcon& icon, + int accessible_name_id) + : SystemMenuButton(listener, + ink_drop_style, + gfx::CreateVectorIcon(icon, kMenuIconColor), + gfx::CreateVectorIcon(icon, kMenuIconColorDisabled), + accessible_name_id) {} + +SystemMenuButton::~SystemMenuButton() {} + +void SystemMenuButton::SetInkDropColor(SkColor color) { + ink_drop_color_ = color; +} + +std::unique_ptr<views::InkDrop> SystemMenuButton::CreateInkDrop() { + return TrayPopupUtils::CreateInkDrop(ink_drop_style_, this); +} + +std::unique_ptr<views::InkDropRipple> SystemMenuButton::CreateInkDropRipple() + const { + return ink_drop_color_ == base::nullopt + ? TrayPopupUtils::CreateInkDropRipple( + ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent()) + : TrayPopupUtils::CreateInkDropRipple( + ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent(), + ink_drop_color_.value()); +} + +std::unique_ptr<views::InkDropHighlight> +SystemMenuButton::CreateInkDropHighlight() const { + return ink_drop_color_ == base::nullopt + ? TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this) + : TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this, + ink_drop_color_.value()); +} + +std::unique_ptr<views::InkDropMask> SystemMenuButton::CreateInkDropMask() + const { + return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this); +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_menu_button.h b/ash/common/system/tray/system_menu_button.h new file mode 100644 index 0000000..78026f0 --- /dev/null +++ b/ash/common/system/tray/system_menu_button.h
@@ -0,0 +1,74 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_MENU_BUTTON_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_MENU_BUTTON_H_ + +#include "ash/common/system/tray/tray_popup_ink_drop_style.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/macros.h" +#include "base/optional.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/image_button.h" + +namespace ash { + +// A 48x48 image button with a material design ripple effect, which can be +// used across Ash material design native UI menus. +// TODO(tdanderson): Deprecate TrayPopupHeaderButton in favor of +// SystemMenuButton once material design is enabled by default. See +// crbug.com/614453. +class SystemMenuButton : public views::ImageButton { + public: + // Constructs the button with |listener| and a centered icon corresponding to + // |normal_icon| when button is enabled and |disabled_icon| when it is + // disabled. |ink_drop_style| specifies which flavor of the ink drop should be + // used. |accessible_name_id| corresponds to the string in ui::ResourceBundle + // to use for the button's accessible and tooltip text. + SystemMenuButton(views::ButtonListener* listener, + TrayPopupInkDropStyle ink_drop_style, + gfx::ImageSkia normal_icon, + gfx::ImageSkia disabled_icon, + int accessible_name_id); + + // Similar to the above constructor. Just gets a single vector icon and + // creates the normal and disabled icons based on that using default menu icon + // colors. + SystemMenuButton(views::ButtonListener* listener, + TrayPopupInkDropStyle ink_drop_style, + const gfx::VectorIcon& icon, + int accessible_name_id); + ~SystemMenuButton() override; + + // Explicity sets the ink drop color. Otherwise the default value will be used + // by TrayPopupUtils::CreateInkDropRipple() and + // TrayPopupUtils::CreateInkDropHighlight(). + void SetInkDropColor(SkColor color); + + // views::ImageButton: + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + + private: + // Returns the size that the ink drop should be constructed with. + gfx::Size GetInkDropSize() const; + + // Defines the flavor of ink drop ripple/highlight that should be constructed. + TrayPopupInkDropStyle ink_drop_style_; + + // The color to use when creating the ink drop. If null the default color is + // used as defined by TrayPopupUtils::CreateInkDropRipple() and + // TrayPopupUtils::CreateInkDropHighlight(). + base::Optional<SkColor> ink_drop_color_; + + DISALLOW_COPY_AND_ASSIGN(SystemMenuButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_MENU_BUTTON_H_
diff --git a/ash/common/system/tray/system_tray.cc b/ash/common/system/tray/system_tray.cc new file mode 100644 index 0000000..521e205 --- /dev/null +++ b/ash/common/system/tray/system_tray.cc
@@ -0,0 +1,776 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray.h" + +#include <algorithm> +#include <map> +#include <vector> + +#include "ash/common/key_event_watcher.h" +#include "ash/common/login_status.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/chromeos/audio/tray_audio.h" +#include "ash/common/system/chromeos/bluetooth/tray_bluetooth.h" +#include "ash/common/system/chromeos/brightness/tray_brightness.h" +#include "ash/common/system/chromeos/cast/tray_cast.h" +#include "ash/common/system/chromeos/enterprise/tray_enterprise.h" +#include "ash/common/system/chromeos/media_security/multi_profile_media_tray_item.h" +#include "ash/common/system/chromeos/network/tray_network.h" +#include "ash/common/system/chromeos/network/tray_vpn.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/chromeos/power/tray_power.h" +#include "ash/common/system/chromeos/screen_security/screen_capture_tray_item.h" +#include "ash/common/system/chromeos/screen_security/screen_share_tray_item.h" +#include "ash/common/system/chromeos/session/tray_session_length_limit.h" +#include "ash/common/system/chromeos/settings/tray_settings.h" +#include "ash/common/system/chromeos/supervised/tray_supervised_user.h" +#include "ash/common/system/chromeos/tray_caps_lock.h" +#include "ash/common/system/chromeos/tray_tracing.h" +#include "ash/common/system/date/tray_date.h" +#include "ash/common/system/date/tray_system_info.h" +#include "ash/common/system/ime/tray_ime_chromeos.h" +#include "ash/common/system/tiles/tray_tiles.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_bubble_wrapper.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray_accessibility.h" +#include "ash/common/system/update/tray_update.h" +#include "ash/common/system/user/tray_user.h" +#include "ash/common/system/web_notification/web_notification_tray.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm_activation_observer.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/timer/timer.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/compositor/layer.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/events/event_constants.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/skia_util.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/message_center_style.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +using views::TrayBubbleView; + +namespace ash { + +namespace { + +// A tray item that just reserves space in the tray. +class PaddingTrayItem : public SystemTrayItem { + public: + PaddingTrayItem() : SystemTrayItem(nullptr, UMA_NOT_RECORDED) {} + ~PaddingTrayItem() override {} + + // SystemTrayItem: + views::View* CreateTrayView(LoginStatus status) override { + return new PaddingView(); + } + + private: + class PaddingView : public views::View { + public: + PaddingView() {} + ~PaddingView() override {} + + private: + gfx::Size GetPreferredSize() const override { + // The other tray items already have some padding baked in so we have to + // subtract that off. + const int side = kTrayEdgePadding - kTrayImageItemPadding; + return gfx::Size(side, side); + } + + DISALLOW_COPY_AND_ASSIGN(PaddingView); + }; + + DISALLOW_COPY_AND_ASSIGN(PaddingTrayItem); +}; + +} // namespace + +// Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper +// instances for a bubble. + +class SystemBubbleWrapper { + public: + // Takes ownership of |bubble|. + explicit SystemBubbleWrapper(SystemTrayBubble* bubble) + : bubble_(bubble), is_persistent_(false) {} + + // Initializes the bubble view and creates |bubble_wrapper_|. + void InitView(TrayBackgroundView* tray, + views::View* anchor, + const gfx::Insets& anchor_insets, + TrayBubbleView::InitParams* init_params, + bool is_persistent) { + DCHECK(anchor); + LoginStatus login_status = + WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); + bubble_->InitView(anchor, login_status, init_params); + bubble_->bubble_view()->set_anchor_view_insets(anchor_insets); + bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_->bubble_view())); + is_persistent_ = is_persistent; + + // If ChromeVox is enabled, focus the default item if no item is focused and + // there isn't a delayed close. + if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled() && + !is_persistent) { + bubble_->FocusDefaultIfNeeded(); + } + } + + // Convenience accessors: + SystemTrayBubble* bubble() const { return bubble_.get(); } + SystemTrayBubble::BubbleType bubble_type() const { + return bubble_->bubble_type(); + } + TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); } + bool is_persistent() const { return is_persistent_; } + + private: + std::unique_ptr<SystemTrayBubble> bubble_; + std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_; + bool is_persistent_; + + DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper); +}; + +// An activation observer to close the bubble if the window other +// than system bubble nor popup notification is activated. +class SystemTray::ActivationObserver : public WmActivationObserver { + public: + explicit ActivationObserver(SystemTray* tray) : tray_(tray) { + DCHECK(tray_); + WmShell::Get()->AddActivationObserver(this); + } + + ~ActivationObserver() override { + WmShell::Get()->RemoveActivationObserver(this); + } + + // WmActivationObserver: + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override { + if (!tray_->HasSystemBubble() || !gained_active) + return; + + int container_id = + wm::GetContainerForWindow(gained_active)->GetShellWindowId(); + + // Don't close the bubble if a popup notification is activated. + if (container_id == kShellWindowId_StatusContainer) + return; + + if (tray_->GetSystemBubble()->bubble_view()->GetWidget() != + gained_active->GetInternalWidget()) { + tray_->CloseSystemBubble(); + } + } + void OnAttemptToReactivateWindow(WmWindow* request_active, + WmWindow* actual_active) override {} + + private: + SystemTray* tray_; + + DISALLOW_COPY_AND_ASSIGN(ActivationObserver); +}; + +// SystemTray + +SystemTray::SystemTray(WmShelf* wm_shelf) + : TrayBackgroundView(wm_shelf), + web_notification_tray_(nullptr), + detailed_item_(nullptr), + default_bubble_height_(0), + full_system_tray_menu_(false), + tray_accessibility_(nullptr), + tray_audio_(nullptr), + tray_cast_(nullptr), + tray_date_(nullptr), + tray_network_(nullptr), + tray_tiles_(nullptr), + tray_system_info_(nullptr), + tray_update_(nullptr), + screen_capture_tray_item_(nullptr), + screen_share_tray_item_(nullptr) { + if (MaterialDesignController::IsShelfMaterial()) { + SetInkDropMode(InkDropMode::ON); + SetContentsBackground(false); + + // Since user avatar is on the right hand side of System tray of a + // horizontal shelf and that is sufficient to indicate separation, no + // separator is required. + set_separator_visibility(false); + } else { + SetContentsBackground(true); + } +} + +SystemTray::~SystemTray() { + // Destroy any child views that might have back pointers before ~View(). + activation_observer_.reset(); + key_event_watcher_.reset(); + system_bubble_.reset(); + for (const auto& item : items_) + item->DestroyTrayView(); +} + +void SystemTray::InitializeTrayItems( + SystemTrayDelegate* delegate, + WebNotificationTray* web_notification_tray) { + DCHECK(web_notification_tray); + web_notification_tray_ = web_notification_tray; + TrayBackgroundView::Initialize(); + CreateItems(delegate); +} + +void SystemTray::Shutdown() { + DCHECK(web_notification_tray_); + web_notification_tray_ = nullptr; +} + +void SystemTray::CreateItems(SystemTrayDelegate* delegate) { + const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial(); + + // Create user items for each possible user. + int maximum_user_profiles = WmShell::Get() + ->GetSessionStateDelegate() + ->GetMaximumNumberOfLoggedInUsers(); + for (int i = 0; i < maximum_user_profiles; i++) + AddTrayItem(base::MakeUnique<TrayUser>(this, i)); + + // Crucially, this trailing padding has to be inside the user item(s). + // Otherwise it could be a main axis margin on the tray's box layout. + AddTrayItem(base::MakeUnique<PaddingTrayItem>()); + + tray_accessibility_ = new TrayAccessibility(this); + if (!use_md) + tray_date_ = new TrayDate(this); + tray_update_ = new TrayUpdate(this); + + AddTrayItem(base::MakeUnique<TraySessionLengthLimit>(this)); + AddTrayItem(base::MakeUnique<TrayEnterprise>(this)); + AddTrayItem(base::MakeUnique<TraySupervisedUser>(this)); + AddTrayItem(base::MakeUnique<TrayIME>(this)); + AddTrayItem(base::WrapUnique(tray_accessibility_)); + AddTrayItem(base::MakeUnique<TrayTracing>(this)); + AddTrayItem( + base::MakeUnique<TrayPower>(this, message_center::MessageCenter::Get())); + tray_network_ = new TrayNetwork(this); + AddTrayItem(base::WrapUnique(tray_network_)); + AddTrayItem(base::MakeUnique<TrayVPN>(this)); + AddTrayItem(base::MakeUnique<TrayBluetooth>(this)); + tray_cast_ = new TrayCast(this); + AddTrayItem(base::WrapUnique(tray_cast_)); + screen_capture_tray_item_ = new ScreenCaptureTrayItem(this); + AddTrayItem(base::WrapUnique(screen_capture_tray_item_)); + screen_share_tray_item_ = new ScreenShareTrayItem(this); + AddTrayItem(base::WrapUnique(screen_share_tray_item_)); + AddTrayItem(base::MakeUnique<MultiProfileMediaTrayItem>(this)); + tray_audio_ = new TrayAudio(this); + AddTrayItem(base::WrapUnique(tray_audio_)); + AddTrayItem(base::MakeUnique<TrayBrightness>(this)); + AddTrayItem(base::MakeUnique<TrayCapsLock>(this)); + // TODO(jamescook): Remove this when mus has support for display management + // and we have a DisplayManager equivalent. See http://crbug.com/548429 + std::unique_ptr<SystemTrayItem> tray_rotation_lock = + delegate->CreateRotationLockTrayItem(this); + if (tray_rotation_lock) + AddTrayItem(std::move(tray_rotation_lock)); + if (!use_md) + AddTrayItem(base::MakeUnique<TraySettings>(this)); + AddTrayItem(base::WrapUnique(tray_update_)); + if (use_md) { + tray_tiles_ = new TrayTiles(this); + AddTrayItem(base::WrapUnique(tray_tiles_)); + tray_system_info_ = new TraySystemInfo(this); + AddTrayItem(base::WrapUnique(tray_system_info_)); + // Leading padding. + AddTrayItem(base::MakeUnique<PaddingTrayItem>()); + } else { + AddTrayItem(base::WrapUnique(tray_date_)); + } +} + +void SystemTray::AddTrayItem(std::unique_ptr<SystemTrayItem> item) { + SystemTrayItem* item_ptr = item.get(); + items_.push_back(std::move(item)); + + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + views::View* tray_item = + item_ptr->CreateTrayView(delegate->GetUserLoginStatus()); + item_ptr->UpdateAfterShelfAlignmentChange(shelf_alignment()); + + if (tray_item) { + tray_container()->AddChildViewAt(tray_item, 0); + PreferredSizeChanged(); + tray_item_map_[item_ptr] = tray_item; + } +} + +std::vector<SystemTrayItem*> SystemTray::GetTrayItems() const { + std::vector<SystemTrayItem*> result; + for (const auto& item : items_) + result.push_back(item.get()); + return result; +} + +void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { + if (creation_type != BUBBLE_USE_EXISTING) + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_MENU_OPENED); + ShowItems(GetTrayItems(), false, true, creation_type, false); +} + +void SystemTray::ShowPersistentDefaultView() { + ShowItems(GetTrayItems(), false, false, BUBBLE_CREATE_NEW, true); +} + +void SystemTray::ShowDetailedView(SystemTrayItem* item, + int close_delay, + bool activate, + BubbleCreationType creation_type) { + std::vector<SystemTrayItem*> items; + // The detailed view with timeout means a UI to show the current system state, + // like the audio level or brightness. Such UI should behave as persistent and + // keep its own logic for the appearance. + bool persistent = + (!activate && close_delay > 0 && creation_type == BUBBLE_CREATE_NEW); + items.push_back(item); + ShowItems(items, true, activate, creation_type, persistent); + if (system_bubble_) + system_bubble_->bubble()->StartAutoCloseTimer(close_delay); +} + +void SystemTray::SetDetailedViewCloseDelay(int close_delay) { + if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED)) + system_bubble_->bubble()->StartAutoCloseTimer(close_delay); +} + +void SystemTray::HideDetailedView(SystemTrayItem* item, bool animate) { + if (item != detailed_item_) + return; + + if (!animate) { + // In unittest, GetSystemBubble might return nullptr. + if (GetSystemBubble()) { + GetSystemBubble() + ->bubble_view() + ->GetWidget() + ->SetVisibilityAnimationTransition( + views::Widget::VisibilityTransition::ANIMATE_NONE); + } + } + + DestroySystemBubble(); +} + +void SystemTray::UpdateAfterLoginStatusChange(LoginStatus login_status) { + DestroySystemBubble(); + + for (const auto& item : items_) + item->UpdateAfterLoginStatusChange(login_status); + + // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial + // position of the shelf differs. + if (!IsHorizontalAlignment(shelf_alignment())) + UpdateAfterShelfAlignmentChange(shelf_alignment()); + + SetVisible(true); + PreferredSizeChanged(); +} + +void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + for (const auto& item : items_) + item->UpdateAfterShelfAlignmentChange(alignment); +} + +bool SystemTray::ShouldShowShelf() const { + return system_bubble_.get() && system_bubble_->bubble()->ShouldShowShelf(); +} + +bool SystemTray::HasSystemBubble() const { + return system_bubble_.get() != NULL; +} + +SystemTrayBubble* SystemTray::GetSystemBubble() { + if (!system_bubble_) + return NULL; + return system_bubble_->bubble(); +} + +bool SystemTray::IsSystemBubbleVisible() const { + return HasSystemBubble() && system_bubble_->bubble()->IsVisible(); +} + +bool SystemTray::CloseSystemBubble() const { + if (!system_bubble_) + return false; + CHECK(!activating_); + system_bubble_->bubble()->Close(); + return true; +} + +views::View* SystemTray::GetHelpButtonView() const { + if (MaterialDesignController::IsSystemTrayMenuMaterial()) + return tray_tiles_->GetHelpButtonView(); + return tray_date_->GetHelpButtonView(); +} + +TrayAudio* SystemTray::GetTrayAudio() const { + return tray_audio_; +} + +// Private methods. + +bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) { + return system_bubble_.get() && system_bubble_->bubble_type() == type; +} + +void SystemTray::DestroySystemBubble() { + CloseSystemBubbleAndDeactivateSystemTray(); + detailed_item_ = NULL; + UpdateWebNotifications(); +} + +base::string16 SystemTray::GetAccessibleNameForTray() { + base::string16 time = GetAccessibleTimeString(base::Time::Now()); + base::string16 battery = PowerStatus::Get()->GetAccessibleNameString(false); + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_DESCRIPTION, + time, battery); +} + +void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, + bool detailed, + bool can_activate, + BubbleCreationType creation_type, + bool persistent) { + // No system tray bubbles in kiosk mode. + SystemTrayDelegate* system_tray_delegate = + WmShell::Get()->system_tray_delegate(); + if (system_tray_delegate->GetUserLoginStatus() == LoginStatus::KIOSK_APP || + system_tray_delegate->GetUserLoginStatus() == + LoginStatus::ARC_KIOSK_APP) { + return; + } + + // Destroy any existing bubble and create a new one. + SystemTrayBubble::BubbleType bubble_type = + detailed ? SystemTrayBubble::BUBBLE_TYPE_DETAILED + : SystemTrayBubble::BUBBLE_TYPE_DEFAULT; + + if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { + system_bubble_->bubble()->UpdateView(items, bubble_type); + // If ChromeVox is enabled, focus the default item if no item is focused. + if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled()) + system_bubble_->bubble()->FocusDefaultIfNeeded(); + } else { + // Cleanup the existing bubble before showing a new one. Otherwise, it's + // possible to confuse the new system bubble with the old one during + // destruction, leading to subtle errors/crashes such as crbug.com/545166. + DestroySystemBubble(); + + // Remember if the menu is a single property (like e.g. volume) or the + // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case + // above, |full_system_tray_menu_| does not get changed since the fact that + // the menu is full (or not) doesn't change even if a "single property" + // (like network) replaces most of the menu. + full_system_tray_menu_ = items.size() > 1; + + // The menu width is fixed for all languages in material design. + int menu_width = kTrayMenuMinimumWidthMd; + if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { + // The menu width is fixed, and it is a per language setting. + menu_width = std::max( + kTrayMenuMinimumWidth, + WmShell::Get()->system_tray_delegate()->GetSystemTrayMenuWidth()); + } + + TrayBubbleView::InitParams init_params(GetAnchorAlignment(), menu_width, + kTrayPopupMaxWidth); + // TODO(oshima): Change TrayBubbleView itself. + init_params.can_activate = false; + if (detailed) { + // This is the case where a volume control or brightness control bubble + // is created. + init_params.max_height = default_bubble_height_; + init_params.bg_color = kBackgroundColor; + } else { + init_params.bg_color = kHeaderBackgroundColor; + } + if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) + init_params.close_on_deactivate = !persistent; + SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type); + + system_bubble_.reset(new SystemBubbleWrapper(bubble)); + system_bubble_->InitView(this, GetBubbleAnchor(), GetBubbleAnchorInsets(), + &init_params, persistent); + + activation_observer_.reset(persistent ? nullptr + : new ActivationObserver(this)); + + // Record metrics for the system menu when the default view is invoked. + if (!detailed) + RecordSystemMenuMetrics(); + } + // Save height of default view for creating detailed views directly. + if (!detailed) + default_bubble_height_ = system_bubble_->bubble_view()->height(); + + key_event_watcher_.reset(); + if (can_activate) + CreateKeyEventWatcher(); + + if (detailed && items.size() > 0) + detailed_item_ = items[0]; + else + detailed_item_ = NULL; + + UpdateWebNotifications(); + shelf()->UpdateAutoHideState(); + + // When we show the system menu in our alternate shelf layout, we need to + // tint the background. + if (full_system_tray_menu_) + SetIsActive(true); +} + +void SystemTray::UpdateWebNotifications() { + TrayBubbleView* bubble_view = NULL; + if (system_bubble_) + bubble_view = system_bubble_->bubble_view(); + + int height = 0; + if (bubble_view) { + gfx::Rect work_area = + display::Screen::GetScreen() + ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView()) + .work_area(); + height = + std::max(0, work_area.bottom() - bubble_view->GetBoundsInScreen().y()); + } + if (web_notification_tray_) + web_notification_tray_->SetTrayBubbleHeight(height); +} + +base::string16 SystemTray::GetAccessibleTimeString( + const base::Time& now) const { + base::HourClockType hour_type = + WmShell::Get()->system_tray_controller()->hour_clock_type(); + return base::TimeFormatTimeOfDayWithHourClockType(now, hour_type, + base::kKeepAmPm); +} + +void SystemTray::SetShelfAlignment(ShelfAlignment alignment) { + if (alignment == shelf_alignment()) + return; + TrayBackgroundView::SetShelfAlignment(alignment); + UpdateAfterShelfAlignmentChange(alignment); + // Destroy any existing bubble so that it is rebuilt correctly. + CloseSystemBubbleAndDeactivateSystemTray(); + // Rebuild any notification bubble. + UpdateWebNotifications(); +} + +void SystemTray::AnchorUpdated() { + if (system_bubble_) { + system_bubble_->bubble_view()->UpdateBubble(); + UpdateBubbleViewArrow(system_bubble_->bubble_view()); + } +} + +void SystemTray::BubbleResized(const TrayBubbleView* bubble_view) { + UpdateWebNotifications(); +} + +void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) { + if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) { + DestroySystemBubble(); + shelf()->UpdateAutoHideState(); + } +} + +void SystemTray::ClickedOutsideBubble() { + if (!system_bubble_ || system_bubble_->is_persistent()) + return; + HideBubbleWithView(system_bubble_->bubble_view()); +} + +void SystemTray::BubbleViewDestroyed() { + if (system_bubble_) { + system_bubble_->bubble()->DestroyItemViews(); + system_bubble_->bubble()->BubbleViewDestroyed(); + } +} + +void SystemTray::OnMouseEnteredView() { + if (system_bubble_) + system_bubble_->bubble()->StopAutoCloseTimer(); +} + +void SystemTray::OnMouseExitedView() { + if (system_bubble_) + system_bubble_->bubble()->RestartAutoCloseTimer(); +} + +base::string16 SystemTray::GetAccessibleNameForBubble() { + return GetAccessibleNameForTray(); +} + +void SystemTray::OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const { + // Place the bubble in the same root window as |anchor_widget|. + WmWindow::Get(anchor_widget->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + bubble_widget, kShellWindowId_SettingBubbleContainer, params); +} + +void SystemTray::HideBubble(const TrayBubbleView* bubble_view) { + HideBubbleWithView(bubble_view); +} + +views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) { + std::map<SystemTrayItem*, views::View*>::iterator it = + tray_item_map_.find(item); + return it == tray_item_map_.end() ? NULL : it->second; +} + +TrayCast* SystemTray::GetTrayCastForTesting() const { + return tray_cast_; +} + +TrayDate* SystemTray::GetTrayDateForTesting() const { + return tray_date_; +} + +TrayNetwork* SystemTray::GetTrayNetworkForTesting() const { + return tray_network_; +} + +TraySystemInfo* SystemTray::GetTraySystemInfoForTesting() const { + return tray_system_info_; +} + +TrayTiles* SystemTray::GetTrayTilesForTesting() const { + return tray_tiles_; +} + +void SystemTray::CloseBubble(const ui::KeyEvent& key_event) { + CloseSystemBubble(); +} + +void SystemTray::ActivateAndStartNavigation(const ui::KeyEvent& key_event) { + if (!system_bubble_) + return; + activating_ = true; + ActivateBubble(); + activating_ = false; + // TODO(oshima): This is to troubleshoot the issue crbug.com/651242. Remove + // once the root cause is fixed. + CHECK(system_bubble_) << " the bubble was deleted while activaing it"; + + views::Widget* widget = GetSystemBubble()->bubble_view()->GetWidget(); + widget->GetFocusManager()->OnKeyEvent(key_event); +} + +void SystemTray::CreateKeyEventWatcher() { + key_event_watcher_ = WmShell::Get()->CreateKeyEventWatcher(); + // mustash does not yet support KeyEventWatcher. http://crbug.com/649600. + if (!key_event_watcher_) + return; + key_event_watcher_->AddKeyEventCallback( + ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE), + base::Bind(&SystemTray::CloseBubble, base::Unretained(this))); + key_event_watcher_->AddKeyEventCallback( + ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE), + base::Bind(&SystemTray::ActivateAndStartNavigation, + base::Unretained(this))); + key_event_watcher_->AddKeyEventCallback( + ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN), + base::Bind(&SystemTray::ActivateAndStartNavigation, + base::Unretained(this))); +} + +void SystemTray::ActivateBubble() { + TrayBubbleView* bubble_view = GetSystemBubble()->bubble_view(); + bubble_view->set_can_activate(true); + bubble_view->GetWidget()->Activate(); +} + +bool SystemTray::PerformAction(const ui::Event& event) { + // If we're already showing the default view, hide it; otherwise, show it + // (and hide any popup that's currently shown). + if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { + system_bubble_->bubble()->Close(); + } else { + ShowDefaultView(BUBBLE_CREATE_NEW); + if (event.IsKeyEvent() || (event.flags() & ui::EF_TOUCH_ACCESSIBILITY)) + ActivateBubble(); + } + return true; +} + +void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() { + CHECK(!activating_); + activation_observer_.reset(); + key_event_watcher_.reset(); + system_bubble_.reset(); + // When closing a system bubble with the alternate shelf layout, we need to + // turn off the active tinting of the shelf. + if (full_system_tray_menu_) { + SetIsActive(false); + full_system_tray_menu_ = false; + } +} + +void SystemTray::RecordSystemMenuMetrics() { + DCHECK(system_bubble_); + + system_bubble_->bubble()->RecordVisibleRowMetrics(); + + TrayBubbleView* bubble_view = system_bubble_->bubble_view(); + int num_rows = 0; + for (int i = 0; i < bubble_view->child_count(); i++) { + // Certain menu rows are attached by default but can set themselves as + // invisible (IME is one such example). Count only user-visible rows. + if (bubble_view->child_at(i)->visible()) + num_rows++; + } + UMA_HISTOGRAM_COUNTS_100("Ash.SystemMenu.Rows", num_rows); + + int work_area_height = + display::Screen::GetScreen() + ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView()) + .work_area() + .height(); + if (work_area_height > 0) { + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Ash.SystemMenu.PercentageOfWorkAreaHeightCoveredByMenu", + 100 * bubble_view->height() / work_area_height, 1, 300, 100); + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_tray.h b/ash/common/system/tray/system_tray.h new file mode 100644 index 0000000..38af857 --- /dev/null +++ b/ash/common/system/tray/system_tray.h
@@ -0,0 +1,256 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/system/tray/system_tray_bubble.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "base/macros.h" +#include "ui/views/bubble/tray_bubble_view.h" +#include "ui/views/view.h" + +namespace ash { + +class KeyEventWatcher; +enum class LoginStatus; +class ScreenTrayItem; +class SystemBubbleWrapper; +class SystemTrayDelegate; +class SystemTrayItem; +class TrayAccessibility; +class TrayAudio; +class TrayCast; +class TrayDate; +class TrayNetwork; +class TraySystemInfo; +class TrayTiles; +class TrayUpdate; +class WebNotificationTray; + +// There are different methods for creating bubble views. +enum BubbleCreationType { + BUBBLE_CREATE_NEW, // Closes any existing bubble and creates a new one. + BUBBLE_USE_EXISTING, // Uses any existing bubble, or creates a new one. +}; + +class ASH_EXPORT SystemTray : public TrayBackgroundView, + public views::TrayBubbleView::Delegate { + public: + explicit SystemTray(WmShelf* wm_shelf); + ~SystemTray() override; + + TrayUpdate* tray_update() { return tray_update_; } + + // Calls TrayBackgroundView::Initialize(), creates the tray items, and + // adds them to SystemTrayNotifier. + void InitializeTrayItems(SystemTrayDelegate* delegate, + WebNotificationTray* web_notification_tray); + + // Resets internal pointers. This has to be called before deletion. + void Shutdown(); + + // Adds a new item in the tray. + void AddTrayItem(std::unique_ptr<SystemTrayItem> item); + + // Returns all tray items that has been added to system tray. + std::vector<SystemTrayItem*> GetTrayItems() const; + + // Shows the default view of all items. + void ShowDefaultView(BubbleCreationType creation_type); + + // Shows default view that ingnores outside clicks and activation loss. + void ShowPersistentDefaultView(); + + // Shows details of a particular item. If |close_delay_in_seconds| is + // non-zero, then the view is automatically closed after the specified time. + void ShowDetailedView(SystemTrayItem* item, + int close_delay_in_seconds, + bool activate, + BubbleCreationType creation_type); + + // Continue showing the existing detailed view, if any, for |close_delay| + // seconds. + void SetDetailedViewCloseDelay(int close_delay); + + // Hides the detailed view for |item|. If |animate| is false, disable + // the hiding animation for hiding |item|. + void HideDetailedView(SystemTrayItem* item, bool animate); + + // Updates the items when the login status of the system changes. + void UpdateAfterLoginStatusChange(LoginStatus login_status); + + // Updates the items when the shelf alignment changes. + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment); + + // Returns true if the shelf should be forced visible when auto-hidden. + bool ShouldShowShelf() const; + + // Returns true if there is a system bubble (already visible or in the process + // of being created). + bool HasSystemBubble() const; + + // Returns true if the system_bubble_ exists and is of type |type|. + bool HasSystemBubbleType(SystemTrayBubble::BubbleType type); + + // Returns a pointer to the system bubble or NULL if none. + SystemTrayBubble* GetSystemBubble(); + + // Returns true if system bubble is visible. + bool IsSystemBubbleVisible() const; + + // Closes system bubble and returns true if it did exist. + bool CloseSystemBubble() const; + + // Returns view for help button if default view is shown. Returns NULL + // otherwise. + views::View* GetHelpButtonView() const; + + // Returns TrayAudio object if present or null otherwise. + TrayAudio* GetTrayAudio() const; + + // Overridden from TrayBackgroundView. + void SetShelfAlignment(ShelfAlignment alignment) override; + void AnchorUpdated() override; + base::string16 GetAccessibleNameForTray() override; + void BubbleResized(const views::TrayBubbleView* bubble_view) override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void ClickedOutsideBubble() override; + + // views::TrayBubbleView::Delegate: + void BubbleViewDestroyed() override; + void OnMouseEnteredView() override; + void OnMouseExitedView() override; + base::string16 GetAccessibleNameForBubble() override; + void OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const override; + void HideBubble(const views::TrayBubbleView* bubble_view) override; + + ScreenTrayItem* GetScreenShareItem() { return screen_share_tray_item_; } + ScreenTrayItem* GetScreenCaptureItem() { return screen_capture_tray_item_; } + + TrayAccessibility* GetTrayAccessibilityForTest() { + return tray_accessibility_; + } + + // Get the tray item view (or NULL) for a given |tray_item| in a unit test. + views::View* GetTrayItemViewForTest(SystemTrayItem* tray_item); + + TrayCast* GetTrayCastForTesting() const; + TrayDate* GetTrayDateForTesting() const; + TrayNetwork* GetTrayNetworkForTesting() const; + TraySystemInfo* GetTraySystemInfoForTesting() const; + TrayTiles* GetTrayTilesForTesting() const; + + // Activates the system tray bubble. + void ActivateBubble(); + + private: + class ActivationObserver; + + // Closes the bubble. Used to bind as a KeyEventWatcher::KeyEventCallback. + void CloseBubble(const ui::KeyEvent& key_event); + + // Activates the bubble and starts key navigation with the |key_event|. + void ActivateAndStartNavigation(const ui::KeyEvent& key_event); + + // Creates the key event watcher. See |ShowItems()| for why key events are + // observed. + void CreateKeyEventWatcher(); + + // Creates the default set of items for the sytem tray. + void CreateItems(SystemTrayDelegate* delegate); + + // Resets |system_bubble_| and clears any related state. + void DestroySystemBubble(); + + // Returns a string with the current time for accessibility on the status + // tray bar. + base::string16 GetAccessibleTimeString(const base::Time& now) const; + + // Constructs or re-constructs |system_bubble_| and populates it with |items|. + // Specify |change_tray_status| to true if want to change the tray background + // status. The bubble will be opened in inactive state. If |can_activate| is + // true, the bubble will be activated by one of following means. + // * When alt/alt-tab acclerator is used to start navigation. + // * When the bubble is opened by accelerator. + // * When the tray item is set to be focused. + void ShowItems(const std::vector<SystemTrayItem*>& items, + bool details, + bool can_activate, + BubbleCreationType creation_type, + bool persistent); + + // Checks the current status of the system tray and updates the web + // notification tray according to the current status. + void UpdateWebNotifications(); + + // Deactivate the system tray in the shelf if it was active before. + void CloseSystemBubbleAndDeactivateSystemTray(); + + // Records UMA metrics for the number of user-visible rows in the system menu + // and the percentage of the work area height covered by the system menu. + void RecordSystemMenuMetrics(); + + // Overridden from ActionableView. + bool PerformAction(const ui::Event& event) override; + + // The web notification tray view that appears adjacent to this view. + WebNotificationTray* web_notification_tray_; + + // Items. + std::vector<std::unique_ptr<SystemTrayItem>> items_; + + // Pointers to members of |items_|. + SystemTrayItem* detailed_item_; + + // Mappings of system tray item and it's view in the tray. + std::map<SystemTrayItem*, views::View*> tray_item_map_; + + // Bubble for default and detailed views. + std::unique_ptr<SystemBubbleWrapper> system_bubble_; + + // Keep track of the default view height so that when we create detailed + // views directly (e.g. from a notification) we know what height to use. + int default_bubble_height_; + + // This is true when the displayed system tray menu is a full tray menu, + // otherwise a single line item menu like the volume slider is shown. + // Note that the value is only valid when |system_bubble_| is true. + bool full_system_tray_menu_; + + // These objects are not owned by this class. + TrayAccessibility* tray_accessibility_; + TrayAudio* tray_audio_; // May be null. + TrayCast* tray_cast_; + TrayDate* tray_date_; // null for material design. + TrayNetwork* tray_network_; + TrayTiles* tray_tiles_; // only used in material design. + TraySystemInfo* tray_system_info_; // only used in material design. + TrayUpdate* tray_update_; + + // A reference to the Screen share and capture item. + ScreenTrayItem* screen_capture_tray_item_; // not owned + ScreenTrayItem* screen_share_tray_item_; // not owned + + // TODO(oshima): Remove this when crbug.com/651242 is fixed. + bool activating_ = false; + + std::unique_ptr<KeyEventWatcher> key_event_watcher_; + + std::unique_ptr<ActivationObserver> activation_observer_; + + DISALLOW_COPY_AND_ASSIGN(SystemTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_H_
diff --git a/ash/common/system/tray/system_tray_bubble.cc b/ash/common/system/tray/system_tray_bubble.cc new file mode 100644 index 0000000..de1dcdb --- /dev/null +++ b/ash/common/system/tray/system_tray_bubble.cc
@@ -0,0 +1,368 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray_bubble.h" + +#include <utility> +#include <vector> + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_bubble_wrapper.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_container.h" +#include "ash/common/wm_shell.h" +#include "base/metrics/histogram_macros.h" +#include "base/threading/thread_task_runner_handle.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/canvas.h" +#include "ui/views/border.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +using views::TrayBubbleView; + +namespace ash { + +namespace { + +// Normally a detailed view is the same size as the default view. However, +// when showing a detailed view directly (e.g. clicking on a notification), +// we may not know the height of the default view, or the default view may +// be too short, so we use this as a default and minimum height for any +// detailed view. +int GetDetailedBubbleMaxHeight() { + return kTrayPopupItemMinHeight * 5; +} + +// Duration of swipe animation used when transitioning from a default to +// detailed view or vice versa. +const int kSwipeDelayMS = 150; + +// Extra bottom padding when showing the BUBBLE_TYPE_DEFAULT view. +const int kDefaultViewBottomPadding = 4; + +// Implicit animation observer that deletes itself and the layer at the end of +// the animation. +class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver { + public: + explicit AnimationObserverDeleteLayer(ui::Layer* layer) : layer_(layer) {} + + ~AnimationObserverDeleteLayer() override {} + + void OnImplicitAnimationsCompleted() override { + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); + } + + private: + std::unique_ptr<ui::Layer> layer_; + + DISALLOW_COPY_AND_ASSIGN(AnimationObserverDeleteLayer); +}; + +} // namespace + +// SystemTrayBubble + +SystemTrayBubble::SystemTrayBubble( + ash::SystemTray* tray, + const std::vector<ash::SystemTrayItem*>& items, + BubbleType bubble_type) + : tray_(tray), + bubble_view_(nullptr), + items_(items), + bubble_type_(bubble_type), + autoclose_delay_(0) {} + +SystemTrayBubble::~SystemTrayBubble() { + DestroyItemViews(); + // Reset the host pointer in bubble_view_ in case its destruction is deferred. + if (bubble_view_) + bubble_view_->reset_delegate(); +} + +void SystemTrayBubble::UpdateView( + const std::vector<ash::SystemTrayItem*>& items, + BubbleType bubble_type) { + std::unique_ptr<ui::Layer> scoped_layer; + if (bubble_type != bubble_type_) { + base::TimeDelta swipe_duration = + base::TimeDelta::FromMilliseconds(kSwipeDelayMS); + scoped_layer = bubble_view_->RecreateLayer(); + // Keep the reference to layer as we need it after releasing it. + ui::Layer* layer = scoped_layer.get(); + DCHECK(layer); + layer->SuppressPaint(); + + // When transitioning from detailed view to default view, animate the + // existing view (slide out towards the right). + if (bubble_type == BUBBLE_TYPE_DEFAULT) { + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + settings.AddObserver( + new AnimationObserverDeleteLayer(scoped_layer.release())); + settings.SetTransitionDuration(swipe_duration); + settings.SetTweenType(gfx::Tween::EASE_OUT); + gfx::Transform transform; + transform.Translate(layer->bounds().width(), 0.0); + layer->SetTransform(transform); + } + + { + // Add a shadow layer to make the old layer darker as the animation + // progresses. + ui::Layer* shadow = new ui::Layer(ui::LAYER_SOLID_COLOR); + shadow->SetColor(SK_ColorBLACK); + shadow->SetOpacity(0.01f); + shadow->SetBounds(layer->bounds()); + layer->Add(shadow); + layer->StackAtTop(shadow); + { + // Animate the darkening effect a little longer than the swipe-in. This + // is to make sure the darkening animation does not end up finishing + // early, because the dark layer goes away at the end of the animation, + // and there is a brief moment when the old view is still visible, but + // it does not have the shadow layer on top. + ui::ScopedLayerAnimationSettings settings(shadow->GetAnimator()); + settings.AddObserver(new AnimationObserverDeleteLayer(shadow)); + settings.SetTransitionDuration(swipe_duration + + base::TimeDelta::FromMilliseconds(150)); + settings.SetTweenType(gfx::Tween::LINEAR); + shadow->SetOpacity(0.15f); + } + } + } + + DestroyItemViews(); + bubble_view_->RemoveAllChildViews(true); + + items_ = items; + bubble_type_ = bubble_type; + CreateItemViews(WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()); + + // Close bubble view if we failed to create the item view. + if (!bubble_view_->has_children()) { + Close(); + return; + } + + UpdateBottomPadding(); + bubble_view_->GetWidget()->GetContentsView()->Layout(); + // Make sure that the bubble is large enough for the default view. + if (bubble_type_ == BUBBLE_TYPE_DEFAULT) { + bubble_view_->SetMaxHeight(0); // Clear max height limit. + } + + if (scoped_layer) { + // When transitioning from default view to detailed view, animate the new + // view (slide in from the right). + if (bubble_type == BUBBLE_TYPE_DETAILED) { + ui::Layer* new_layer = bubble_view_->layer(); + + // Make sure the new layer is stacked above the old layer during the + // animation. + new_layer->parent()->StackAbove(new_layer, scoped_layer.get()); + + gfx::Rect bounds = new_layer->bounds(); + gfx::Transform transform; + transform.Translate(bounds.width(), 0.0); + new_layer->SetTransform(transform); + { + ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator()); + settings.AddObserver( + new AnimationObserverDeleteLayer(scoped_layer.release())); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kSwipeDelayMS)); + settings.SetTweenType(gfx::Tween::EASE_OUT); + new_layer->SetTransform(gfx::Transform()); + } + } + } +} + +void SystemTrayBubble::InitView(views::View* anchor, + LoginStatus login_status, + TrayBubbleView::InitParams* init_params) { + DCHECK(anchor); + DCHECK(!bubble_view_); + + if (bubble_type_ == BUBBLE_TYPE_DETAILED && + init_params->max_height < GetDetailedBubbleMaxHeight()) { + init_params->max_height = GetDetailedBubbleMaxHeight(); + } + + bubble_view_ = TrayBubbleView::Create(anchor, tray_, init_params); + UpdateBottomPadding(); + bubble_view_->set_adjust_if_offscreen(false); + CreateItemViews(login_status); + + if (bubble_view_->CanActivate()) { + bubble_view_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); + } +} + +void SystemTrayBubble::FocusDefaultIfNeeded() { + views::FocusManager* manager = bubble_view_->GetFocusManager(); + if (!manager || manager->GetFocusedView()) + return; + + views::View* view = + manager->GetNextFocusableView(nullptr, nullptr, false, false); + // TODO(oshima): RequestFocus calls View::OnFocus even if the widget + // is not active (crbug.com/621791). Remove this check once the bug + // is fixed. + if (bubble_view_->GetWidget()->IsActive()) { + view->RequestFocus(); + } else { + manager->SetStoredFocusView(view); + } +} + +void SystemTrayBubble::DestroyItemViews() { + for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin(); + it != items_.end(); ++it) { + switch (bubble_type_) { + case BUBBLE_TYPE_DEFAULT: + (*it)->DestroyDefaultView(); + break; + case BUBBLE_TYPE_DETAILED: + (*it)->DestroyDetailedView(); + break; + } + } +} + +void SystemTrayBubble::BubbleViewDestroyed() { + bubble_view_ = nullptr; +} + +void SystemTrayBubble::StartAutoCloseTimer(int seconds) { + autoclose_.Stop(); + autoclose_delay_ = seconds; + if (autoclose_delay_) { + autoclose_.Start(FROM_HERE, base::TimeDelta::FromSeconds(autoclose_delay_), + this, &SystemTrayBubble::Close); + } +} + +void SystemTrayBubble::StopAutoCloseTimer() { + autoclose_.Stop(); +} + +void SystemTrayBubble::RestartAutoCloseTimer() { + if (autoclose_delay_) + StartAutoCloseTimer(autoclose_delay_); +} + +void SystemTrayBubble::Close() { + tray_->HideBubbleWithView(bubble_view()); +} + +void SystemTrayBubble::SetVisible(bool is_visible) { + if (!bubble_view_) + return; + views::Widget* bubble_widget = bubble_view_->GetWidget(); + if (is_visible) + bubble_widget->Show(); + else + bubble_widget->Hide(); +} + +bool SystemTrayBubble::IsVisible() { + return bubble_view() && bubble_view()->GetWidget()->IsVisible(); +} + +bool SystemTrayBubble::ShouldShowShelf() const { + for (std::vector<ash::SystemTrayItem*>::const_iterator it = items_.begin(); + it != items_.end(); ++it) { + if ((*it)->ShouldShowShelf()) + return true; + } + return false; +} + +void SystemTrayBubble::RecordVisibleRowMetrics() { + if (bubble_type_ != BUBBLE_TYPE_DEFAULT) + return; + + for (const std::pair<SystemTrayItem::UmaType, views::View*>& pair : + tray_item_view_map_) { + if (pair.second->visible() && + pair.first != SystemTrayItem::UMA_NOT_RECORDED) { + UMA_HISTOGRAM_ENUMERATION("Ash.SystemMenu.DefaultView.VisibleRows", + pair.first, SystemTrayItem::UMA_COUNT); + } + } +} + +void SystemTrayBubble::UpdateBottomPadding() { + if (bubble_type_ == BUBBLE_TYPE_DEFAULT && + MaterialDesignController::IsSystemTrayMenuMaterial()) { + bubble_view_->SetBottomPadding(kDefaultViewBottomPadding); + } else { + bubble_view_->SetBottomPadding(0); + } +} + +void SystemTrayBubble::CreateItemViews(LoginStatus login_status) { + tray_item_view_map_.clear(); + + // If a system modal dialog is present, create the same tray as + // in locked state. + if (WmShell::Get()->IsSystemModalWindowOpen() && + login_status != LoginStatus::NOT_LOGGED_IN) { + login_status = LoginStatus::LOCKED; + } + + std::vector<TrayPopupItemContainer*> item_containers; + views::View* focus_view = nullptr; + const bool is_default_bubble = bubble_type_ == BUBBLE_TYPE_DEFAULT; + for (size_t i = 0; i < items_.size(); ++i) { + views::View* item_view = nullptr; + switch (bubble_type_) { + case BUBBLE_TYPE_DEFAULT: + item_view = items_[i]->CreateDefaultView(login_status); + if (items_[i]->restore_focus()) + focus_view = item_view; + break; + case BUBBLE_TYPE_DETAILED: + item_view = items_[i]->CreateDetailedView(login_status); + break; + } + if (item_view) { + TrayPopupItemContainer* tray_popup_item_container = + new TrayPopupItemContainer( + item_view, + is_default_bubble && + !MaterialDesignController::IsSystemTrayMenuMaterial()); + bubble_view_->AddChildView(tray_popup_item_container); + item_containers.push_back(tray_popup_item_container); + tray_item_view_map_[items_[i]->uma_type()] = tray_popup_item_container; + } + } + + if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { + // For default view, draw bottom border for each item, except the last + // 2 items, which are the bottom header row and the one just above it. + if (is_default_bubble) { + const int last_item_with_border = + static_cast<int>(item_containers.size()) - 2; + for (int i = 0; i < last_item_with_border; ++i) { + item_containers.at(i)->SetBorder( + views::CreateSolidSidedBorder(0, 0, 1, 0, kBorderLightColor)); + } + } + } + + if (focus_view) { + tray_->ActivateBubble(); + focus_view->RequestFocus(); + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_tray_bubble.h b/ash/common/system/tray/system_tray_bubble.h new file mode 100644 index 0000000..a19137b --- /dev/null +++ b/ash/common/system/tray/system_tray_bubble.h
@@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "ash/common/login_status.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" +#include "base/timer/timer.h" +#include "ui/views/bubble/tray_bubble_view.h" + +namespace ash { +class SystemTray; +class SystemTrayItem; + +class SystemTrayBubble { + public: + enum BubbleType { BUBBLE_TYPE_DEFAULT, BUBBLE_TYPE_DETAILED }; + + SystemTrayBubble(ash::SystemTray* tray, + const std::vector<ash::SystemTrayItem*>& items, + BubbleType bubble_type); + virtual ~SystemTrayBubble(); + + // Change the items displayed in the bubble. + void UpdateView(const std::vector<ash::SystemTrayItem*>& items, + BubbleType bubble_type); + + // Creates |bubble_view_| and a child views for each member of |items_|. + // Also creates |bubble_wrapper_|. |init_params| may be modified. + void InitView(views::View* anchor, + LoginStatus login_status, + views::TrayBubbleView::InitParams* init_params); + + // Focus the default item if no item is focused. Othewise, do nothing. + void FocusDefaultIfNeeded(); + + BubbleType bubble_type() const { return bubble_type_; } + views::TrayBubbleView* bubble_view() const { return bubble_view_; } + + void DestroyItemViews(); + void BubbleViewDestroyed(); + void StartAutoCloseTimer(int seconds); + void StopAutoCloseTimer(); + void RestartAutoCloseTimer(); + void Close(); + void SetVisible(bool is_visible); + bool IsVisible(); + + // Returns true if any of the SystemTrayItems return true from + // ShouldShowShelf(). + bool ShouldShowShelf() const; + + // Records metrics for visible system menu rows. Only implemented for the + // BUBBLE_TYPE_DEFAULT BubbleType. + void RecordVisibleRowMetrics(); + + private: + // Updates the bottom padding of the |bubble_view_| based on the + // |bubble_type_|. + void UpdateBottomPadding(); + void CreateItemViews(LoginStatus login_status); + + ash::SystemTray* tray_; + views::TrayBubbleView* bubble_view_; + std::vector<ash::SystemTrayItem*> items_; + BubbleType bubble_type_; + + // Tracks the views created in the last call to CreateItemViews(). + std::map<SystemTrayItem::UmaType, views::View*> tray_item_view_map_; + + int autoclose_delay_; + base::OneShotTimer autoclose_; + + DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
diff --git a/ash/common/system/tray/system_tray_controller.cc b/ash/common/system/tray/system_tray_controller.cc new file mode 100644 index 0000000..c4317df --- /dev/null +++ b/ash/common/system/tray/system_tray_controller.cc
@@ -0,0 +1,181 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray_controller.h" + +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/update/tray_update.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" + +namespace ash { + +SystemTrayController::SystemTrayController() + : hour_clock_type_(base::GetHourClockType()) {} + +SystemTrayController::~SystemTrayController() {} + +void SystemTrayController::ShowSettings() { + if (system_tray_client_) + system_tray_client_->ShowSettings(); +} + +void SystemTrayController::ShowDateSettings() { + if (system_tray_client_) + system_tray_client_->ShowDateSettings(); +} + +void SystemTrayController::ShowSetTimeDialog() { + if (system_tray_client_) + system_tray_client_->ShowSetTimeDialog(); +} + +void SystemTrayController::ShowDisplaySettings() { + if (system_tray_client_) + system_tray_client_->ShowDisplaySettings(); +} + +void SystemTrayController::ShowPowerSettings() { + if (system_tray_client_) + system_tray_client_->ShowPowerSettings(); +} + +void SystemTrayController::ShowChromeSlow() { + if (system_tray_client_) + system_tray_client_->ShowChromeSlow(); +} + +void SystemTrayController::ShowIMESettings() { + if (system_tray_client_) + system_tray_client_->ShowIMESettings(); +} + +void SystemTrayController::ShowHelp() { + if (system_tray_client_) + system_tray_client_->ShowHelp(); +} + +void SystemTrayController::ShowAccessibilityHelp() { + if (system_tray_client_) + system_tray_client_->ShowAccessibilityHelp(); +} + +void SystemTrayController::ShowAccessibilitySettings() { + if (system_tray_client_) + system_tray_client_->ShowAccessibilitySettings(); +} + +void SystemTrayController::ShowPaletteHelp() { + if (system_tray_client_) + system_tray_client_->ShowPaletteHelp(); +} + +void SystemTrayController::ShowPaletteSettings() { + if (system_tray_client_) + system_tray_client_->ShowPaletteSettings(); +} + +void SystemTrayController::ShowPublicAccountInfo() { + if (system_tray_client_) + system_tray_client_->ShowPublicAccountInfo(); +} + +void SystemTrayController::ShowNetworkConfigure(const std::string& network_id) { + if (system_tray_client_) + system_tray_client_->ShowNetworkConfigure(network_id); +} + +void SystemTrayController::ShowNetworkCreate(const std::string& type) { + if (system_tray_client_) + system_tray_client_->ShowNetworkCreate(type); +} + +void SystemTrayController::ShowThirdPartyVpnCreate( + const std::string& extension_id) { + if (system_tray_client_) + system_tray_client_->ShowThirdPartyVpnCreate(extension_id); +} + +void SystemTrayController::ShowNetworkSettings(const std::string& network_id) { + if (system_tray_client_) + system_tray_client_->ShowNetworkSettings(network_id); +} + +void SystemTrayController::ShowProxySettings() { + if (system_tray_client_) + system_tray_client_->ShowProxySettings(); +} + +void SystemTrayController::SignOut() { + if (system_tray_client_) + system_tray_client_->SignOut(); +} + +void SystemTrayController::RequestRestartForUpdate() { + if (system_tray_client_) + system_tray_client_->RequestRestartForUpdate(); +} + +void SystemTrayController::BindRequest(mojom::SystemTrayRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void SystemTrayController::SetClient(mojom::SystemTrayClientPtr client) { + system_tray_client_ = std::move(client); +} + +void SystemTrayController::SetPrimaryTrayEnabled(bool enabled) { + ash::SystemTray* tray = + WmShell::Get()->GetPrimaryRootWindowController()->GetSystemTray(); + if (!tray) + return; + + // We disable the UI to prevent user from interacting with UI elements, + // particularly with the system tray menu. However, in case if the system tray + // bubble is opened at this point, it remains opened and interactive even + // after SystemTray::SetEnabled(false) call, which can be dangerous + // (http://crbug.com/497080). Close the menu to fix it. Calling + // SystemTray::SetEnabled(false) guarantees, that the menu will not be opened + // until the UI is enabled again. + if (!enabled && tray->HasSystemBubble()) + tray->CloseSystemBubble(); + + tray->SetEnabled(enabled); +} + +void SystemTrayController::SetPrimaryTrayVisible(bool visible) { + ash::SystemTray* tray = + WmShell::Get()->GetPrimaryRootWindowController()->GetSystemTray(); + if (!tray) + return; + + tray->SetVisible(visible); + tray->GetWidget()->SetOpacity(visible ? 1.f : 0.f); + if (visible) { + tray->GetWidget()->Show(); + } else { + tray->GetWidget()->Hide(); + } +} + +void SystemTrayController::SetUse24HourClock(bool use_24_hour) { + hour_clock_type_ = use_24_hour ? base::k24HourClock : base::k12HourClock; + WmShell::Get()->system_tray_notifier()->NotifyDateFormatChanged(); +} + +void SystemTrayController::ShowUpdateIcon(mojom::UpdateSeverity severity, + bool factory_reset_required) { + // Show the icon on all displays. + for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { + ash::SystemTray* tray = root->GetRootWindowController()->GetSystemTray(); + // External monitors might not have a tray yet. + if (!tray) + continue; + tray->tray_update()->ShowUpdateIcon(severity, factory_reset_required); + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_tray_controller.h b/ash/common/system/tray/system_tray_controller.h new file mode 100644 index 0000000..c2cb6d0 --- /dev/null +++ b/ash/common/system/tray/system_tray_controller.h
@@ -0,0 +1,82 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_CONTROLLER_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_CONTROLLER_H_ + +#include "ash/ash_export.h" +#include "ash/public/interfaces/system_tray.mojom.h" +#include "base/compiler_specific.h" +#include "base/i18n/time_formatting.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding_set.h" + +namespace ash { + +// Both implements mojom::SystemTray and wraps the mojom::SystemTrayClient +// interface. Implements both because it caches state pushed down from the +// browser process via SystemTray so it can be synchronously queried inside ash. +// +// Conceptually similar to historical ash-to-chrome interfaces like +// SystemTrayDelegate. Lives on the main thread. +// +// TODO: Consider renaming this to SystemTrayClient or renaming the current +// SystemTray to SystemTrayView and making this class SystemTray. +class ASH_EXPORT SystemTrayController + : NON_EXPORTED_BASE(public mojom::SystemTray) { + public: + SystemTrayController(); + ~SystemTrayController() override; + + base::HourClockType hour_clock_type() const { return hour_clock_type_; } + + // Wrappers around the mojom::SystemTrayClient interface. + void ShowSettings(); + void ShowDateSettings(); + void ShowSetTimeDialog(); + void ShowDisplaySettings(); + void ShowPowerSettings(); + void ShowChromeSlow(); + void ShowIMESettings(); + void ShowHelp(); + void ShowAccessibilityHelp(); + void ShowAccessibilitySettings(); + void ShowPaletteHelp(); + void ShowPaletteSettings(); + void ShowPublicAccountInfo(); + void ShowNetworkConfigure(const std::string& network_id); + void ShowNetworkCreate(const std::string& type); + void ShowThirdPartyVpnCreate(const std::string& extension_id); + void ShowNetworkSettings(const std::string& network_id); + void ShowProxySettings(); + void SignOut(); + void RequestRestartForUpdate(); + + // Binds the mojom::SystemTray interface to this object. + void BindRequest(mojom::SystemTrayRequest request); + + // mojom::SystemTray overrides. Public for testing. + void SetClient(mojom::SystemTrayClientPtr client) override; + void SetPrimaryTrayEnabled(bool enabled) override; + void SetPrimaryTrayVisible(bool visible) override; + void SetUse24HourClock(bool use_24_hour) override; + void ShowUpdateIcon(mojom::UpdateSeverity severity, + bool factory_reset_required) override; + + private: + // Client interface in chrome browser. Only bound on Chrome OS. + mojom::SystemTrayClientPtr system_tray_client_; + + // Bindings for the SystemTray interface. + mojo::BindingSet<mojom::SystemTray> bindings_; + + // The type of clock hour display: 12 or 24 hour. + base::HourClockType hour_clock_type_; + + DISALLOW_COPY_AND_ASSIGN(SystemTrayController); +}; + +} // namspace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_CONTROLLER_H_
diff --git a/ash/common/system/tray/system_tray_delegate.cc b/ash/common/system/tray/system_tray_delegate.cc new file mode 100644 index 0000000..3e250ba --- /dev/null +++ b/ash/common/system/tray/system_tray_delegate.cc
@@ -0,0 +1,153 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray_delegate.h" + +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/system_tray_item.h" + +namespace ash { + +BluetoothDeviceInfo::BluetoothDeviceInfo() + : connected(false), connecting(false), paired(false) {} + +BluetoothDeviceInfo::BluetoothDeviceInfo(const BluetoothDeviceInfo& other) = + default; + +BluetoothDeviceInfo::~BluetoothDeviceInfo() {} + +SystemTrayDelegate::SystemTrayDelegate() {} + +SystemTrayDelegate::~SystemTrayDelegate() {} + +void SystemTrayDelegate::Initialize() {} + +LoginStatus SystemTrayDelegate::GetUserLoginStatus() const { + return LoginStatus::NOT_LOGGED_IN; +} + +std::string SystemTrayDelegate::GetEnterpriseDomain() const { + return std::string(); +} + +std::string SystemTrayDelegate::GetEnterpriseRealm() const { + return std::string(); +} + +base::string16 SystemTrayDelegate::GetEnterpriseMessage() const { + return base::string16(); +} + +std::string SystemTrayDelegate::GetSupervisedUserManager() const { + return std::string(); +} + +base::string16 SystemTrayDelegate::GetSupervisedUserManagerName() const { + return base::string16(); +} + +base::string16 SystemTrayDelegate::GetSupervisedUserMessage() const { + return base::string16(); +} + +bool SystemTrayDelegate::IsUserSupervised() const { + return false; +} + +bool SystemTrayDelegate::IsUserChild() const { + return false; +} + +bool SystemTrayDelegate::ShouldShowSettings() const { + return false; +} + +bool SystemTrayDelegate::ShouldShowNotificationTray() const { + return false; +} + +void SystemTrayDelegate::ShowEnterpriseInfo() {} + +void SystemTrayDelegate::ShowUserLogin() {} + +void SystemTrayDelegate::GetAvailableBluetoothDevices( + BluetoothDeviceList* list) {} + +void SystemTrayDelegate::BluetoothStartDiscovering() {} + +void SystemTrayDelegate::BluetoothStopDiscovering() {} + +void SystemTrayDelegate::ConnectToBluetoothDevice(const std::string& address) {} + +void SystemTrayDelegate::GetCurrentIME(IMEInfo* info) {} + +void SystemTrayDelegate::GetAvailableIMEList(IMEInfoList* list) {} + +void SystemTrayDelegate::GetCurrentIMEProperties(IMEPropertyInfoList* list) {} + +base::string16 SystemTrayDelegate::GetIMEManagedMessage() { + return base::string16(); +} + +void SystemTrayDelegate::SwitchIME(const std::string& ime_id) {} + +void SystemTrayDelegate::ActivateIMEProperty(const std::string& key) {} + +void SystemTrayDelegate::ManageBluetoothDevices() {} + +void SystemTrayDelegate::ToggleBluetooth() {} + +bool SystemTrayDelegate::IsBluetoothDiscovering() const { + return false; +} + +bool SystemTrayDelegate::GetBluetoothAvailable() { + return false; +} + +bool SystemTrayDelegate::GetBluetoothEnabled() { + return false; +} + +bool SystemTrayDelegate::GetBluetoothDiscovering() { + return false; +} + +NetworkingConfigDelegate* SystemTrayDelegate::GetNetworkingConfigDelegate() + const { + return nullptr; +} + +bool SystemTrayDelegate::GetSessionStartTime( + base::TimeTicks* session_start_time) { + return false; +} + +bool SystemTrayDelegate::GetSessionLengthLimit( + base::TimeDelta* session_length_limit) { + return false; +} + +int SystemTrayDelegate::GetSystemTrayMenuWidth() { + return 0; +} + +void SystemTrayDelegate::ActiveUserWasChanged() {} + +bool SystemTrayDelegate::IsSearchKeyMappedToCapsLock() { + return false; +} + +void SystemTrayDelegate::AddCustodianInfoTrayObserver( + CustodianInfoTrayObserver* observer) {} + +void SystemTrayDelegate::RemoveCustodianInfoTrayObserver( + CustodianInfoTrayObserver* observer) {} + +std::unique_ptr<SystemTrayItem> SystemTrayDelegate::CreateRotationLockTrayItem( + SystemTray* tray) { + return nullptr; +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_tray_delegate.h b/ash/common/system/tray/system_tray_delegate.h new file mode 100644 index 0000000..eb99683 --- /dev/null +++ b/ash/common/system/tray/system_tray_delegate.h
@@ -0,0 +1,206 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_DELEGATE_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "base/callback_forward.h" +#include "base/files/file_path.h" +#include "base/i18n/time_formatting.h" +#include "base/strings/string16.h" + +namespace base { +class TimeDelta; +class TimeTicks; +} + +namespace device { +enum class BluetoothDeviceType; +} + +namespace ash { +struct IMEInfo; +struct IMEPropertyInfo; + +class CustodianInfoTrayObserver; +class SystemTray; +class SystemTrayItem; + +using IMEInfoList = std::vector<IMEInfo>; +using IMEPropertyInfoList = std::vector<IMEPropertyInfo>; + +struct ASH_EXPORT BluetoothDeviceInfo { + BluetoothDeviceInfo(); + BluetoothDeviceInfo(const BluetoothDeviceInfo& other); + ~BluetoothDeviceInfo(); + + std::string address; + base::string16 display_name; + bool connected; + bool connecting; + bool paired; + device::BluetoothDeviceType device_type; +}; + +using BluetoothDeviceList = std::vector<BluetoothDeviceInfo>; + +class NetworkingConfigDelegate; + +// SystemTrayDelegate is intended for delegating tasks in the System Tray to the +// application (e.g. Chrome). These tasks should be limited to application +// (browser) specific tasks. For non application specific tasks, where possible, +// components/, chromeos/, device/, etc., code should be used directly. If more +// than one related method is being added, consider adding an additional +// specific delegate (e.g. CastConfigDelegate). +// +// These methods should all have trivial default implementations for platforms +// that do not implement the method (e.g. return false or nullptr). This +// eliminates the need to propagate default implementations across the various +// implementations of this class. Consumers of this delegate should handle the +// default return value (e.g. nullptr). +class ASH_EXPORT SystemTrayDelegate { + public: + SystemTrayDelegate(); + virtual ~SystemTrayDelegate(); + + // Called after SystemTray has been instantiated. + virtual void Initialize(); + + // Gets information about the active user. + virtual LoginStatus GetUserLoginStatus() const; + + // Returns the domain that manages the device, if it is enterprise-enrolled. + virtual std::string GetEnterpriseDomain() const; + + // Returns the realm that manages the device, if it is enterprise enrolled + // with Active Directory and joined the realm (Active Directory domain). + virtual std::string GetEnterpriseRealm() const; + + // Returns notification for enterprise enrolled devices. + virtual base::string16 GetEnterpriseMessage() const; + + // Returns the display email of the user that manages the current supervised + // user. + virtual std::string GetSupervisedUserManager() const; + + // Returns the name of the user that manages the current supervised user. + virtual base::string16 GetSupervisedUserManagerName() const; + + // Returns the notification for supervised users. + virtual base::string16 GetSupervisedUserMessage() const; + + // Returns true if the current user is supervised: has legacy supervised + // account or kid account. + virtual bool IsUserSupervised() const; + + // Returns true if the current user is child. + // TODO(merkulova): remove on FakeUserManager componentization. + // crbug.com/443119 + virtual bool IsUserChild() const; + + // Returns true if settings menu item should appear. + virtual bool ShouldShowSettings() const; + + // Returns true if notification tray should appear. + virtual bool ShouldShowNotificationTray() const; + + // Shows information about enterprise enrolled devices. + virtual void ShowEnterpriseInfo(); + + // Shows login UI to add other users to this session. + virtual void ShowUserLogin(); + + // Returns a list of available bluetooth devices. + virtual void GetAvailableBluetoothDevices(BluetoothDeviceList* devices); + + // Requests bluetooth start discovering devices. + virtual void BluetoothStartDiscovering(); + + // Requests bluetooth stop discovering devices. + virtual void BluetoothStopDiscovering(); + + // Connect to a specific bluetooth device. + virtual void ConnectToBluetoothDevice(const std::string& address); + + // Returns true if bluetooth adapter is discovering bluetooth devices. + virtual bool IsBluetoothDiscovering() const; + + // Returns the currently selected IME. + virtual void GetCurrentIME(IMEInfo* info); + + // Returns a list of availble IMEs. + virtual void GetAvailableIMEList(IMEInfoList* list); + + // Returns a list of properties for the currently selected IME. + virtual void GetCurrentIMEProperties(IMEPropertyInfoList* list); + + // Returns a non-empty string if IMEs are managed by policy. + virtual base::string16 GetIMEManagedMessage(); + + // Switches to the selected input method. + virtual void SwitchIME(const std::string& ime_id); + + // Activates an IME property. + virtual void ActivateIMEProperty(const std::string& key); + + // Shows UI to manage bluetooth devices. + virtual void ManageBluetoothDevices(); + + // Toggles bluetooth. + virtual void ToggleBluetooth(); + + // Returns whether bluetooth capability is available. + virtual bool GetBluetoothAvailable(); + + // Returns whether bluetooth is enabled. + virtual bool GetBluetoothEnabled(); + + // Returns whether the delegate has initiated a bluetooth discovery session. + virtual bool GetBluetoothDiscovering(); + + // Returns NetworkingConfigDelegate. May return nullptr. + virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() const; + + // Retrieves the session start time. Returns |false| if the time is not set. + virtual bool GetSessionStartTime(base::TimeTicks* session_start_time); + + // Retrieves the session length limit. Returns |false| if no limit is set. + virtual bool GetSessionLengthLimit(base::TimeDelta* session_length_limit); + + // Get the system tray menu size in pixels (dependent on the language). + // This is not used in material design and should be removed during pre-MD + // code cleanup. See https://crbug.com/614453. + virtual int GetSystemTrayMenuWidth(); + + // The active user has been changed. This will be called when the UI is ready + // to be switched to the new user. + // Note: This will happen after SessionStateObserver::ActiveUserChanged fires. + virtual void ActiveUserWasChanged(); + + // Returns true when the Search key is configured to be treated as Caps Lock. + virtual bool IsSearchKeyMappedToCapsLock(); + + // Adding observers that are notified when supervised info is being changed. + virtual void AddCustodianInfoTrayObserver( + CustodianInfoTrayObserver* observer); + + virtual void RemoveCustodianInfoTrayObserver( + CustodianInfoTrayObserver* observer); + + // Creates a system tray item for display rotation lock. + // TODO(jamescook): Remove this when mus has support for display management + // and we have a DisplayManager equivalent. See http://crbug.com/548429 + virtual std::unique_ptr<SystemTrayItem> CreateRotationLockTrayItem( + SystemTray* tray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_DELEGATE_H_
diff --git a/ash/common/system/tray/system_tray_item.cc b/ash/common/system/tray/system_tray_item.cc new file mode 100644 index 0000000..ff1b7ee --- /dev/null +++ b/ash/common/system/tray/system_tray_item.cc
@@ -0,0 +1,68 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray_item.h" + +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "base/timer/timer.h" +#include "ui/views/view.h" + +namespace ash { + +SystemTrayItem::SystemTrayItem(SystemTray* system_tray, UmaType uma_type) + : system_tray_(system_tray), uma_type_(uma_type), restore_focus_(false) {} + +SystemTrayItem::~SystemTrayItem() {} + +views::View* SystemTrayItem::CreateTrayView(LoginStatus status) { + return nullptr; +} + +views::View* SystemTrayItem::CreateDefaultView(LoginStatus status) { + return nullptr; +} + +views::View* SystemTrayItem::CreateDetailedView(LoginStatus status) { + return nullptr; +} + +void SystemTrayItem::DestroyTrayView() {} + +void SystemTrayItem::DestroyDefaultView() {} + +void SystemTrayItem::DestroyDetailedView() {} + +void SystemTrayItem::TransitionDetailedView() { + transition_delay_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs), + base::Bind(&SystemTray::ShowDetailedView, base::Unretained(system_tray()), + this, 0, true, BUBBLE_USE_EXISTING)); +} + +void SystemTrayItem::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void SystemTrayItem::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { +} + +void SystemTrayItem::PopupDetailedView(int for_seconds, bool activate) { + system_tray()->ShowDetailedView(this, for_seconds, activate, + BUBBLE_CREATE_NEW); +} + +void SystemTrayItem::SetDetailedViewCloseDelay(int for_seconds) { + system_tray()->SetDetailedViewCloseDelay(for_seconds); +} + +void SystemTrayItem::HideDetailedView(bool animate) { + system_tray()->HideDetailedView(this, animate); +} + +bool SystemTrayItem::ShouldShowShelf() const { + return true; +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_tray_item.h b/ash/common/system/tray/system_tray_item.h new file mode 100644 index 0000000..cbf508f --- /dev/null +++ b/ash/common/system/tray/system_tray_item.h
@@ -0,0 +1,159 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_ITEM_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_ITEM_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "base/timer/timer.h" + +namespace views { +class View; +} + +namespace ash { +class SystemTray; +class SystemTrayBubble; +class TrayItemView; + +// Controller for an item in the system tray. Each item can create these views: +// Tray view - The icon in the status area in the shelf. +// Default view - The row in the top-level menu. +// Detailed view - The submenu shown when the top-level menu row is clicked. +class ASH_EXPORT SystemTrayItem { + public: + // The different types of SystemTrayItems. + // + // NOTE: These values are used for UMA metrics so do NOT re-order this enum + // and only insert items before the COUNT item. + enum UmaType { + // SystemTrayItem's with this type are not recorded in the histogram. + UMA_NOT_RECORDED = 0, + // Used for testing purposes only. + UMA_TEST = 1, + UMA_ACCESSIBILITY = 2, + UMA_AUDIO = 3, + UMA_BLUETOOTH = 4, + UMA_CAPS_LOCK = 5, + UMA_CAST = 6, + UMA_DATE = 7, + UMA_DISPLAY = 8, + UMA_DISPLAY_BRIGHTNESS = 9, + UMA_ENTERPRISE = 10, + UMA_IME = 11, + UMA_MULTI_PROFILE_MEDIA = 12, + UMA_NETWORK = 13, + UMA_SETTINGS = 14, + UMA_UPDATE = 15, + UMA_POWER = 16, + UMA_ROTATION_LOCK = 17, + UMA_SCREEN_CAPTURE = 18, + UMA_SCREEN_SHARE = 19, + UMA_SESSION_LENGTH_LIMIT = 20, + UMA_SMS = 21, + UMA_SUPERVISED_USER = 22, + UMA_TRACING = 23, + UMA_USER = 24, + UMA_VPN = 25, + UMA_COUNT = 26, + }; + + SystemTrayItem(SystemTray* system_tray, UmaType type); + virtual ~SystemTrayItem(); + + // Create* functions may return NULL if nothing should be displayed for the + // type of view. The default implementations return NULL. + + // Returns a view to be displayed in the system tray. If this returns NULL, + // then this item is not displayed in the tray. + // NOTE: The returned view should almost always be a TrayItemView, which + // automatically resizes the widget when the size of the view changes, and + // adds animation when the visibility of the view changes. If a view wants to + // avoid this behavior, then it should not be a TrayItemView. + virtual views::View* CreateTrayView(LoginStatus status); + + // Returns a view for the item to be displayed in the list. This view can be + // displayed with a number of other tray items, so this should not be too + // big. + virtual views::View* CreateDefaultView(LoginStatus status); + + // Returns a detailed view for the item. This view is displayed standalone. + virtual views::View* CreateDetailedView(LoginStatus status); + + // These functions are called when the corresponding view item is about to be + // removed. An item should do appropriate cleanup in these functions. + // The default implementation does nothing. + virtual void DestroyTrayView(); + virtual void DestroyDefaultView(); + virtual void DestroyDetailedView(); + + // Updates the tray view (if applicable) when the user's login status changes. + // It is not necessary the update the default or detailed view, since the + // default/detailed popup is closed when login status changes. The default + // implementation does nothing. + virtual void UpdateAfterLoginStatusChange(LoginStatus status); + + // Updates the tray view (if applicable) when shelf's alignment changes. + // The default implementation does nothing. + virtual void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment); + + // Shows the detailed view for this item. If the main popup for the tray is + // currently visible, then making this call would use the existing window to + // display the detailed item. The detailed item will inherit the bounds of the + // existing window. + // + // In Material Design the actual transition is intentionally delayed to allow + // the user to perceive the ink drop animation on the clicked target. + void TransitionDetailedView(); + + // Pops up the detailed view for this item. An item can request to show its + // detailed view using this function (e.g. from an observer callback when + // something, e.g. volume, network availability etc. changes). If + // |for_seconds| is non-zero, then the popup is closed after the specified + // time. + void PopupDetailedView(int for_seconds, bool activate); + + // Continue showing the currently-shown detailed view, if any, for + // |for_seconds| seconds. The caller is responsible for checking that the + // currently-shown view is for this item. + void SetDetailedViewCloseDelay(int for_seconds); + + // Hides the detailed view for this item. Disable hiding animation if + // |animate| is false. + void HideDetailedView(bool animate); + + // Returns true if this item needs to force the shelf to be visible when + // the shelf is in the auto-hide state. Default is true. + virtual bool ShouldShowShelf() const; + + // Returns the system tray that this item belongs to. + SystemTray* system_tray() const { return system_tray_; } + + bool restore_focus() const { return restore_focus_; } + void set_restore_focus(bool restore_focus) { restore_focus_ = restore_focus; } + + private: + // Accesses uma_type(). + friend class SystemTrayBubble; + + UmaType uma_type() const { return uma_type_; } + + SystemTray* system_tray_; + UmaType uma_type_; + bool restore_focus_; + + // Used to delay the transition to the detailed view. + base::OneShotTimer transition_delay_timer_; + + DISALLOW_COPY_AND_ASSIGN(SystemTrayItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_ITEM_H_
diff --git a/ash/common/system/tray/system_tray_notifier.cc b/ash/common/system/tray/system_tray_notifier.cc new file mode 100644 index 0000000..bfff62a --- /dev/null +++ b/ash/common/system/tray/system_tray_notifier.cc
@@ -0,0 +1,299 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray_notifier.h" + +#include "ash/common/system/accessibility_observer.h" +#include "ash/common/system/chromeos/bluetooth/bluetooth_observer.h" +#include "ash/common/system/chromeos/enterprise/enterprise_domain_observer.h" +#include "ash/common/system/chromeos/network/network_observer.h" +#include "ash/common/system/chromeos/network/network_portal_detector_observer.h" +#include "ash/common/system/chromeos/screen_security/screen_capture_observer.h" +#include "ash/common/system/chromeos/screen_security/screen_share_observer.h" +#include "ash/common/system/chromeos/session/last_window_closed_observer.h" +#include "ash/common/system/chromeos/session/logout_button_observer.h" +#include "ash/common/system/chromeos/session/session_length_limit_observer.h" +#include "ash/common/system/chromeos/tray_tracing.h" +#include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h" +#include "ash/common/system/date/clock_observer.h" +#include "ash/common/system/ime/ime_observer.h" +#include "ash/common/system/user/user_observer.h" + +namespace ash { + +SystemTrayNotifier::SystemTrayNotifier() {} + +SystemTrayNotifier::~SystemTrayNotifier() {} + +void SystemTrayNotifier::AddAccessibilityObserver( + AccessibilityObserver* observer) { + accessibility_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveAccessibilityObserver( + AccessibilityObserver* observer) { + accessibility_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyAccessibilityModeChanged( + AccessibilityNotificationVisibility notify) { + for (auto& observer : accessibility_observers_) + observer.OnAccessibilityModeChanged(notify); +} + +void SystemTrayNotifier::AddBluetoothObserver(BluetoothObserver* observer) { + bluetooth_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveBluetoothObserver(BluetoothObserver* observer) { + bluetooth_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyRefreshBluetooth() { + for (auto& observer : bluetooth_observers_) + observer.OnBluetoothRefresh(); +} + +void SystemTrayNotifier::NotifyBluetoothDiscoveringChanged() { + for (auto& observer : bluetooth_observers_) + observer.OnBluetoothDiscoveringChanged(); +} + +void SystemTrayNotifier::AddClockObserver(ClockObserver* observer) { + clock_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveClockObserver(ClockObserver* observer) { + clock_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyRefreshClock() { + for (auto& observer : clock_observers_) + observer.Refresh(); +} + +void SystemTrayNotifier::NotifyDateFormatChanged() { + for (auto& observer : clock_observers_) + observer.OnDateFormatChanged(); +} + +void SystemTrayNotifier::NotifySystemClockTimeUpdated() { + for (auto& observer : clock_observers_) + observer.OnSystemClockTimeUpdated(); +} + +void SystemTrayNotifier::NotifySystemClockCanSetTimeChanged(bool can_set_time) { + for (auto& observer : clock_observers_) + observer.OnSystemClockCanSetTimeChanged(can_set_time); +} + +void SystemTrayNotifier::AddEnterpriseDomainObserver( + EnterpriseDomainObserver* observer) { + enterprise_domain_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveEnterpriseDomainObserver( + EnterpriseDomainObserver* observer) { + enterprise_domain_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyEnterpriseDomainChanged() { + for (auto& observer : enterprise_domain_observers_) + observer.OnEnterpriseDomainChanged(); +} + +void SystemTrayNotifier::AddIMEObserver(IMEObserver* observer) { + ime_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveIMEObserver(IMEObserver* observer) { + ime_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyRefreshIME() { + for (auto& observer : ime_observers_) + observer.OnIMERefresh(); +} + +void SystemTrayNotifier::NotifyRefreshIMEMenu(bool is_active) { + for (auto& observer : ime_observers_) + observer.OnIMEMenuActivationChanged(is_active); +} + +void SystemTrayNotifier::AddLastWindowClosedObserver( + LastWindowClosedObserver* observer) { + last_window_closed_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveLastWindowClosedObserver( + LastWindowClosedObserver* observer) { + last_window_closed_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyLastWindowClosed() { + for (auto& observer : last_window_closed_observers_) + observer.OnLastWindowClosed(); +} + +void SystemTrayNotifier::AddLogoutButtonObserver( + LogoutButtonObserver* observer) { + logout_button_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveLogoutButtonObserver( + LogoutButtonObserver* observer) { + logout_button_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyShowLoginButtonChanged(bool show_login_button) { + for (auto& observer : logout_button_observers_) + observer.OnShowLogoutButtonInTrayChanged(show_login_button); +} + +void SystemTrayNotifier::NotifyLogoutDialogDurationChanged( + base::TimeDelta duration) { + for (auto& observer : logout_button_observers_) + observer.OnLogoutDialogDurationChanged(duration); +} + +void SystemTrayNotifier::AddNetworkObserver(NetworkObserver* observer) { + network_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveNetworkObserver(NetworkObserver* observer) { + network_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyRequestToggleWifi() { + for (auto& observer : network_observers_) + observer.RequestToggleWifi(); +} + +void SystemTrayNotifier::AddNetworkPortalDetectorObserver( + NetworkPortalDetectorObserver* observer) { + network_portal_detector_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveNetworkPortalDetectorObserver( + NetworkPortalDetectorObserver* observer) { + network_portal_detector_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyOnCaptivePortalDetected( + const std::string& guid) { + for (auto& observer : network_portal_detector_observers_) + observer.OnCaptivePortalDetected(guid); +} + +void SystemTrayNotifier::AddScreenCaptureObserver( + ScreenCaptureObserver* observer) { + screen_capture_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveScreenCaptureObserver( + ScreenCaptureObserver* observer) { + screen_capture_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyScreenCaptureStart( + const base::Closure& stop_callback, + const base::string16& sharing_app_name) { + for (auto& observer : screen_capture_observers_) + observer.OnScreenCaptureStart(stop_callback, sharing_app_name); +} + +void SystemTrayNotifier::NotifyScreenCaptureStop() { + for (auto& observer : screen_capture_observers_) + observer.OnScreenCaptureStop(); +} + +void SystemTrayNotifier::AddScreenShareObserver(ScreenShareObserver* observer) { + screen_share_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveScreenShareObserver( + ScreenShareObserver* observer) { + screen_share_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyScreenShareStart( + const base::Closure& stop_callback, + const base::string16& helper_name) { + for (auto& observer : screen_share_observers_) + observer.OnScreenShareStart(stop_callback, helper_name); +} + +void SystemTrayNotifier::NotifyScreenShareStop() { + for (auto& observer : screen_share_observers_) + observer.OnScreenShareStop(); +} + +void SystemTrayNotifier::AddSessionLengthLimitObserver( + SessionLengthLimitObserver* observer) { + session_length_limit_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveSessionLengthLimitObserver( + SessionLengthLimitObserver* observer) { + session_length_limit_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifySessionStartTimeChanged() { + for (auto& observer : session_length_limit_observers_) + observer.OnSessionStartTimeChanged(); +} + +void SystemTrayNotifier::NotifySessionLengthLimitChanged() { + for (auto& observer : session_length_limit_observers_) + observer.OnSessionLengthLimitChanged(); +} + +void SystemTrayNotifier::AddTracingObserver(TracingObserver* observer) { + tracing_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveTracingObserver(TracingObserver* observer) { + tracing_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyTracingModeChanged(bool value) { + for (auto& observer : tracing_observers_) + observer.OnTracingModeChanged(value); +} + +void SystemTrayNotifier::AddUserObserver(UserObserver* observer) { + user_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveUserObserver(UserObserver* observer) { + user_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyUserUpdate() { + for (auto& observer : user_observers_) + observer.OnUserUpdate(); +} + +void SystemTrayNotifier::NotifyUserAddedToSession() { + for (auto& observer : user_observers_) + observer.OnUserAddedToSession(); +} + +void SystemTrayNotifier::AddVirtualKeyboardObserver( + VirtualKeyboardObserver* observer) { + virtual_keyboard_observers_.AddObserver(observer); +} + +void SystemTrayNotifier::RemoveVirtualKeyboardObserver( + VirtualKeyboardObserver* observer) { + virtual_keyboard_observers_.RemoveObserver(observer); +} + +void SystemTrayNotifier::NotifyVirtualKeyboardSuppressionChanged( + bool suppressed) { + for (auto& observer : virtual_keyboard_observers_) + observer.OnKeyboardSuppressionChanged(suppressed); +} + +} // namespace ash
diff --git a/ash/common/system/tray/system_tray_notifier.h b/ash/common/system/tray/system_tray_notifier.h new file mode 100644 index 0000000..1b80a67 --- /dev/null +++ b/ash/common/system/tray/system_tray_notifier.h
@@ -0,0 +1,160 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_NOTIFIER_H_ +#define ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_NOTIFIER_H_ + +#include <string> + +#include "ash/ash_export.h" +#include "ash/common/accessibility_types.h" +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/strings/string16.h" +#include "base/time/time.h" + +namespace ash { + +class AccessibilityObserver; +class BluetoothObserver; +class ClockObserver; +class EnterpriseDomainObserver; +class IMEObserver; +class LastWindowClosedObserver; +class LogoutButtonObserver; +class NetworkObserver; +class NetworkPortalDetectorObserver; +class ScreenCaptureObserver; +class ScreenShareObserver; +class SessionLengthLimitObserver; +class TracingObserver; +class UserObserver; +class VirtualKeyboardObserver; + +namespace mojom { +enum class UpdateSeverity; +} + +// Observer and notification manager for the ash system tray. +class ASH_EXPORT SystemTrayNotifier { + public: + SystemTrayNotifier(); + ~SystemTrayNotifier(); + + // Accessibility. + void AddAccessibilityObserver(AccessibilityObserver* observer); + void RemoveAccessibilityObserver(AccessibilityObserver* observer); + void NotifyAccessibilityModeChanged( + AccessibilityNotificationVisibility notify); + + // Bluetooth. + void AddBluetoothObserver(BluetoothObserver* observer); + void RemoveBluetoothObserver(BluetoothObserver* observer); + void NotifyRefreshBluetooth(); + void NotifyBluetoothDiscoveringChanged(); + + // Date and time. + void AddClockObserver(ClockObserver* observer); + void RemoveClockObserver(ClockObserver* observer); + void NotifyRefreshClock(); + void NotifyDateFormatChanged(); + void NotifySystemClockTimeUpdated(); + void NotifySystemClockCanSetTimeChanged(bool can_set_time); + + // Enterprise domain. + void AddEnterpriseDomainObserver(EnterpriseDomainObserver* observer); + void RemoveEnterpriseDomainObserver(EnterpriseDomainObserver* observer); + void NotifyEnterpriseDomainChanged(); + + // Input methods. + void AddIMEObserver(IMEObserver* observer); + void RemoveIMEObserver(IMEObserver* observer); + void NotifyRefreshIME(); + void NotifyRefreshIMEMenu(bool is_active); + + // Last window closed. + void AddLastWindowClosedObserver(LastWindowClosedObserver* observer); + void RemoveLastWindowClosedObserver(LastWindowClosedObserver* observer); + void NotifyLastWindowClosed(); + + // Logout button. + void AddLogoutButtonObserver(LogoutButtonObserver* observer); + void RemoveLogoutButtonObserver(LogoutButtonObserver* observer); + void NotifyShowLoginButtonChanged(bool show_login_button); + void NotifyLogoutDialogDurationChanged(base::TimeDelta duration); + + // Network. + void AddNetworkObserver(NetworkObserver* observer); + void RemoveNetworkObserver(NetworkObserver* observer); + void NotifyRequestToggleWifi(); + + // Network portal detector. + void AddNetworkPortalDetectorObserver( + NetworkPortalDetectorObserver* observer); + void RemoveNetworkPortalDetectorObserver( + NetworkPortalDetectorObserver* observer); + void NotifyOnCaptivePortalDetected(const std::string& guid); + + // Screen capture. + void AddScreenCaptureObserver(ScreenCaptureObserver* observer); + void RemoveScreenCaptureObserver(ScreenCaptureObserver* observer); + void NotifyScreenCaptureStart(const base::Closure& stop_callback, + const base::string16& sharing_app_name); + void NotifyScreenCaptureStop(); + + // Screen share. + void AddScreenShareObserver(ScreenShareObserver* observer); + void RemoveScreenShareObserver(ScreenShareObserver* observer); + void NotifyScreenShareStart(const base::Closure& stop_callback, + const base::string16& helper_name); + void NotifyScreenShareStop(); + + // Session length limit. + void AddSessionLengthLimitObserver(SessionLengthLimitObserver* observer); + void RemoveSessionLengthLimitObserver(SessionLengthLimitObserver* observer); + void NotifySessionStartTimeChanged(); + void NotifySessionLengthLimitChanged(); + + // Tracing. + void AddTracingObserver(TracingObserver* observer); + void RemoveTracingObserver(TracingObserver* observer); + void NotifyTracingModeChanged(bool value); + + // User. + void AddUserObserver(UserObserver* observer); + void RemoveUserObserver(UserObserver* observer); + void NotifyUserUpdate(); + void NotifyUserAddedToSession(); + + // Virtual keyboard. + void AddVirtualKeyboardObserver(VirtualKeyboardObserver* observer); + void RemoveVirtualKeyboardObserver(VirtualKeyboardObserver* observer); + void NotifyVirtualKeyboardSuppressionChanged(bool suppressed); + + private: + base::ObserverList<AccessibilityObserver> accessibility_observers_; + base::ObserverList<BluetoothObserver> bluetooth_observers_; + base::ObserverList<ClockObserver> clock_observers_; + base::ObserverList<EnterpriseDomainObserver> enterprise_domain_observers_; + base::ObserverList<IMEObserver> ime_observers_; + base::ObserverList<LastWindowClosedObserver> last_window_closed_observers_; + base::ObserverList<LogoutButtonObserver> logout_button_observers_; + base::ObserverList<NetworkObserver> network_observers_; + base::ObserverList<NetworkPortalDetectorObserver> + network_portal_detector_observers_; + base::ObserverList<ScreenCaptureObserver> screen_capture_observers_; + base::ObserverList<ScreenShareObserver> screen_share_observers_; + base::ObserverList<SessionLengthLimitObserver> + session_length_limit_observers_; + base::ObserverList<TracingObserver> tracing_observers_; + base::ObserverList<UserObserver> user_observers_; + base::ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; + + DISALLOW_COPY_AND_ASSIGN(SystemTrayNotifier); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_SYSTEM_TRAY_NOTIFIER_H_
diff --git a/ash/common/system/tray/system_tray_unittest.cc b/ash/common/system/tray/system_tray_unittest.cc new file mode 100644 index 0000000..4b3123c --- /dev/null +++ b/ash/common/system/tray/system_tray_unittest.cc
@@ -0,0 +1,562 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/system_tray.h" + +#include <string> +#include <vector> + +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accessibility_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray_bubble.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_container.h" +#include "ash/common/system/web_notification/web_notification_tray.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/status_area_widget_test_helper.h" +#include "ash/test/test_system_tray_item.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/histogram_tester.h" +#include "ui/base/ui_base_types.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/events/test/event_generator.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/controls/separator.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { +namespace test { + +namespace { + +const char kVisibleRowsHistogramName[] = + "Ash.SystemMenu.DefaultView.VisibleRows"; + +class ModalWidgetDelegate : public views::WidgetDelegateView { + public: + ModalWidgetDelegate() {} + ~ModalWidgetDelegate() override {} + + ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_SYSTEM; } + + private: + DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate); +}; + +} // namespace + +typedef AshTestBase SystemTrayTest; + +// Verifies only the visible default views are recorded in the +// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. +TEST_F(SystemTrayTest, OnlyVisibleItemsRecorded) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(test_item)); + + base::HistogramTester histogram_tester; + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 1); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 2); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); + + test_item->set_views_are_visible(false); + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 2); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); +} + +// Verifies a visible UMA_NOT_RECORDED default view is not recorded in the +// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. +TEST_F(SystemTrayTest, NotRecordedtemsAreNotRecorded) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = + new TestSystemTrayItem(SystemTrayItem::UMA_NOT_RECORDED); + tray->AddTrayItem(base::WrapUnique(test_item)); + + base::HistogramTester histogram_tester; + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_NOT_RECORDED, 0); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); +} + +// Verifies null default views are not recorded in the +// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. +TEST_F(SystemTrayTest, NullDefaultViewIsNotRecorded) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + test_item->set_has_views(false); + tray->AddTrayItem(base::WrapUnique(test_item)); + + base::HistogramTester histogram_tester; + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 0); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); +} + +// Verifies visible detailed views are not recorded in the +// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. +TEST_F(SystemTrayTest, VisibleDetailedViewsIsNotRecorded) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(test_item)); + + base::HistogramTester histogram_tester; + + tray->ShowDetailedView(test_item, 0, false, BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + + histogram_tester.ExpectTotalCount(kVisibleRowsHistogramName, 0); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); +} + +// Verifies visible default views are not recorded for menu re-shows in the +// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. +TEST_F(SystemTrayTest, VisibleDefaultViewIsNotRecordedOnReshow) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(test_item)); + + base::HistogramTester histogram_tester; + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 1); + + tray->ShowDetailedView(test_item, 0, false, BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 1); + + tray->ShowDefaultView(BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, + SystemTrayItem::UMA_TEST, 1); + + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); +} + +TEST_F(SystemTrayTest, SystemTrayDefaultView) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + + // Ensure that closing the bubble destroys it. + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); + ASSERT_FALSE(tray->CloseSystemBubble()); +} + +// Make sure the opening system tray bubble will not deactivate the +// other window. crbug.com/120680. +TEST_F(SystemTrayTest, Activation) { + // TODO: investigate why this fails in mash. http://crbug.com/695559. + if (WmShell::Get()->IsRunningInMash()) + return; + + SystemTray* tray = GetPrimarySystemTray(); + std::unique_ptr<views::Widget> widget(CreateTestWidget( + nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100))); + EXPECT_TRUE(widget->IsActive()); + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + ASSERT_TRUE(tray->GetWidget()); + EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive()); + EXPECT_TRUE(widget->IsActive()); + + tray->ActivateBubble(); + EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive()); + EXPECT_FALSE(widget->IsActive()); + + // Accelerator will activate the bubble. + tray->CloseSystemBubble(); + + EXPECT_TRUE(widget->IsActive()); + WmShell::Get()->accelerator_controller()->PerformActionIfEnabled( + SHOW_SYSTEM_TRAY_BUBBLE); + EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive()); + EXPECT_FALSE(widget->IsActive()); +} + +// Opening and closing the bubble should change the coloring of the tray. +TEST_F(SystemTrayTest, SystemTrayColoring) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + // At the beginning the tray coloring is not active. + ASSERT_FALSE(tray->is_active()); + + // Showing the system bubble should show the background as active. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + ASSERT_TRUE(tray->is_active()); + + // Closing the system menu should change the coloring back to normal. + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); + ASSERT_FALSE(tray->is_active()); +} + +// Closing the system bubble through an alignment change should change the +// system tray coloring back to normal. +TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + WmShelf* shelf = GetPrimaryShelf(); + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + // At the beginning the tray coloring is not active. + ASSERT_FALSE(tray->is_active()); + + // Showing the system bubble should show the background as active. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + ASSERT_TRUE(tray->is_active()); + + // Changing the alignment should close the system bubble and change the + // background color. + shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); + ASSERT_FALSE(tray->is_active()); + RunAllPendingInMessageLoop(); + // The bubble should already be closed by now. + ASSERT_FALSE(tray->CloseSystemBubble()); +} + +TEST_F(SystemTrayTest, SystemTrayTestItems) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + TestSystemTrayItem* detailed_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(test_item)); + tray->AddTrayItem(base::WrapUnique(detailed_item)); + + // Check items have been added. + std::vector<SystemTrayItem*> items = tray->GetTrayItems(); + ASSERT_TRUE(std::find(items.begin(), items.end(), test_item) != items.end()); + ASSERT_TRUE(std::find(items.begin(), items.end(), detailed_item) != + items.end()); + + // Ensure the tray views are created. + ASSERT_TRUE(test_item->tray_view() != NULL); + ASSERT_TRUE(detailed_item->tray_view() != NULL); + + // Ensure a default views are created. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + ASSERT_TRUE(test_item->default_view() != NULL); + ASSERT_TRUE(detailed_item->default_view() != NULL); + + // Show the detailed view, ensure it's created and the default view destroyed. + tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + ASSERT_TRUE(test_item->default_view() == NULL); + ASSERT_TRUE(detailed_item->detailed_view() != NULL); + + // Show the default view, ensure it's created and the detailed view destroyed. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + ASSERT_TRUE(test_item->default_view() != NULL); + ASSERT_TRUE(detailed_item->detailed_view() == NULL); +} + +TEST_F(SystemTrayTest, SystemTrayNoViewItems) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + // Verify that no crashes occur on items lacking some views. + TestSystemTrayItem* no_view_item = new TestSystemTrayItem(); + no_view_item->set_has_views(false); + tray->AddTrayItem(base::WrapUnique(no_view_item)); + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + tray->ShowDetailedView(no_view_item, 0, false, BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); +} + +TEST_F(SystemTrayTest, TrayWidgetAutoResizes) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + // Add an initial tray item so that the tray gets laid out correctly. + TestSystemTrayItem* initial_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(initial_item)); + + gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size(); + + TestSystemTrayItem* new_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(new_item)); + + gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size(); + + // Adding the new item should change the size of the tray. + EXPECT_NE(initial_size.ToString(), new_size.ToString()); + + // Hiding the tray view of the new item should also change the size of the + // tray. + new_item->tray_view()->SetVisible(false); + EXPECT_EQ(initial_size.ToString(), + tray->GetWidget()->GetWindowBoundsInScreen().size().ToString()); + + new_item->tray_view()->SetVisible(true); + EXPECT_EQ(new_size.ToString(), + tray->GetWidget()->GetWindowBoundsInScreen().size().ToString()); +} + +// Test is flaky. http://crbug.com/637978 +TEST_F(SystemTrayTest, DISABLED_BubbleCreationTypesTest) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(test_item)); + + // Ensure the tray views are created. + ASSERT_TRUE(test_item->tray_view() != NULL); + + // Show the default view, ensure the notification view is destroyed. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + + views::Widget* widget = test_item->default_view()->GetWidget(); + gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen(); + + tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + + EXPECT_FALSE(test_item->default_view()); + + EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view() + ->GetWidget() + ->GetWindowBoundsInScreen() + .ToString()); + EXPECT_EQ(widget, test_item->detailed_view()->GetWidget()); + + tray->ShowDefaultView(BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + + EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view() + ->GetWidget() + ->GetWindowBoundsInScreen() + .ToString()); + EXPECT_EQ(widget, test_item->default_view()->GetWidget()); +} + +// Tests that the tray view is laid out properly and is fully contained within +// the shelf widget. +TEST_F(SystemTrayTest, TrayBoundsInWidget) { + WmShelf* shelf = GetPrimaryShelf(); + StatusAreaWidget* widget = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); + SystemTray* tray = GetPrimarySystemTray(); + + // Test in bottom alignment. + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + gfx::Rect window_bounds = widget->GetWindowBoundsInScreen(); + gfx::Rect tray_bounds = tray->GetBoundsInScreen(); + EXPECT_TRUE(window_bounds.Contains(tray_bounds)); + + // Test in locked alignment. + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM_LOCKED); + window_bounds = widget->GetWindowBoundsInScreen(); + tray_bounds = tray->GetBoundsInScreen(); + EXPECT_TRUE(window_bounds.Contains(tray_bounds)); + + // Test in the left alignment. + shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); + window_bounds = widget->GetWindowBoundsInScreen(); + tray_bounds = tray->GetBoundsInScreen(); + // TODO(estade): Re-enable this check. See crbug.com/660928. + // EXPECT_TRUE(window_bounds.Contains(tray_bounds)); + + // Test in the right alignment. + shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); + window_bounds = widget->GetWindowBoundsInScreen(); + tray_bounds = tray->GetBoundsInScreen(); + // TODO(estade): Re-enable this check. See crbug.com/660928. + // EXPECT_TRUE(window_bounds.Contains(tray_bounds)); +} + +TEST_F(SystemTrayTest, PersistentBubble) { + // TODO: investigate why this fails in mash. http://crbug.com/695559. + if (WmShell::Get()->IsRunningInMash()) + return; + + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestSystemTrayItem* test_item = new TestSystemTrayItem(); + tray->AddTrayItem(base::WrapUnique(test_item)); + + std::unique_ptr<views::Widget> widget(CreateTestWidget( + nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100))); + + // Tests for usual default view while activating a window. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + tray->ActivateBubble(); + ASSERT_TRUE(tray->HasSystemBubble()); + widget->Activate(); + base::RunLoop().RunUntilIdle(); + ASSERT_FALSE(tray->HasSystemBubble()); + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + ASSERT_TRUE(tray->HasSystemBubble()); + { + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.set_current_location(gfx::Point(5, 5)); + generator.ClickLeftButton(); + ASSERT_FALSE(tray->HasSystemBubble()); + } + + // Same tests for persistent default view. + tray->ShowPersistentDefaultView(); + ASSERT_TRUE(tray->HasSystemBubble()); + widget->Activate(); + base::RunLoop().RunUntilIdle(); + ASSERT_TRUE(tray->HasSystemBubble()); + + { + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.set_current_location(gfx::Point(5, 5)); + generator.ClickLeftButton(); + ASSERT_TRUE(tray->HasSystemBubble()); + } + + // Same tests for persistent default view with activation. + tray->ShowPersistentDefaultView(); + EXPECT_TRUE(tray->HasSystemBubble()); + widget->Activate(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(tray->HasSystemBubble()); + + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.set_current_location(gfx::Point(5, 5)); + generator.ClickLeftButton(); + EXPECT_TRUE(tray->HasSystemBubble()); +} + +TEST_F(SystemTrayTest, WithSystemModal) { + // Check if the accessibility item is created even with system modal dialog. + WmShell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(true); + std::unique_ptr<views::Widget> widget(CreateTestWidget( + new ModalWidgetDelegate, kShellWindowId_SystemModalContainer, + gfx::Rect(0, 0, 100, 100))); + + SystemTray* tray = GetPrimarySystemTray(); + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + + ASSERT_TRUE(tray->HasSystemBubble()); + const views::View* accessibility = + tray->GetSystemBubble()->bubble_view()->GetViewByID( + test::kAccessibilityTrayItemViewId); + ASSERT_TRUE(accessibility); + EXPECT_TRUE(accessibility->visible()); + EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetViewByID( + test::kSettingsTrayItemViewId)); + + // Close the modal dialog. + widget.reset(); + + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + // System modal is gone. The bubble should now contains settings + // as well. + accessibility = tray->GetSystemBubble()->bubble_view()->GetViewByID( + test::kAccessibilityTrayItemViewId); + ASSERT_TRUE(accessibility); + EXPECT_TRUE(accessibility->visible()); +} + +// Tests that if SetVisible(true) is called while animating to hidden that the +// tray becomes visible, and stops animating to hidden. +TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->visible()); + + std::unique_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration; + animation_duration.reset(new ui::ScopedAnimationDurationScaleMode( + ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); + tray->SetVisible(false); + EXPECT_TRUE(tray->visible()); + EXPECT_EQ(0.0f, tray->layer()->GetTargetOpacity()); + + tray->SetVisible(true); + animation_duration.reset(); + tray->layer()->GetAnimator()->StopAnimating(); + EXPECT_TRUE(tray->visible()); + EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity()); +} + +TEST_F(SystemTrayTest, SystemTrayHeightWithBubble) { + SystemTray* tray = GetPrimarySystemTray(); + WebNotificationTray* notification_tray = + StatusAreaWidgetTestHelper::GetStatusAreaWidget() + ->web_notification_tray(); + + // Ensure the initial tray bubble height is zero. + EXPECT_EQ(0, notification_tray->tray_bubble_height_for_test()); + + // Show the default view, ensure the tray bubble height is changed. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + EXPECT_LT(0, notification_tray->tray_bubble_height_for_test()); + + // Hide the default view, ensure the tray bubble height is back to zero. + ASSERT_TRUE(tray->CloseSystemBubble()); + RunAllPendingInMessageLoop(); + + EXPECT_EQ(0, notification_tray->tray_bubble_height_for_test()); +} + +TEST_F(SystemTrayTest, SeparatorThickness) { + EXPECT_EQ(kSeparatorWidth, views::Separator::kThickness); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/system/tray/throbber_view.cc b/ash/common/system/tray/throbber_view.cc new file mode 100644 index 0000000..e345fdc7 --- /dev/null +++ b/ash/common/system/tray/throbber_view.cc
@@ -0,0 +1,97 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/throbber_view.h" + +#include "ash/common/system/tray/tray_constants.h" +#include "ash/resources/grit/ash_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" + +namespace ash { +namespace { + +// Duration for showing/hiding animation in milliseconds. +const int kThrobberAnimationDurationMs = 200; + +} // namespace + +SystemTrayThrobber::SystemTrayThrobber() : views::SmoothedThrobber() {} + +SystemTrayThrobber::~SystemTrayThrobber() {} + +void SystemTrayThrobber::SetTooltipText(const base::string16& tooltip_text) { + tooltip_text_ = tooltip_text; +} + +bool SystemTrayThrobber::GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const { + if (tooltip_text_.empty()) + return false; + + *tooltip = tooltip_text_; + return true; +} + +ThrobberView::ThrobberView() { + throbber_ = new SystemTrayThrobber(); + throbber_->set_stop_delay_ms(kThrobberAnimationDurationMs); + AddChildView(throbber_); + + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + layer()->SetOpacity(0.0); +} + +ThrobberView::~ThrobberView() {} + +gfx::Size ThrobberView::GetPreferredSize() const { + return gfx::Size(kTrayPopupItemMinHeight, kTrayPopupItemMinHeight); +} + +void ThrobberView::Layout() { + View* child = child_at(0); + gfx::Size ps = child->GetPreferredSize(); + child->SetBounds((width() - ps.width()) / 2, (height() - ps.height()) / 2, + ps.width(), ps.height()); + SizeToPreferredSize(); +} + +bool ThrobberView::GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const { + if (tooltip_text_.empty()) + return false; + + *tooltip = tooltip_text_; + return true; +} + +void ThrobberView::Start() { + ScheduleAnimation(true); + throbber_->Start(); +} + +void ThrobberView::Stop() { + ScheduleAnimation(false); + throbber_->Stop(); +} + +void ThrobberView::SetTooltipText(const base::string16& tooltip_text) { + tooltip_text_ = tooltip_text; + throbber_->SetTooltipText(tooltip_text); +} + +void ThrobberView::ScheduleAnimation(bool start_throbber) { + // Stop any previous animation. + layer()->GetAnimator()->StopAnimating(); + + ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); + animation.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kThrobberAnimationDurationMs)); + + layer()->SetOpacity(start_throbber ? 1.0 : 0.0); +} + +} // namespace ash
diff --git a/ash/common/system/tray/throbber_view.h b/ash/common/system/tray/throbber_view.h new file mode 100644 index 0000000..9b3332b4 --- /dev/null +++ b/ash/common/system/tray/throbber_view.h
@@ -0,0 +1,64 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_THROBBER_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_THROBBER_VIEW_H_ + +#include "base/macros.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/controls/throbber.h" +#include "ui/views/view.h" + +namespace ash { + +// A SmoothedThrobber with tooltip. +class SystemTrayThrobber : public views::SmoothedThrobber { + public: + SystemTrayThrobber(); + ~SystemTrayThrobber() override; + + void SetTooltipText(const base::string16& tooltip_text); + + // Overriden from views::View. + bool GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const override; + + private: + // The current tooltip text. + base::string16 tooltip_text_; + + DISALLOW_COPY_AND_ASSIGN(SystemTrayThrobber); +}; + +// A View containing a SystemTrayThrobber with animation for starting/stopping. +class ThrobberView : public views::View { + public: + ThrobberView(); + ~ThrobberView() override; + + void Start(); + void Stop(); + void SetTooltipText(const base::string16& tooltip_text); + + // Overriden from views::View. + gfx::Size GetPreferredSize() const override; + void Layout() override; + bool GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const override; + + private: + // Schedules animation for starting/stopping throbber. + void ScheduleAnimation(bool start_throbber); + + SystemTrayThrobber* throbber_; + + // The current tooltip text. + base::string16 tooltip_text_; + + DISALLOW_COPY_AND_ASSIGN(ThrobberView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_THROBBER_VIEW_H_
diff --git a/ash/common/system/tray/tray_background_view.cc b/ash/common/system/tray/tray_background_view.cc new file mode 100644 index 0000000..7297e15 --- /dev/null +++ b/ash/common/system/tray/tray_background_view.cc
@@ -0,0 +1,622 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_background_view.h" + +#include <algorithm> + +#include "ash/common/ash_constants.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_event_filter.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "base/memory/ptr_util.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/nine_image_painter_factory.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/layer_animation_element.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/events/event_constants.h" +#include "ui/gfx/animation/tween.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/nine_image_painter.h" +#include "ui/gfx/scoped_canvas.h" +#include "ui/gfx/skia_util.h" +#include "ui/gfx/transform.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_highlight.h" +#include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/background.h" +#include "ui/views/layout/box_layout.h" +#include "ui/wm/core/window_animations.h" + +namespace { + +const int kAnimationDurationForPopupMs = 200; + +// Duration of opacity animation for visibility changes. +const int kAnimationDurationForVisibilityMs = 250; + +// When becoming visible delay the animation so that StatusAreaWidgetDelegate +// can animate sibling views out of the position to be occuped by the +// TrayBackgroundView. +const int kShowAnimationDelayMs = 100; + +// Additional padding used to adjust the user-visible size of status tray +// and overview button dark background. +const int kBackgroundAdjustPadding = 3; + +// Switches left and right insets if RTL mode is active. +void MirrorInsetsIfNecessary(gfx::Insets* insets) { + if (base::i18n::IsRTL()) { + insets->Set(insets->top(), insets->right(), insets->bottom(), + insets->left()); + } +} + +// Returns background insets relative to the contents bounds of the view and +// mirrored if RTL mode is active. +gfx::Insets GetMirroredBackgroundInsets(ash::ShelfAlignment shelf_alignment) { + gfx::Insets insets; + if (IsHorizontalAlignment(shelf_alignment)) { + insets.Set(0, ash::kHitRegionPadding, 0, + ash::kHitRegionPadding + ash::kSeparatorWidth); + } else { + insets.Set(ash::kHitRegionPadding, 0, + ash::kHitRegionPadding + ash::kSeparatorWidth, 0); + } + MirrorInsetsIfNecessary(&insets); + return insets; +} + +} // namespace + +using views::TrayBubbleView; + +namespace ash { + +// static +const char TrayBackgroundView::kViewClassName[] = "tray/TrayBackgroundView"; + +// Used to track when the anchor widget changes position on screen so that the +// bubble position can be updated. +class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver { + public: + explicit TrayWidgetObserver(TrayBackgroundView* host) : host_(host) {} + + void OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) override { + host_->AnchorUpdated(); + } + + void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override { + host_->AnchorUpdated(); + } + + private: + TrayBackgroundView* host_; + + DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver); +}; + +class TrayBackground : public views::Background { + public: + TrayBackground(TrayBackgroundView* tray_background_view, bool draws_active) + : tray_background_view_(tray_background_view), + draws_active_(draws_active), + color_(SK_ColorTRANSPARENT) {} + + ~TrayBackground() override {} + + void set_color(SkColor color) { color_ = color; } + + private: + WmShelf* GetShelf() const { return tray_background_view_->shelf(); } + + void PaintMaterial(gfx::Canvas* canvas, views::View* view) const { + cc::PaintFlags background_flags; + background_flags.setAntiAlias(true); + background_flags.setColor(color_); + gfx::Insets insets = + GetMirroredBackgroundInsets(GetShelf()->GetAlignment()); + gfx::Rect bounds = view->GetLocalBounds(); + bounds.Inset(insets); + canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, background_flags); + + if (draws_active_ && tray_background_view_->is_active()) { + cc::PaintFlags highlight_flags; + highlight_flags.setAntiAlias(true); + highlight_flags.setColor(kShelfButtonActivatedHighlightColor); + canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, highlight_flags); + } + } + + void PaintNonMaterial(gfx::Canvas* canvas, views::View* view) const { + const static int kImageTypeDefault = 0; + // TODO(estade): leftover type which should be removed along with the rest + // of pre-MD code. + // const static int kImageTypeOnBlack = 1; + const static int kImageTypePressed = 2; + const static int kNumStates = 3; + + const static int kImageHorizontal = 0; + const static int kImageVertical = 1; + const static int kNumOrientations = 2; + + const int kGridSizeForPainter = 9; + + const int kImages[kNumOrientations][kNumStates][kGridSizeForPainter] = { + { + // Horizontal + IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ), + IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_ONBLACK), + IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_PRESSED), + }, + { + // Vertical + IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL), + IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_ONBLACK), + IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_PRESSED), + }}; + + WmShelf* shelf = GetShelf(); + const int orientation = IsHorizontalAlignment(shelf->GetAlignment()) + ? kImageHorizontal + : kImageVertical; + + int state = kImageTypeDefault; + if (draws_active_ && tray_background_view_->is_active()) + state = kImageTypePressed; + else + state = kImageTypeDefault; + + ui::CreateNineImagePainter(kImages[orientation][state]) + ->Paint(canvas, view->GetLocalBounds()); + } + + // Overridden from views::Background. + void Paint(gfx::Canvas* canvas, views::View* view) const override { + if (MaterialDesignController::IsShelfMaterial()) + PaintMaterial(canvas, view); + else + PaintNonMaterial(canvas, view); + } + + // Reference to the TrayBackgroundView for which this is a background. + TrayBackgroundView* tray_background_view_; + + // Determines whether we should draw an active background for the view when it + // is active. This is used in non-MD mode. In material design mode, an active + // ink drop ripple would indicate if the view is active or not. + // TODO(mohsen): This is used only in non-MD version. Remove when non-MD code + // is removed (see https://crbug.com/614453). + bool draws_active_; + + SkColor color_; + + DISALLOW_COPY_AND_ASSIGN(TrayBackground); +}; + +TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment) + : alignment_(alignment) { + UpdateLayout(); +} + +void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) { + if (alignment_ == alignment) + return; + alignment_ = alignment; + UpdateLayout(); +} + +void TrayBackgroundView::TrayContainer::SetMargin(int main_axis_margin, + int cross_axis_margin) { + main_axis_margin_ = main_axis_margin; + cross_axis_margin_ = cross_axis_margin; + UpdateLayout(); +} + +void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged( + views::View* child) { + PreferredSizeChanged(); +} + +void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) { + PreferredSizeChanged(); +} + +void TrayBackgroundView::TrayContainer::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + if (details.parent == this) + PreferredSizeChanged(); +} + +void TrayBackgroundView::TrayContainer::UpdateLayout() { + bool is_horizontal = IsHorizontalAlignment(alignment_); + + // Adjust the size of status tray dark background by adding additional + // empty border. + views::BoxLayout::Orientation orientation = + is_horizontal ? views::BoxLayout::kHorizontal + : views::BoxLayout::kVertical; + + if (ash::MaterialDesignController::IsShelfMaterial()) { + const int hit_region_with_separator = kHitRegionPadding + kSeparatorWidth; + gfx::Insets insets( + is_horizontal + ? gfx::Insets(0, kHitRegionPadding, 0, hit_region_with_separator) + : gfx::Insets(kHitRegionPadding, 0, hit_region_with_separator, 0)); + MirrorInsetsIfNecessary(&insets); + SetBorder(views::CreateEmptyBorder(insets)); + } else { + SetBorder(views::CreateEmptyBorder(gfx::Insets(kBackgroundAdjustPadding))); + } + + int horizontal_margin = main_axis_margin_; + int vertical_margin = cross_axis_margin_; + if (!is_horizontal) + std::swap(horizontal_margin, vertical_margin); + views::BoxLayout* layout = + new views::BoxLayout(orientation, horizontal_margin, vertical_margin, 0); + + if (!ash::MaterialDesignController::IsShelfMaterial()) + layout->SetDefaultFlex(1); + layout->set_minimum_cross_axis_size(kTrayItemSize); + views::View::SetLayoutManager(layout); + + PreferredSizeChanged(); +} + +//////////////////////////////////////////////////////////////////////////////// +// TrayBackgroundView + +TrayBackgroundView::TrayBackgroundView(WmShelf* wm_shelf) + // Note the ink drop style is ignored. + : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), + wm_shelf_(wm_shelf), + tray_container_(NULL), + shelf_alignment_(SHELF_ALIGNMENT_BOTTOM), + background_(NULL), + is_active_(false), + separator_visible_(true), + widget_observer_(new TrayWidgetObserver(this)) { + DCHECK(wm_shelf_); + set_notify_enter_exit_on_child(true); + set_ink_drop_base_color(kShelfInkDropBaseColor); + set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); + + tray_container_ = new TrayContainer(shelf_alignment_); + SetContents(tray_container_); + tray_event_filter_.reset(new TrayEventFilter); + + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + // Start the tray items not visible, because visibility changes are animated. + views::View::SetVisible(false); +} + +TrayBackgroundView::~TrayBackgroundView() { + if (GetWidget()) + GetWidget()->RemoveObserver(widget_observer_.get()); + StopObservingImplicitAnimations(); +} + +void TrayBackgroundView::Initialize() { + GetWidget()->AddObserver(widget_observer_.get()); +} + +// static +void TrayBackgroundView::InitializeBubbleAnimations( + views::Widget* bubble_widget) { + WmWindow* window = WmWindow::Get(bubble_widget->GetNativeWindow()); + window->SetVisibilityAnimationType( + ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); + window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE); + window->SetVisibilityAnimationDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs)); +} + +void TrayBackgroundView::SetVisible(bool visible) { + if (visible == layer()->GetTargetVisibility()) + return; + + if (visible) { + // The alignment of the shelf can change while the TrayBackgroundView is + // hidden. Reset the offscreen transform so that the animation to becoming + // visible reflects the current layout. + HideTransformation(); + // SetVisible(false) is defered until the animation for hiding is done. + // Otherwise the view is immediately hidden and the animation does not + // render. + views::View::SetVisible(true); + // If SetVisible(true) is called while animating to not visible, then + // views::View::SetVisible(true) is a no-op. When the previous animation + // ends layer->SetVisible(false) is called. To prevent this + // layer->SetVisible(true) immediately interrupts the animation of this + // property, and keeps the layer visible. + layer()->SetVisible(true); + } + + ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); + animation.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationForVisibilityMs)); + animation.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + + if (visible) { + animation.SetTweenType(gfx::Tween::EASE_OUT); + // Show is delayed so as to allow time for other children of + // StatusAreaWidget to begin animating to their new positions. + layer()->GetAnimator()->SchedulePauseForProperties( + base::TimeDelta::FromMilliseconds(kShowAnimationDelayMs), + ui::LayerAnimationElement::OPACITY | + ui::LayerAnimationElement::TRANSFORM); + layer()->SetOpacity(1.0f); + gfx::Transform transform; + transform.Translate(0.0f, 0.0f); + layer()->SetTransform(transform); + } else { + // Listen only to the hide animation. As we cannot turn off visibility + // until the animation is over. + animation.AddObserver(this); + animation.SetTweenType(gfx::Tween::EASE_IN); + layer()->SetOpacity(0.0f); + layer()->SetVisible(false); + HideTransformation(); + } +} + +const char* TrayBackgroundView::GetClassName() const { + return kViewClassName; +} + +void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) { + PreferredSizeChanged(); +} + +void TrayBackgroundView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + ActionableView::GetAccessibleNodeData(node_data); + node_data->SetName(GetAccessibleNameForTray()); +} + +void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) { + // Return focus to the login view. See crbug.com/120500. + views::View* v = GetNextFocusableView(); + if (v) + v->AboutToRequestFocusFromTabTraversal(reverse); +} + +std::unique_ptr<views::InkDropRipple> TrayBackgroundView::CreateInkDropRipple() + const { + return base::MakeUnique<views::FloodFillInkDropRipple>( + size(), GetBackgroundInsets(), GetInkDropCenterBasedOnLastEvent(), + GetInkDropBaseColor(), ink_drop_visible_opacity()); +} + +std::unique_ptr<views::InkDropHighlight> +TrayBackgroundView::CreateInkDropHighlight() const { + gfx::Rect bounds = GetBackgroundBounds(); + // Currently, we don't handle view resize. To compensate for that, enlarge the + // bounds by two tray icons so that the hightlight looks good even if two more + // icons are added when it is visible. Note that ink drop mask handles resize + // correctly, so the extra highlight would be clipped. + // TODO(mohsen): Remove this extra size when resize is handled properly (see + // https://crbug.com/669253). + const int icon_size = kTrayIconSize + 2 * kTrayImageItemPadding; + bounds.set_width(bounds.width() + 2 * icon_size); + bounds.set_height(bounds.height() + 2 * icon_size); + std::unique_ptr<views::InkDropHighlight> highlight( + new views::InkDropHighlight(bounds.size(), 0, + gfx::RectF(bounds).CenterPoint(), + GetInkDropBaseColor())); + highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity); + return highlight; +} + +void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) { + // If there is no ink drop, show "touch feedback". + // TODO(mohsen): This is used only in non-MD version. Remove when non-MD code + // is removed (see https://crbug.com/614453). + if (ink_drop_mode() == InkDropMode::OFF) { + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetIsActive(true); + } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || + event->type() == ui::ET_GESTURE_TAP_CANCEL) { + SetIsActive(false); + } + } + ActionableView::OnGestureEvent(event); +} + +void TrayBackgroundView::SetContents(views::View* contents) { + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); + AddChildView(contents); +} + +void TrayBackgroundView::SetContentsBackground(bool draws_active) { + background_ = new TrayBackground(this, draws_active); + tray_container_->set_background(background_); +} + +void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) { + shelf_alignment_ = alignment; + tray_container_->SetAlignment(alignment); +} + +void TrayBackgroundView::OnImplicitAnimationsCompleted() { + // If there is another animation in the queue, the reverse animation was + // triggered before the completion of animating to invisible. Do not turn off + // the visibility so that the next animation may render. The value of + // layer()->GetTargetVisibility() can be incorrect if the hide animation was + // aborted to schedule an animation to become visible. As the new animation + // is not yet added to the queue. crbug.com/374236 + if (layer()->GetAnimator()->is_animating() || layer()->GetTargetVisibility()) + return; + views::View::SetVisible(false); +} + +bool TrayBackgroundView::RequiresNotificationWhenAnimatorDestroyed() const { + // This is needed so that OnImplicitAnimationsCompleted() is called even upon + // destruction of the animator. This can occure when parallel animations + // caused by ScreenRotationAnimator end before the animations of + // TrayBackgroundView. This allows for a proper update to the visual state of + // the view. (crbug.com/476667) + return true; +} + +void TrayBackgroundView::HideTransformation() { + gfx::Transform transform; + if (IsHorizontalAlignment(shelf_alignment_)) + transform.Translate(width(), 0.0f); + else + transform.Translate(0.0f, height()); + layer()->SetTransform(transform); +} + +TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const { + if (shelf_alignment_ == SHELF_ALIGNMENT_LEFT) + return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT; + if (shelf_alignment_ == SHELF_ALIGNMENT_RIGHT) + return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT; + return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM; +} + +void TrayBackgroundView::SetIsActive(bool is_active) { + if (is_active_ == is_active) + return; + is_active_ = is_active; + AnimateInkDrop(is_active_ ? views::InkDropState::ACTIVATED + : views::InkDropState::DEACTIVATED, + nullptr); + if (!background_) + return; + // TODO(mohsen): This is needed for non-MD version. Remove when non-MD code is + // removed (see https://crbug.com/614453). + SchedulePaint(); +} + +void TrayBackgroundView::UpdateBubbleViewArrow( + views::TrayBubbleView* bubble_view) { + // Nothing to do here. +} + +void TrayBackgroundView::UpdateShelfItemBackground(SkColor color) { + if (background_) { + background_->set_color(color); + SchedulePaint(); + } +} + +views::View* TrayBackgroundView::GetBubbleAnchor() const { + return tray_container_; +} + +gfx::Insets TrayBackgroundView::GetBubbleAnchorInsets() const { + gfx::Insets anchor_insets = GetBubbleAnchor()->GetInsets(); + gfx::Insets tray_bg_insets = GetInsets(); + if (GetAnchorAlignment() == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) { + return gfx::Insets(-tray_bg_insets.top(), anchor_insets.left(), + -tray_bg_insets.bottom(), anchor_insets.right()); + } else { + return gfx::Insets(anchor_insets.top(), -tray_bg_insets.left(), + anchor_insets.bottom(), -tray_bg_insets.right()); + } +} + +std::unique_ptr<views::InkDropMask> TrayBackgroundView::CreateInkDropMask() + const { + return base::MakeUnique<views::RoundRectInkDropMask>( + size(), GetBackgroundInsets(), kTrayRoundedBorderRadius); +} + +bool TrayBackgroundView::ShouldEnterPushedState(const ui::Event& event) { + if (is_active_) + return false; + + return ActionableView::ShouldEnterPushedState(event); +} + +bool TrayBackgroundView::PerformAction(const ui::Event& event) { + return false; +} + +void TrayBackgroundView::HandlePerformActionResult(bool action_performed, + const ui::Event& event) { + // When an action is performed, ink drop ripple is handled in SetIsActive(). + if (action_performed) + return; + ActionableView::HandlePerformActionResult(action_performed, event); +} + +void TrayBackgroundView::OnPaintFocus(gfx::Canvas* canvas) { + // The tray itself expands to the right and bottom edge of the screen to make + // sure clicking on the edges brings up the popup. However, the focus border + // should be only around the container. + gfx::RectF paint_bounds; + paint_bounds = gfx::RectF(GetBackgroundBounds()); + paint_bounds.Inset(gfx::Insets(-kFocusBorderThickness)); + canvas->DrawSolidFocusRect(paint_bounds, kFocusBorderColor, + kFocusBorderThickness); +} + +void TrayBackgroundView::OnPaint(gfx::Canvas* canvas) { + ActionableView::OnPaint(canvas); + if (shelf()->GetBackgroundType() == + ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT || + !separator_visible_) { + return; + } + // In the given |canvas|, for a horizontal shelf draw a separator line to the + // right or left of the TrayBackgroundView when the system is LTR or RTL + // aligned, respectively. For a vertical shelf draw the separator line + // underneath the items instead. + const gfx::Rect local_bounds = GetLocalBounds(); + const SkColor color = SkColorSetA(SK_ColorWHITE, 0x4D); + + if (IsHorizontalAlignment(shelf_alignment_)) { + const gfx::PointF point( + base::i18n::IsRTL() ? 0 : (local_bounds.width() - kSeparatorWidth), + (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2); + const gfx::Vector2dF vector(0, kTrayItemSize); + canvas->Draw1pxLine(point, point + vector, color); + } else { + const gfx::PointF point((GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2, + local_bounds.height() - kSeparatorWidth); + const gfx::Vector2dF vector(kTrayItemSize, 0); + canvas->Draw1pxLine(point, point + vector, color); + } +} + +gfx::Insets TrayBackgroundView::GetBackgroundInsets() const { + gfx::Insets insets = GetMirroredBackgroundInsets(shelf_alignment_); + + // |insets| are relative to contents bounds. Change them to be relative to + // local bounds. + gfx::Insets local_contents_insets = + GetLocalBounds().InsetsFrom(GetContentsBounds()); + MirrorInsetsIfNecessary(&local_contents_insets); + insets += local_contents_insets; + + return insets; +} + +gfx::Rect TrayBackgroundView::GetBackgroundBounds() const { + gfx::Insets insets = GetBackgroundInsets(); + gfx::Rect bounds = GetLocalBounds(); + bounds.Inset(insets); + return bounds; +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_background_view.h b/ash/common/system/tray/tray_background_view.h new file mode 100644 index 0000000..49e71055 --- /dev/null +++ b/ash/common/system/tray/tray_background_view.h
@@ -0,0 +1,197 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/common/system/tray/actionable_view.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/views/bubble/tray_bubble_view.h" + +namespace ash { +class TrayEventFilter; +class TrayBackground; +class WmShelf; + +// Base class for children of StatusAreaWidget: SystemTray, WebNotificationTray, +// LogoutButtonTray, OverviewButtonTray. +// This class handles setting and animating the background when the Launcher +// is shown/hidden. It also inherits from ActionableView so that the tray +// items can override PerformAction when clicked on. +class ASH_EXPORT TrayBackgroundView : public ActionableView, + public ui::ImplicitAnimationObserver, + public ShelfBackgroundAnimatorObserver { + public: + static const char kViewClassName[]; + + // Base class for tray containers. Sets the border and layout. The container + // auto-resizes the widget when necessary. + class TrayContainer : public views::View { + public: + explicit TrayContainer(ShelfAlignment alignment); + ~TrayContainer() override {} + + void SetAlignment(ShelfAlignment alignment); + + void SetMargin(int main_axis_margin, int cross_axis_margin); + + protected: + // views::View: + void ChildPreferredSizeChanged(views::View* child) override; + void ChildVisibilityChanged(View* child) override; + void ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) override; + + private: + void UpdateLayout(); + + ShelfAlignment alignment_; + int main_axis_margin_ = 0; + int cross_axis_margin_ = 0; + + DISALLOW_COPY_AND_ASSIGN(TrayContainer); + }; + + explicit TrayBackgroundView(WmShelf* wm_shelf); + ~TrayBackgroundView() override; + + // Called after the tray has been added to the widget containing it. + virtual void Initialize(); + + // Initializes animations for the bubble. + static void InitializeBubbleAnimations(views::Widget* bubble_widget); + + // views::View: + void SetVisible(bool visible) override; + const char* GetClassName() const override; + void ChildPreferredSizeChanged(views::View* child) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void AboutToRequestFocusFromTabTraversal(bool reverse) override; + void OnPaint(gfx::Canvas* canvas) override; + + // ActionableView: + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override; + void OnGestureEvent(ui::GestureEvent* event) override; + + // Called whenever the shelf alignment changes. + virtual void SetShelfAlignment(ShelfAlignment alignment); + + // Called when the anchor (tray or bubble) may have moved or changed. + virtual void AnchorUpdated() {} + + // Called from GetAccessibleNodeData, must return a valid accessible name. + virtual base::string16 GetAccessibleNameForTray() = 0; + + // Called when the bubble is resized. + virtual void BubbleResized(const views::TrayBubbleView* bubble_view) {} + + // Hides the bubble associated with |bubble_view|. Called when the widget + // is closed. + virtual void HideBubbleWithView(const views::TrayBubbleView* bubble_view) = 0; + + // Called by the bubble wrapper when a click event occurs outside the bubble. + // May close the bubble. + virtual void ClickedOutsideBubble() = 0; + + // Sets |contents| as a child. + void SetContents(views::View* contents); + + // Creates and sets contents background to |background_|. |draws_active| + // determines if the view's background should be drawn as active when the view + // is in the active state. + void SetContentsBackground(bool draws_active); + + // Returns the bubble anchor alignment based on |shelf_alignment_|. + views::TrayBubbleView::AnchorAlignment GetAnchorAlignment() const; + + void SetIsActive(bool is_active); + bool is_active() const { return is_active_; } + + TrayContainer* tray_container() const { return tray_container_; } + ShelfAlignment shelf_alignment() const { return shelf_alignment_; } + TrayEventFilter* tray_event_filter() { return tray_event_filter_.get(); } + WmShelf* shelf() { return wm_shelf_; } + + // Updates the arrow visibility based on the launcher visibility. + void UpdateBubbleViewArrow(views::TrayBubbleView* bubble_view); + + // ShelfBackgroundAnimatorObserver: + void UpdateShelfItemBackground(SkColor color) override; + + // Updates the visibility of this tray's separator. + void set_separator_visibility(bool visible) { separator_visible_ = visible; } + + // Gets the anchor for bubbles, which is tray_container(). + views::View* GetBubbleAnchor() const; + + // Gets additional insets for positioning bubbles relative to + // tray_container(). + gfx::Insets GetBubbleAnchorInsets() const; + + protected: + // ActionableView: + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + bool ShouldEnterPushedState(const ui::Event& event) override; + bool PerformAction(const ui::Event& event) override; + void HandlePerformActionResult(bool action_performed, + const ui::Event& event) override; + void OnPaintFocus(gfx::Canvas* canvas) override; + + private: + class TrayWidgetObserver; + + // ui::ImplicitAnimationObserver: + void OnImplicitAnimationsCompleted() override; + bool RequiresNotificationWhenAnimatorDestroyed() const override; + + // Applies transformations to the |layer()| to animate the view when + // SetVisible(false) is called. + void HideTransformation(); + + // Helper function that calculates background insets relative to local bounds. + gfx::Insets GetBackgroundInsets() const; + + // Helper function that calculates background bounds relative to local bounds + // based on background insets returned from GetBackgroundInsets(). + gfx::Rect GetBackgroundBounds() const; + + // The shelf containing the system tray for this view. + WmShelf* wm_shelf_; + + // Convenience pointer to the contents view. + TrayContainer* tray_container_; + + // Shelf alignment. + // TODO(jamescook): Don't cache this, get it from WmShelf. + ShelfAlignment shelf_alignment_; + + // Owned by the view passed to SetContents(). + TrayBackground* background_; + + // Determines if the view is active. This changes how the background is drawn + // in non-MD version and how the ink drop ripples behave in MD version. + bool is_active_; + + // Visibility of this tray's separator which is a line of 1x32px and 4px to + // right of tray. + bool separator_visible_; + + std::unique_ptr<TrayWidgetObserver> widget_observer_; + std::unique_ptr<TrayEventFilter> tray_event_filter_; + + DISALLOW_COPY_AND_ASSIGN(TrayBackgroundView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_
diff --git a/ash/common/system/tray/tray_bubble_wrapper.cc b/ash/common/system/tray/tray_bubble_wrapper.cc new file mode 100644 index 0000000..5495042 --- /dev/null +++ b/ash/common/system/tray/tray_bubble_wrapper.cc
@@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_bubble_wrapper.h" + +#include "ash/common/system/tray/tray_background_view.h" +#include "ash/common/system/tray/tray_event_filter.h" +#include "ash/common/wm_window.h" +#include "ui/views/bubble/tray_bubble_view.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +TrayBubbleWrapper::TrayBubbleWrapper(TrayBackgroundView* tray, + views::TrayBubbleView* bubble_view) + : tray_(tray), bubble_view_(bubble_view) { + bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_); + bubble_widget_->AddObserver(this); + + TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_); + tray_->UpdateBubbleViewArrow(bubble_view_); + bubble_view_->InitializeAndShowBubble(); + + tray->tray_event_filter()->AddWrapper(this); +} + +TrayBubbleWrapper::~TrayBubbleWrapper() { + tray_->tray_event_filter()->RemoveWrapper(this); + if (bubble_widget_) { + bubble_widget_->RemoveObserver(this); + bubble_widget_->Close(); + } +} + +void TrayBubbleWrapper::OnWidgetDestroying(views::Widget* widget) { + CHECK_EQ(bubble_widget_, widget); + bubble_widget_->RemoveObserver(this); + bubble_widget_ = NULL; + + // Although the bubble is already closed, the next mouse release event + // will invoke PerformAction which reopens the bubble again. To prevent the + // reopen, the mouse capture of |tray_| has to be released. + // See crbug.com/177075 + WmWindow::Get(tray_->GetWidget()->GetNativeWindow())->ReleaseCapture(); + + tray_->HideBubbleWithView(bubble_view_); // May destroy |bubble_view_| +} + +void TrayBubbleWrapper::OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) { + DCHECK_EQ(bubble_widget_, widget); + tray_->BubbleResized(bubble_view_); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_bubble_wrapper.h b/ash/common/system/tray/tray_bubble_wrapper.h new file mode 100644 index 0000000..d5f0c44c --- /dev/null +++ b/ash/common/system/tray/tray_bubble_wrapper.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_ + +#include "base/macros.h" +#include "ui/views/widget/widget_observer.h" + +namespace views { +class TrayBubbleView; +} + +namespace ash { +class TrayBackgroundView; + +// Creates and manages the Widget and EventFilter components of a bubble. + +class TrayBubbleWrapper : public views::WidgetObserver { + public: + TrayBubbleWrapper(TrayBackgroundView* tray, + views::TrayBubbleView* bubble_view); + ~TrayBubbleWrapper() override; + + // views::WidgetObserver overrides: + void OnWidgetDestroying(views::Widget* widget) override; + void OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) override; + + const TrayBackgroundView* tray() const { return tray_; } + TrayBackgroundView* tray() { return tray_; } + views::TrayBubbleView* bubble_view() { return bubble_view_; } + const views::TrayBubbleView* bubble_view() const { return bubble_view_; } + views::Widget* bubble_widget() { return bubble_widget_; } + const views::Widget* bubble_widget() const { return bubble_widget_; } + + private: + TrayBackgroundView* tray_; + views::TrayBubbleView* bubble_view_; // unowned + views::Widget* bubble_widget_; + + DISALLOW_COPY_AND_ASSIGN(TrayBubbleWrapper); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_
diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc new file mode 100644 index 0000000..161edf0 --- /dev/null +++ b/ash/common/system/tray/tray_constants.cc
@@ -0,0 +1,115 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_constants.h" + +#include "base/logging.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/color_palette.h" + +namespace ash { + +const int kPaddingFromRightEdgeOfScreenBottomAlignment = 7; +const int kPaddingFromBottomOfScreenBottomAlignment = 7; +const int kPaddingFromOuterEdgeOfLauncherVerticalAlignment = 8; +const int kPaddingFromInnerEdgeOfLauncherVerticalAlignment = 9; +const int kPaddingFromBottomOfScreenVerticalAlignment = 10; + +// Padding used to position the system menu relative to the status area. +const int kBubblePaddingHorizontalBottom = 6; +const int kBubblePaddingHorizontalSide = 10; +const int kBubblePaddingVerticalBottom = 3; +const int kBubblePaddingVerticalSide = 15; + +// Top inset of system tray bubble for bottom anchor alignment. +const int kTrayBubbleAnchorTopInsetBottomAnchor = 3; + +const int kTrayImageItemHorizontalPaddingVerticalAlignment = 1; + +// Size of tray items on the primary axis. +const int kTrayItemSize = 32; + +const int kTrayImageItemPadding = 3; + +const int kTrayLabelItemHorizontalPaddingBottomAlignment = 7; + +// Vertical padding between status tray items when the shelf is vertical. +const int kTrayLabelItemVerticalPaddingVerticalAlignment = 4; + +const int kTrayMenuBottomRowPadding = 3; +const int kTrayMenuBottomRowPaddingBetweenItems = -1; +const int kTrayMenuMinimumWidth = 300; +const int kTrayMenuMinimumWidthMd = 352; + +const int kTrayPopupAutoCloseDelayInSeconds = 2; +const int kTrayPopupAutoCloseDelayForTextInSeconds = 5; +const int kTrayPopupPaddingHorizontal = 18; +const int kTrayPopupPaddingBetweenItems = 10; +const int kTrayPopupButtonEndMargin = 10; +const int kTrayPopupLabelHorizontalPadding = 4; +const int kTrayPopupItemMinHeight = 48; +const int kTrayPopupItemMinStartWidth = 48; +const int kTrayPopupItemMinEndWidth = + kMenuIconSize + 2 * kTrayPopupButtonEndMargin; + +const int kTrayDetailedViewTransitionDelayMs = 100; + +const int kTrayPopupLabelRightPadding = 8; + +const int kTrayPopupDetailsIconWidth = 25; +const int kTrayPopupDetailsLabelExtraLeftMargin = 8; +const SkColor kTrayPopupHoverBackgroundColor = SkColorSetRGB(0xe4, 0xe4, 0xe4); +const int kTrayPopupScrollSeparatorHeight = 15; +const int kTrayRoundedBorderRadius = 2; + +const int kTrayToggleButtonWidth = 68; + +const SkColor kBackgroundColor = SkColorSetRGB(0xfe, 0xfe, 0xfe); +const SkColor kHoverBackgroundColor = SkColorSetRGB(0xf3, 0xf3, 0xf3); +const SkColor kPublicAccountUserCardTextColor = SkColorSetRGB(0x66, 0x66, 0x66); +const SkColor kPublicAccountUserCardNameColor = SK_ColorBLACK; + +const SkColor kHeaderBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5); + +const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); +const SkColor kBorderLightColor = SkColorSetRGB(0xeb, 0xeb, 0xeb); +const SkColor kButtonStrokeColor = SkColorSetRGB(0xdd, 0xdd, 0xdd); + +const SkColor kHeaderTextColorNormal = SkColorSetARGB(0x7f, 0, 0, 0); +const SkColor kHeaderTextColorHover = SkColorSetARGB(0xd3, 0, 0, 0); + +const int kTrayPopupMinWidth = 300; +const int kTrayPopupMaxWidth = 500; +const int kNotificationIconWidth = 40; +const int kNotificationButtonWidth = 32; +const int kTrayNotificationContentsWidth = + kTrayPopupMinWidth - (kNotificationIconWidth + kNotificationButtonWidth + + (kTrayPopupPaddingHorizontal / 2) * 3); + +const int kTrayIconSize = 16; +const int kTrayEdgePadding = 6; +const SkColor kTrayIconColor = SK_ColorWHITE; +const int kMenuIconSize = 20; +const SkColor kMenuIconColor = gfx::kChromeIconGrey; +const SkColor kMenuIconColorDisabled = SkColorSetA(gfx::kChromeIconGrey, 0x61); +const int kMenuButtonSize = 48; +const int kMenuSeparatorVerticalPadding = 4; +const int kMenuExtraMarginFromLeftEdge = 4; +const int kMenuEdgeEffectivePadding = + kMenuExtraMarginFromLeftEdge + (kMenuButtonSize - kMenuIconSize) / 2; + +const int kHitRegionPadding = 4; +const int kSeparatorWidth = 1; + +const SkColor kMenuSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); + +const SkColor kTrayPopupInkDropBaseColor = SK_ColorBLACK; +const float kTrayPopupInkDropRippleOpacity = 0.06f; +const float kTrayPopupInkDropHighlightOpacity = 0.08f; +const int kTrayPopupInkDropInset = 4; +const int kTrayPopupInkDropCornerRadius = 2; + +const int kTrayPopupSystemInfoRowHeight = 40; + +} // namespace ash
diff --git a/ash/common/system/tray/tray_constants.h b/ash/common/system/tray/tray_constants.h new file mode 100644 index 0000000..8ee390c4 --- /dev/null +++ b/ash/common/system/tray/tray_constants.h
@@ -0,0 +1,158 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_CONSTANTS_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_CONSTANTS_H_ + +#include "ash/ash_export.h" + +typedef unsigned int SkColor; + +namespace ash { + +extern const int kPaddingFromRightEdgeOfScreenBottomAlignment; +extern const int kPaddingFromBottomOfScreenBottomAlignment; +extern const int kPaddingFromOuterEdgeOfLauncherVerticalAlignment; +extern const int kPaddingFromInnerEdgeOfLauncherVerticalAlignment; +extern const int kPaddingFromBottomOfScreenVerticalAlignment; + +extern const int kBubblePaddingHorizontalBottom; +extern const int kBubblePaddingHorizontalSide; +extern const int kBubblePaddingVerticalBottom; +extern const int kBubblePaddingVerticalSide; + +extern const int kTrayBubbleAnchorTopInsetBottomAnchor; + +extern const int kTrayImageItemHorizontalPaddingVerticalAlignment; + +ASH_EXPORT extern const int kTrayItemSize; + +// Extra padding used beside a single icon in the tray area of the shelf. +extern const int kTrayImageItemPadding; + +extern const int kTrayLabelItemHorizontalPaddingBottomAlignment; +extern const int kTrayLabelItemVerticalPaddingVerticalAlignment; + +extern const int kTrayMenuBottomRowPadding; +extern const int kTrayMenuBottomRowPaddingBetweenItems; + +// The minimum width of the tray menu. +extern const int kTrayMenuMinimumWidth; +extern const int kTrayMenuMinimumWidthMd; + +extern const int kTrayPopupAutoCloseDelayInSeconds; +extern const int kTrayPopupAutoCloseDelayForTextInSeconds; +extern const int kTrayPopupPaddingHorizontal; +extern const int kTrayPopupPaddingBetweenItems; +extern const int kTrayPopupButtonEndMargin; +// The padding used on the left and right of labels. This applies to all labels +// in the system menu. +extern const int kTrayPopupLabelHorizontalPadding; + +// The minimum/default height of the rows in the system tray menu. +extern const int kTrayPopupItemMinHeight; + +// The width used for the first region of the row (which holds an image). +extern const int kTrayPopupItemMinStartWidth; + +// The width used for the end region of the row (usually a more arrow). +extern const int kTrayPopupItemMinEndWidth; + +// When transitioning between a detailed and a default view, this delay is used +// before the transition starts. +ASH_EXPORT extern const int kTrayDetailedViewTransitionDelayMs; + +// Padding used on right side of labels to keep minimum distance to the next +// item. This applies to all labels in the system menu. +extern const int kTrayPopupLabelRightPadding; + +extern const int kTrayPopupDetailsIconWidth; +extern const int kTrayPopupDetailsLabelExtraLeftMargin; +extern const SkColor kTrayPopupHoverBackgroundColor; +extern const int kTrayPopupScrollSeparatorHeight; +extern const int kTrayRoundedBorderRadius; + +// The width of ToggleButton views including any border padding. +extern const int kTrayToggleButtonWidth; + +extern const SkColor kBackgroundColor; +extern const SkColor kHoverBackgroundColor; +extern const SkColor kPublicAccountUserCardTextColor; +extern const SkColor kPublicAccountUserCardNameColor; + +extern const SkColor kHeaderBackgroundColor; + +extern const SkColor kBorderDarkColor; +extern const SkColor kBorderLightColor; +extern const SkColor kButtonStrokeColor; + +extern const SkColor kHeaderTextColorNormal; +extern const SkColor kHeaderTextColorHover; + +extern const int kTrayPopupMinWidth; +extern const int kTrayPopupMaxWidth; +extern const int kNotificationIconWidth; +extern const int kNotificationButtonWidth; +extern const int kTrayNotificationContentsWidth; + +// Extra padding used to adjust hitting region around tray items. +extern const int kHitRegionPadding; + +// Width of a line used to separate tray items in the shelf. +ASH_EXPORT extern const int kSeparatorWidth; + +// The color of the separators used in the system menu. +extern const SkColor kMenuSeparatorColor; + +// The size and foreground color of the icons appearing in the material design +// system tray. +extern const int kTrayIconSize; +extern const SkColor kTrayIconColor; + +// The total visual padding at the start and end of the icon/label section +// of the tray. +extern const int kTrayEdgePadding; + +// The size and foreground color of the icons appearing in the material design +// system menu. +extern const int kMenuIconSize; +extern const SkColor kMenuIconColor; +extern const SkColor kMenuIconColorDisabled; +// The size of buttons in the system menu. +ASH_EXPORT extern const int kMenuButtonSize; +// The vertical padding for the system menu separator. +extern const int kMenuSeparatorVerticalPadding; +// The horizontal padding for the system menu separator. +extern const int kMenuExtraMarginFromLeftEdge; +// The visual padding to the left of icons in the system menu. +extern const int kMenuEdgeEffectivePadding; + +// The base color used for all ink drops in the system menu. +extern const SkColor kTrayPopupInkDropBaseColor; + +// The opacity of the ink drop ripples for all ink drops in the system menu. +extern const float kTrayPopupInkDropRippleOpacity; + +// The opacity of the ink drop ripples for all ink highlights in the system +// menu. +extern const float kTrayPopupInkDropHighlightOpacity; + +// The inset applied to clickable surfaces in the system menu that do not have +// the ink drop filling the entire bounds. +extern const int kTrayPopupInkDropInset; + +// The radius used to draw the corners of the rounded rect style ink drops. +extern const int kTrayPopupInkDropCornerRadius; + +// The height of the system info row. +extern const int kTrayPopupSystemInfoRowHeight; + +namespace test { +const int kSettingsTrayItemViewId = 10000; +const int kAccessibilityTrayItemViewId = 10001; +} // namespace test + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_CONSTANTS_H_
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc new file mode 100644 index 0000000..a99790f --- /dev/null +++ b/ash/common/system/tray/tray_details_view.cc
@@ -0,0 +1,510 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_details_view.h" + +#include "ash/common/ash_view_ids.h" +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/system/tray/system_menu_button.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/containers/adapters.h" +#include "base/memory/ptr_util.h" +#include "third_party/skia/include/core/SkDrawLooper.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/paint_context.h" +#include "ui/compositor/paint_recorder.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/skia_paint_util.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/progress_bar.h" +#include "ui/views/controls/scroll_view.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/view_targeter.h" +#include "ui/views/view_targeter_delegate.h" + +namespace ash { +namespace { + +bool UseMd() { + return MaterialDesignController::IsSystemTrayMenuMaterial(); +} + +// The index of the horizontal rule below the title row. +const int kTitleRowSeparatorIndex = 1; + +// A view that is used as ScrollView contents. It supports designating some of +// the children as sticky header rows. The sticky header rows are not scrolled +// above the top of the visible viewport until the next one "pushes" it up and +// are painted above other children. To indicate that a child is a sticky header +// row use set_id(VIEW_ID_STICKY_HEADER). +class ScrollContentsView : public views::View { + public: + ScrollContentsView() + : box_layout_(new views::BoxLayout( + views::BoxLayout::kVertical, + 0, + 0, + UseMd() ? 0 : kContentsBetweenChildSpacingNonMd)) { + SetLayoutManager(box_layout_); + } + ~ScrollContentsView() override {} + + protected: + // views::View: + void OnBoundsChanged(const gfx::Rect& previous_bounds) override { + PositionHeaderRows(); + } + + void PaintChildren(const ui::PaintContext& context) override { + views::View::PaintChildren(context); + bool did_draw_shadow = false; + // Paint header row separators. + for (auto& header : headers_) + did_draw_shadow = PaintDelineation(header, context) || did_draw_shadow; + + // Draw a shadow at the top of the viewport when scrolled, but only if a + // header didn't already draw one. Overlap the shadow with the separator + // that's below the header view so we don't get both a separator and a full + // shadow. + if (y() != 0 && !did_draw_shadow) + DrawShadow(context, gfx::Rect(0, 0, width(), -y() - kSeparatorWidth)); + } + + void Layout() override { + views::View::Layout(); + headers_.clear(); + for (int i = 0; i < child_count(); ++i) { + views::View* view = child_at(i); + if (view->id() == VIEW_ID_STICKY_HEADER) + headers_.emplace_back(view); + } + PositionHeaderRows(); + } + + View::Views GetChildrenInZOrder() override { + View::Views children; + // Iterate over regular children and later over the sticky headers to keep + // the sticky headers above in Z-order. + for (int i = 0; i < child_count(); ++i) { + if (child_at(i)->id() != VIEW_ID_STICKY_HEADER) + children.push_back(child_at(i)); + } + for (int i = 0; i < child_count(); ++i) { + if (child_at(i)->id() == VIEW_ID_STICKY_HEADER) + children.push_back(child_at(i)); + } + DCHECK_EQ(child_count(), static_cast<int>(children.size())); + return children; + } + + void ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) override { + if (!details.is_add && details.parent == this) { + headers_.erase(std::remove_if(headers_.begin(), headers_.end(), + [details](const Header& header) { + return header.view == details.child; + }), + headers_.end()); + } else if (details.is_add && details.parent == this && + details.child == child_at(0)) { + // We always want padding on the bottom of the scroll contents. + // We only want padding on the top of the scroll contents if the first + // child is not a header (in that case, the padding is built into the + // header). + DCHECK_EQ(box_layout_, GetLayoutManager()); + box_layout_->set_inside_border_insets( + gfx::Insets(details.child->id() == VIEW_ID_STICKY_HEADER + ? 0 + : kMenuSeparatorVerticalPadding, + 0, kMenuSeparatorVerticalPadding, 0)); + } + } + + private: + const int kShadowOffsetY = 2; + const int kShadowBlur = 2; + // TODO(fukino): Remove this constant once we stop maintaining pre-MD design. + // crbug.com/614453. + const int kContentsBetweenChildSpacingNonMd = 1; + + // A structure that keeps the original offset of each header between the + // calls to Layout() to allow keeping track of which view should be sticky. + struct Header { + explicit Header(views::View* view) + : view(view), natural_offset(view->y()), draw_separator_below(false) {} + + // A header View that can be decorated as sticky. + views::View* view; + + // Offset from the top of ScrollContentsView to |view|'s original vertical + // position. + int natural_offset; + + // True when a separator needs to be painted below the header when another + // header is pushing |this| header up. + bool draw_separator_below; + }; + + // Adjusts y-position of header rows allowing one or two rows to stick to the + // top of the visible viewport. + void PositionHeaderRows() { + const int scroll_offset = -y(); + Header* previous_header = nullptr; + for (auto& header : base::Reversed(headers_)) { + views::View* header_view = header.view; + bool draw_separator_below = false; + if (header.natural_offset >= scroll_offset) { + previous_header = &header; + header_view->SetY(header.natural_offset); + } else { + if (previous_header && + previous_header->view->y() <= + scroll_offset + header_view->height()) { + // Lower header displacing the header above. + draw_separator_below = true; + header_view->SetY(previous_header->view->y() - header_view->height()); + } else { + // A header becomes sticky. + header_view->SetY(scroll_offset); + header_view->Layout(); + header_view->SchedulePaint(); + } + } + if (header.draw_separator_below != draw_separator_below) { + header.draw_separator_below = draw_separator_below; + TrayPopupUtils::ShowStickyHeaderSeparator(header_view, + draw_separator_below); + } + if (header.natural_offset < scroll_offset) + break; + } + } + + // Paints a separator for a header view. The separator can be a horizontal + // rule or a horizontal shadow, depending on whether the header is sticking to + // the top of the scroll viewport. The return value indicates whether a shadow + // was drawn. + bool PaintDelineation(const Header& header, const ui::PaintContext& context) { + const View* view = header.view; + + // If the header is where it normally belongs or If the header is pushed by + // a header directly below it, draw nothing. + if (view->y() == header.natural_offset || header.draw_separator_below) + return false; + + // Otherwise, draw a shadow below. + DrawShadow(context, + gfx::Rect(0, 0, view->width(), view->bounds().bottom())); + return true; + } + + // Draws a drop shadow below |shadowed_area|. + void DrawShadow(const ui::PaintContext& context, + const gfx::Rect& shadowed_area) { + ui::PaintRecorder recorder(context, size()); + gfx::Canvas* canvas = recorder.canvas(); + cc::PaintFlags flags; + gfx::ShadowValues shadow; + shadow.emplace_back(gfx::Vector2d(0, kShadowOffsetY), kShadowBlur, + kMenuSeparatorColor); + flags.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow)); + flags.setAntiAlias(true); + canvas->ClipRect(shadowed_area, SkClipOp::kDifference); + canvas->DrawRect(shadowed_area, flags); + } + + views::BoxLayout* box_layout_; + + // Header child views that stick to the top of visible viewport when scrolled. + std::vector<Header> headers_; + + DISALLOW_COPY_AND_ASSIGN(ScrollContentsView); +}; + +// Constants for the title row in material design. +const int kTitleRowVerticalPadding = 4; +const int kTitleRowProgressBarHeight = 2; +const int kTitleRowPaddingTop = kTitleRowVerticalPadding; +const int kTitleRowPaddingBottom = + kTitleRowVerticalPadding - kTitleRowProgressBarHeight; + +class ScrollSeparator : public views::View { + public: + ScrollSeparator() {} + + ~ScrollSeparator() override {} + + private: + // views::View: + void OnPaint(gfx::Canvas* canvas) override { + canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); + } + gfx::Size GetPreferredSize() const override { + return gfx::Size(1, kTrayPopupScrollSeparatorHeight); + } + + DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); +}; + +} // namespace + +class ScrollBorder : public views::Border { + public: + ScrollBorder() {} + ~ScrollBorder() override {} + + void set_visible(bool visible) { visible_ = visible; } + + private: + // views::Border: + void Paint(const views::View& view, gfx::Canvas* canvas) override { + if (!visible_) + return; + canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), + kBorderLightColor); + } + + gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } + + gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } + + bool visible_ = false; + + DISALLOW_COPY_AND_ASSIGN(ScrollBorder); +}; + +TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) + : owner_(owner), + box_layout_(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)), + title_row_(nullptr), + scroller_(nullptr), + scroll_content_(nullptr), + progress_bar_(nullptr), + scroll_border_(nullptr), + tri_view_(nullptr), + back_button_(nullptr) { + SetLayoutManager(box_layout_); + set_background(views::Background::CreateSolidBackground(kBackgroundColor)); +} + +TrayDetailsView::~TrayDetailsView() {} + +void TrayDetailsView::OnViewClicked(views::View* sender) { + if (!UseMd() && title_row_ && sender == title_row_->content()) { + TransitionToDefaultView(); + return; + } + + HandleViewClicked(sender); +} + +void TrayDetailsView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + if (UseMd() && sender == back_button_) { + TransitionToDefaultView(); + return; + } + + HandleButtonPressed(sender, event); +} + +void TrayDetailsView::CreateTitleRow(int string_id) { + DCHECK(!tri_view_); + DCHECK(!title_row_); + + if (UseMd()) { + tri_view_ = TrayPopupUtils::CreateDefaultRowView(); + + back_button_ = CreateBackButton(); + tri_view_->AddView(TriView::Container::START, back_button_); + + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + auto* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(rb.GetLocalizedString(string_id)); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); + style.SetupLabel(label); + tri_view_->AddView(TriView::Container::CENTER, label); + + tri_view_->SetContainerVisible(TriView::Container::END, false); + + tri_view_->SetBorder(views::CreateEmptyBorder(kTitleRowPaddingTop, 0, + kTitleRowPaddingBottom, 0)); + AddChildViewAt(tri_view_, 0); + views::Separator* separator = new views::Separator(); + separator->SetColor(kMenuSeparatorColor); + separator->SetBorder(views::CreateEmptyBorder( + kTitleRowProgressBarHeight - views::Separator::kThickness, 0, 0, 0)); + AddChildViewAt(separator, kTitleRowSeparatorIndex); + } else { + title_row_ = new SpecialPopupRow(); + title_row_->SetTextLabel(string_id, this); + AddChildViewAt(title_row_, child_count()); + } + + CreateExtraTitleRowButtons(); + Layout(); +} + +void TrayDetailsView::CreateScrollableList() { + DCHECK(!scroller_); + scroll_content_ = new ScrollContentsView(); + scroller_ = new views::ScrollView; + scroller_->SetContents(scroll_content_); + // Make the |scroller_| have a layer to clip |scroll_content_|'s children. + // TODO(varkha): Make the sticky rows work with EnableViewPortLayer(). + scroller_->SetPaintToLayer(); + scroller_->set_background( + views::Background::CreateSolidBackground(kBackgroundColor)); + scroller_->layer()->SetMasksToBounds(true); + + // Note: |scroller_| takes ownership of |scroll_border_|. + if (!UseMd()) { + // In MD, the scroller is always the last thing, so this border is + // unnecessary and reserves extra space we don't want. + scroll_border_ = new ScrollBorder; + scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); + } + + AddChildView(scroller_); + box_layout_->SetFlexForView(scroller_, 1); +} + +void TrayDetailsView::AddScrollSeparator() { + DCHECK(scroll_content_); + // Do not draw the separator if it is the very first item + // in the scrollable list. + if (scroll_content_->has_children()) + scroll_content_->AddChildView(new ScrollSeparator); +} + +void TrayDetailsView::Reset() { + RemoveAllChildViews(true); + title_row_ = nullptr; + scroller_ = nullptr; + scroll_content_ = nullptr; + progress_bar_ = nullptr; + back_button_ = nullptr; + tri_view_ = nullptr; +} + +void TrayDetailsView::ShowProgress(double value, bool visible) { + DCHECK(UseMd()); + DCHECK(tri_view_); + if (!progress_bar_) { + progress_bar_ = new views::ProgressBar(kTitleRowProgressBarHeight); + progress_bar_->SetVisible(false); + AddChildViewAt(progress_bar_, kTitleRowSeparatorIndex + 1); + } + + progress_bar_->SetValue(value); + progress_bar_->SetVisible(visible); + child_at(kTitleRowSeparatorIndex)->SetVisible(!visible); +} + +views::CustomButton* TrayDetailsView::CreateSettingsButton( + LoginStatus status, + int setting_accessible_name_id) { + DCHECK(UseMd()); + SystemMenuButton* button = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + kSystemMenuSettingsIcon, setting_accessible_name_id); + if (!TrayPopupUtils::CanOpenWebUISettings(status)) + button->SetEnabled(false); + return button; +} + +views::CustomButton* TrayDetailsView::CreateHelpButton(LoginStatus status) { + DCHECK(UseMd()); + SystemMenuButton* button = + new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, + kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); + if (!TrayPopupUtils::CanOpenWebUISettings(status)) + button->SetEnabled(false); + return button; +} + +void TrayDetailsView::HandleViewClicked(views::View* view) { + NOTREACHED(); +} + +void TrayDetailsView::HandleButtonPressed(views::Button* sender, + const ui::Event& event) { + NOTREACHED(); +} + +void TrayDetailsView::CreateExtraTitleRowButtons() {} + +void TrayDetailsView::TransitionToDefaultView() { + if (UseMd()) { + if (back_button_ && back_button_->HasFocus()) + owner_->set_restore_focus(true); + } else { + if (title_row_ && title_row_->content() && + title_row_->content()->HasFocus()) { + owner_->set_restore_focus(true); + } + DoTransitionToDefaultView(); + return; + } + + transition_delay_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs), + this, &TrayDetailsView::DoTransitionToDefaultView); +} + +void TrayDetailsView::DoTransitionToDefaultView() { + // Cache pointer to owner in this function scope. TrayDetailsView will be + // deleted after called ShowDefaultView. + SystemTrayItem* owner = owner_; + owner->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING); + owner->set_restore_focus(false); +} + +views::Button* TrayDetailsView::CreateBackButton() { + DCHECK(UseMd()); + SystemMenuButton* button = new SystemMenuButton( + this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuArrowBackIcon, + IDS_ASH_STATUS_TRAY_PREVIOUS_MENU); + return button; +} + +void TrayDetailsView::Layout() { + views::View::Layout(); + if (scroller_ && !scroller_->is_bounded()) + scroller_->ClipHeightTo(0, scroller_->height()); +} + +int TrayDetailsView::GetHeightForWidth(int width) const { + if (!UseMd() || bounds().IsEmpty()) + return views::View::GetHeightForWidth(width); + + // The height of the bubble that contains this detailed view is set to + // the preferred height of the default view, and that determines the + // initial height of |this|. Always request to stay the same height. + return height(); +} + +void TrayDetailsView::OnPaintBorder(gfx::Canvas* canvas) { + if (scroll_border_) { + int index = GetIndexOf(scroller_); + if (index < child_count() - 1 && child_at(index + 1) != title_row_) + scroll_border_->set_visible(true); + else + scroll_border_->set_visible(false); + } + + views::View::OnPaintBorder(canvas); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_details_view.h b/ash/common/system/tray/tray_details_view.h new file mode 100644 index 0000000..2828763 --- /dev/null +++ b/ash/common/system/tray/tray_details_view.h
@@ -0,0 +1,145 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_DETAILS_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_DETAILS_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/system/tray/special_popup_row.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "base/macros.h" +#include "base/timer/timer.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace views { +class BoxLayout; +class CustomButton; +class ProgressBar; +class ScrollView; +} // namespace views + +namespace ash { +namespace test { +class TrayDetailsViewTest; +} // namespace test + +class ScrollBorder; +class SystemTrayItem; +class TriView; + +class ASH_EXPORT TrayDetailsView : public views::View, + public ViewClickListener, + public views::ButtonListener { + public: + explicit TrayDetailsView(SystemTrayItem* owner); + ~TrayDetailsView() override; + + // ViewClickListener: + // Don't override this --- override HandleViewClicked. + void OnViewClicked(views::View* sender) final; + + // views::ButtonListener: + // Don't override this --- override HandleButtonPressed. + void ButtonPressed(views::Button* sender, const ui::Event& event) final; + + SystemTrayItem* owner() { return owner_; } + SpecialPopupRow* title_row() { return title_row_; } + views::ScrollView* scroller() { return scroller_; } + views::View* scroll_content() { return scroll_content_; } + + protected: + // views::View: + void Layout() override; + int GetHeightForWidth(int width) const override; + void OnPaintBorder(gfx::Canvas* canvas) override; + + // Exposes the layout manager of this view to give control to subclasses. + views::BoxLayout* box_layout() { return box_layout_; } + + // Creates the row containing the back button and title. For material design + // this appears at the top of the view, for non-material design it appears + // at the bottom. + void CreateTitleRow(int string_id); + + // Creates a scrollable list. The list has a border at the bottom if there is + // any other view between the list and the footer row at the bottom. + void CreateScrollableList(); + + // Adds a separator in scrollable list. + void AddScrollSeparator(); + + // Removes (and destroys) all child views. + void Reset(); + + // Shows or hides the progress bar below the title row. It occupies the same + // space as the separator, so when shown the separator is hidden. If + // |progress_bar_| doesn't already exist it will be created. + void ShowProgress(double value, bool visible); + + // Helper functions which create and return the settings and help buttons, + // respectively, used in the material design top-most header row. The caller + // assumes ownership of the returned buttons. + views::CustomButton* CreateSettingsButton(LoginStatus status, + int setting_accessible_name_id); + views::CustomButton* CreateHelpButton(LoginStatus status); + + TriView* tri_view() { return tri_view_; } + + private: + friend class test::TrayDetailsViewTest; + + // Overridden to handle clicks on subclass-specific views. + virtual void HandleViewClicked(views::View* view); + + // Overridden to handle button presses on subclass-specific buttons. + virtual void HandleButtonPressed(views::Button* sender, + const ui::Event& event); + + // Creates and adds subclass-specific buttons to the title row. + virtual void CreateExtraTitleRowButtons(); + + // Transition to default view from details view. If |title_row_| has focus + // before transition, the default view should focus on the owner of this + // details view. + // + // In Material Design the actual transition is intentionally delayed to allow + // the user to perceive the ink drop animation on the clicked target. + void TransitionToDefaultView(); + + // Actually transitions to the default view. + void DoTransitionToDefaultView(); + + // Helper function which creates and returns the back button used in the + // material design top-most header row. The caller assumes ownership of the + // returned button. + views::Button* CreateBackButton(); + + SystemTrayItem* owner_; + views::BoxLayout* box_layout_; + SpecialPopupRow* title_row_; // Not used in material design. + views::ScrollView* scroller_; + views::View* scroll_content_; + views::ProgressBar* progress_bar_; + + ScrollBorder* scroll_border_; // Weak reference + + // The container view for the top-most title row in material design. + TriView* tri_view_; + + // The back button that appears in the material design title row. Not owned. + views::Button* back_button_; + + // Used to delay the transition to the default view. + base::OneShotTimer transition_delay_timer_; + + DISALLOW_COPY_AND_ASSIGN(TrayDetailsView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_DETAILS_VIEW_H_
diff --git a/ash/common/system/tray/tray_details_view_unittest.cc b/ash/common/system/tray/tray_details_view_unittest.cc new file mode 100644 index 0000000..f860a3a --- /dev/null +++ b/ash/common/system/tray/tray_details_view_unittest.cc
@@ -0,0 +1,248 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_details_view.h" + +#include "ash/common/ash_view_ids.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/special_popup_row.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_header_button.h" +#include "ash/common/system/tray/view_click_listener.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/test/ash_test_base.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/scoped_mock_time_message_loop_task_runner.h" +#include "base/test/test_mock_time_task_runner.h" +#include "ui/events/test/event_generator.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace test { + +namespace { + +class TestDetailsView : public TrayDetailsView { + public: + explicit TestDetailsView(SystemTrayItem* owner) : TrayDetailsView(owner) { + // Uses bluetooth label for testing purpose. It can be changed to any + // string_id. + CreateTitleRow(IDS_ASH_STATUS_TRAY_BLUETOOTH); + } + + ~TestDetailsView() override {} + + TrayPopupHeaderButton* tray_popup_header_button() { + return tray_popup_header_button_; + } + + void FocusTitleRow() { title_row()->content()->RequestFocus(); } + + void CreateScrollerViews() { CreateScrollableList(); } + + private: + TrayPopupHeaderButton* tray_popup_header_button_; + + DISALLOW_COPY_AND_ASSIGN(TestDetailsView); +}; + +// Trivial item implementation that tracks its views for testing. +class TestItem : public SystemTrayItem { + public: + TestItem() + : SystemTrayItem(AshTestBase::GetPrimarySystemTray(), UMA_TEST), + tray_view_(nullptr), + default_view_(nullptr), + detailed_view_(nullptr) {} + + // Overridden from SystemTrayItem: + views::View* CreateTrayView(LoginStatus status) override { + tray_view_ = new views::View; + return tray_view_; + } + views::View* CreateDefaultView(LoginStatus status) override { + default_view_ = new views::View; + default_view_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); + return default_view_; + } + views::View* CreateDetailedView(LoginStatus status) override { + detailed_view_ = new TestDetailsView(this); + return detailed_view_; + } + void DestroyTrayView() override { tray_view_ = NULL; } + void DestroyDefaultView() override { default_view_ = NULL; } + void DestroyDetailedView() override { detailed_view_ = NULL; } + + views::View* tray_view() const { return tray_view_; } + views::View* default_view() const { return default_view_; } + TestDetailsView* detailed_view() const { return detailed_view_; } + + private: + views::View* tray_view_; + views::View* default_view_; + TestDetailsView* detailed_view_; + + DISALLOW_COPY_AND_ASSIGN(TestItem); +}; + +} // namespace + +class TrayDetailsViewTest : public AshTestBase { + public: + TrayDetailsViewTest() {} + ~TrayDetailsViewTest() override {} + + HoverHighlightView* CreateAndShowHoverHighlightView() { + SystemTray* tray = GetPrimarySystemTray(); + TestItem* test_item = new TestItem; + tray->AddTrayItem(base::WrapUnique(test_item)); + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + + return static_cast<HoverHighlightView*>( + test_item->detailed_view()->title_row()->content()); + } + + TrayPopupHeaderButton* CreateAndShowTrayPopupHeaderButton() { + SystemTray* tray = GetPrimarySystemTray(); + TestItem* test_item = new TestItem; + tray->AddTrayItem(base::WrapUnique(test_item)); + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + + return test_item->detailed_view()->tray_popup_header_button(); + } + + void TransitionFromDetailedToDefaultView(TestDetailsView* detailed) { + detailed->TransitionToDefaultView(); + (*scoped_task_runner_) + ->FastForwardBy(base::TimeDelta::FromMilliseconds( + kTrayDetailedViewTransitionDelayMs)); + } + + void FocusBackButton(TestDetailsView* detailed) { + detailed->back_button_->RequestFocus(); + } + + void SetUp() override { + AshTestBase::SetUp(); + scoped_task_runner_ = + base::MakeUnique<base::ScopedMockTimeMessageLoopTaskRunner>(); + } + + void TearDown() override { + scoped_task_runner_.reset(); + AshTestBase::TearDown(); + } + + private: + // Used to control the |transition_delay_timer_|. + std::unique_ptr<base::ScopedMockTimeMessageLoopTaskRunner> + scoped_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(TrayDetailsViewTest); +}; + +TEST_F(TrayDetailsViewTest, TransitionToDefaultViewTest) { + SystemTray* tray = GetPrimarySystemTray(); + ASSERT_TRUE(tray->GetWidget()); + + TestItem* test_item_1 = new TestItem; + TestItem* test_item_2 = new TestItem; + tray->AddTrayItem(base::WrapUnique(test_item_1)); + tray->AddTrayItem(base::WrapUnique(test_item_2)); + + // Ensure the tray views are created. + ASSERT_TRUE(test_item_1->tray_view() != NULL); + ASSERT_TRUE(test_item_2->tray_view() != NULL); + + // Show the default view. + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + + // Show the detailed view of item 2. + tray->ShowDetailedView(test_item_2, 0, true, BUBBLE_USE_EXISTING); + EXPECT_TRUE(test_item_2->detailed_view()); + RunAllPendingInMessageLoop(); + EXPECT_FALSE(test_item_2->default_view()); + + // Transition back to default view, the default view of item 2 should have + // focus. + tray->GetSystemBubble()->bubble_view()->set_can_activate(true); + FocusBackButton(test_item_2->detailed_view()); + TransitionFromDetailedToDefaultView(test_item_2->detailed_view()); + RunAllPendingInMessageLoop(); + + EXPECT_TRUE(test_item_2->default_view()); + EXPECT_FALSE(test_item_2->detailed_view()); + EXPECT_TRUE(test_item_2->default_view()->HasFocus()); + + // Show the detailed view of item 2 again. + tray->ShowDetailedView(test_item_2, 0, true, BUBBLE_USE_EXISTING); + EXPECT_TRUE(test_item_2->detailed_view()); + RunAllPendingInMessageLoop(); + EXPECT_FALSE(test_item_2->default_view()); + + // Transition back to default view, the default view of item 2 should NOT have + // focus. + TransitionFromDetailedToDefaultView(test_item_2->detailed_view()); + RunAllPendingInMessageLoop(); + + EXPECT_TRUE(test_item_2->default_view()); + EXPECT_FALSE(test_item_2->detailed_view()); + EXPECT_FALSE(test_item_2->default_view()->HasFocus()); +} + +TEST_F(TrayDetailsViewTest, ScrollContentsTest) { + SystemTray* tray = GetPrimarySystemTray(); + TestItem* test_item = new TestItem; + tray->AddTrayItem(base::WrapUnique(test_item)); + tray->ShowDefaultView(BUBBLE_CREATE_NEW); + RunAllPendingInMessageLoop(); + tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); + RunAllPendingInMessageLoop(); + test_item->detailed_view()->CreateScrollerViews(); + + test_item->detailed_view()->scroll_content()->SetPaintToLayer(); + views::View* view1 = new views::View(); + test_item->detailed_view()->scroll_content()->AddChildView(view1); + views::View* view2 = new views::View(); + view2->SetPaintToLayer(); + test_item->detailed_view()->scroll_content()->AddChildView(view2); + views::View* view3 = new views::View(); + view3->SetPaintToLayer(); + test_item->detailed_view()->scroll_content()->AddChildView(view3); + + // Child layers should have same order as the child views. + const std::vector<ui::Layer*>& layers = + test_item->detailed_view()->scroll_content()->layer()->children(); + EXPECT_EQ(2u, layers.size()); + EXPECT_EQ(view2->layer(), layers[0]); + EXPECT_EQ(view3->layer(), layers[1]); + + // Mark |view2| as sticky and add one more child (which will reorder layers). + view2->set_id(VIEW_ID_STICKY_HEADER); + views::View* view4 = new views::View(); + view4->SetPaintToLayer(); + test_item->detailed_view()->scroll_content()->AddChildView(view4); + + // Sticky header layer should be above the last child's layer. + EXPECT_EQ(3u, layers.size()); + EXPECT_EQ(view3->layer(), layers[0]); + EXPECT_EQ(view4->layer(), layers[1]); + EXPECT_EQ(view2->layer(), layers[2]); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/system/tray/tray_event_filter.cc b/ash/common/system/tray/tray_event_filter.cc new file mode 100644 index 0000000..668d538 --- /dev/null +++ b/ash/common/system/tray/tray_event_filter.cc
@@ -0,0 +1,96 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_event_filter.h" + +#include "ash/common/system/tray/tray_background_view.h" +#include "ash/common/system/tray/tray_bubble_wrapper.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +TrayEventFilter::TrayEventFilter() {} + +TrayEventFilter::~TrayEventFilter() { + DCHECK(wrappers_.empty()); +} + +void TrayEventFilter::AddWrapper(TrayBubbleWrapper* wrapper) { + bool was_empty = wrappers_.empty(); + wrappers_.insert(wrapper); + if (was_empty && !wrappers_.empty()) { + WmShell::Get()->AddPointerWatcher(this, + views::PointerWatcherEventTypes::BASIC); + } +} + +void TrayEventFilter::RemoveWrapper(TrayBubbleWrapper* wrapper) { + wrappers_.erase(wrapper); + if (wrappers_.empty()) + WmShell::Get()->RemovePointerWatcher(this); +} + +void TrayEventFilter::OnPointerEventObserved( + const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) { + if (event.type() == ui::ET_POINTER_DOWN) + ProcessPressedEvent(location_in_screen, target); +} + +void TrayEventFilter::ProcessPressedEvent(const gfx::Point& location_in_screen, + views::Widget* target) { + if (target) { + WmWindow* window = WmWindow::Get(target->GetNativeWindow()); + int container_id = wm::GetContainerForWindow(window)->GetShellWindowId(); + // Don't process events that occurred inside an embedded menu, for example + // the right-click menu in a popup notification. + if (container_id == kShellWindowId_MenuContainer) + return; + // Don't process events that occurred inside a popup notification + // from message center. + if (container_id == kShellWindowId_StatusContainer && + window->GetType() == ui::wm::WINDOW_TYPE_POPUP && + target->IsAlwaysOnTop()) { + return; + } + } + + std::set<TrayBackgroundView*> trays; + // Check the boundary for all wrappers, and do not handle the event if it + // happens inside of any of those wrappers. + for (std::set<TrayBubbleWrapper*>::const_iterator iter = wrappers_.begin(); + iter != wrappers_.end(); ++iter) { + const TrayBubbleWrapper* wrapper = *iter; + const views::Widget* bubble_widget = wrapper->bubble_widget(); + if (!bubble_widget) + continue; + + gfx::Rect bounds = bubble_widget->GetWindowBoundsInScreen(); + bounds.Inset(wrapper->bubble_view()->GetBorderInsets()); + if (bounds.Contains(location_in_screen)) + continue; + if (wrapper->tray()) { + // If the user clicks on the parent tray, don't process the event here, + // let the tray logic handle the event and determine show/hide behavior. + bounds = wrapper->tray()->GetBoundsInScreen(); + if (bounds.Contains(location_in_screen)) + continue; + } + trays.insert((*iter)->tray()); + } + + // Close all bubbles other than the one a user clicked on the tray + // or its bubble. + for (std::set<TrayBackgroundView*>::iterator iter = trays.begin(); + iter != trays.end(); ++iter) { + (*iter)->ClickedOutsideBubble(); + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_event_filter.h b/ash/common/system/tray/tray_event_filter.h new file mode 100644 index 0000000..8d7b50f --- /dev/null +++ b/ash/common/system/tray/tray_event_filter.h
@@ -0,0 +1,50 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_ + +#include <set> + +#include "base/macros.h" +#include "ui/views/pointer_watcher.h" + +namespace gfx { +class Point; +} + +namespace ui { +class PointerEvent; +} + +namespace ash { +class TrayBubbleWrapper; + +// Handles events for a tray bubble, e.g. to close the system tray bubble when +// the user clicks outside it. +class TrayEventFilter : public views::PointerWatcher { + public: + TrayEventFilter(); + ~TrayEventFilter() override; + + void AddWrapper(TrayBubbleWrapper* wrapper); + void RemoveWrapper(TrayBubbleWrapper* wrapper); + + // views::PointerWatcher: + void OnPointerEventObserved(const ui::PointerEvent& event, + const gfx::Point& location_in_screen, + views::Widget* target) override; + + private: + void ProcessPressedEvent(const gfx::Point& location_in_screen, + views::Widget* target); + + std::set<TrayBubbleWrapper*> wrappers_; + + DISALLOW_COPY_AND_ASSIGN(TrayEventFilter); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_
diff --git a/ash/common/system/tray/tray_image_item.cc b/ash/common/system/tray/tray_image_item.cc new file mode 100644 index 0000000..da63db5 --- /dev/null +++ b/ash/common/system/tray/tray_image_item.cc
@@ -0,0 +1,78 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_image_item.h" + +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/layout/box_layout.h" + +namespace ash { + +TrayImageItem::TrayImageItem(SystemTray* system_tray, + const gfx::VectorIcon& icon, + UmaType uma_type) + : SystemTrayItem(system_tray, uma_type), + icon_(icon), + icon_color_(kTrayIconColor), + tray_view_(nullptr) {} + +TrayImageItem::~TrayImageItem() {} + +views::View* TrayImageItem::tray_view() { + return tray_view_; +} + +views::View* TrayImageItem::CreateTrayView(LoginStatus status) { + CHECK(!tray_view_); + tray_view_ = new TrayItemView(this); + tray_view_->CreateImageView(); + UpdateImageOnImageView(); + tray_view_->SetVisible(GetInitialVisibility()); + return tray_view_; +} + +views::View* TrayImageItem::CreateDefaultView(LoginStatus status) { + return nullptr; +} + +views::View* TrayImageItem::CreateDetailedView(LoginStatus status) { + return nullptr; +} + +void TrayImageItem::UpdateAfterLoginStatusChange(LoginStatus status) {} + +void TrayImageItem::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + SetTrayImageItemBorder(tray_view_, alignment); +} + +void TrayImageItem::DestroyTrayView() { + tray_view_ = nullptr; +} + +void TrayImageItem::DestroyDefaultView() {} + +void TrayImageItem::DestroyDetailedView() {} + +void TrayImageItem::SetIconColor(SkColor color) { + icon_color_ = color; + UpdateImageOnImageView(); +} + +void TrayImageItem::UpdateImageOnImageView() { + if (!tray_view_) + return; + + tray_view_->image_view()->SetImage( + gfx::CreateVectorIcon(icon_, kTrayIconSize, icon_color_)); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_image_item.h b/ash/common/system/tray/tray_image_item.h new file mode 100644 index 0000000..e9ac0b5 --- /dev/null +++ b/ash/common/system/tray/tray_image_item.h
@@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_IMAGE_ITEM_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_IMAGE_ITEM_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace views { +class ImageView; +} + +namespace gfx { +struct VectorIcon; +} + +namespace ash { +class TrayItemView; + +// A system tray item that uses an image as its "tray view" in the status area. +class ASH_EXPORT TrayImageItem : public SystemTrayItem { + public: + TrayImageItem(SystemTray* system_tray, + const gfx::VectorIcon& icon, + UmaType uma_type); + ~TrayImageItem() override; + + views::View* tray_view(); + + protected: + virtual bool GetInitialVisibility() = 0; + + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // Sets the color of the icon to |color|. + void SetIconColor(SkColor color); + + private: + // Sets the current icon on |tray_view_|'s ImageView. + void UpdateImageOnImageView(); + + // The icon and its current color. + const gfx::VectorIcon& icon_; + SkColor icon_color_; + + // The image view in the tray. + TrayItemView* tray_view_; + + DISALLOW_COPY_AND_ASSIGN(TrayImageItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_IMAGE_ITEM_H_
diff --git a/ash/common/system/tray/tray_item_more.cc b/ash/common/system/tray/tray_item_more.cc new file mode 100644 index 0000000..19edec9 --- /dev/null +++ b/ash/common/system/tray/tray_item_more.cc
@@ -0,0 +1,93 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_item_more.h" + +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "base/memory/ptr_util.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/gfx/image/image.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +TrayItemMore::TrayItemMore(SystemTrayItem* owner) + : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), + tri_view_(TrayPopupUtils::CreateDefaultRowView()), + icon_(TrayPopupUtils::CreateMainImageView()), + label_(TrayPopupUtils::CreateDefaultLabel()), + more_(TrayPopupUtils::CreateMoreImageView()) { + AddChildView(tri_view_); + SetLayoutManager(new views::FillLayout); + + tri_view_->AddView(TriView::Container::START, icon_); + tri_view_->AddView(TriView::Container::CENTER, label_); + tri_view_->AddView(TriView::Container::END, more_); + + SetInkDropMode(InkDropHostView::InkDropMode::ON); +} + +TrayItemMore::~TrayItemMore() {} + +void TrayItemMore::SetLabel(const base::string16& label) { + label_->SetText(label); + Layout(); + SchedulePaint(); +} + +void TrayItemMore::SetImage(const gfx::ImageSkia& image_skia) { + icon_->SetImage(image_skia); + SchedulePaint(); +} + +void TrayItemMore::SetAccessibleName(const base::string16& name) { + accessible_name_ = name; +} + +std::unique_ptr<TrayPopupItemStyle> TrayItemMore::CreateStyle() const { + std::unique_ptr<TrayPopupItemStyle> style = HandleCreateStyle(); + if (!enabled()) + style->set_color_style(TrayPopupItemStyle::ColorStyle::DISABLED); + return style; +} + +std::unique_ptr<TrayPopupItemStyle> TrayItemMore::HandleCreateStyle() const { + return base::MakeUnique<TrayPopupItemStyle>( + TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); +} + +void TrayItemMore::UpdateStyle() { + std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); + style->SetupLabel(label_); +} + +bool TrayItemMore::PerformAction(const ui::Event& event) { + owner()->TransitionDetailedView(); + return true; +} + +void TrayItemMore::GetAccessibleNodeData(ui::AXNodeData* node_data) { + ActionableView::GetAccessibleNodeData(node_data); + if (!accessible_name_.empty()) + node_data->SetName(accessible_name_); +} + +void TrayItemMore::OnEnabledChanged() { + ActionableView::OnEnabledChanged(); + tri_view_->SetContainerVisible(TriView::Container::END, enabled()); + UpdateStyle(); +} + +void TrayItemMore::OnNativeThemeChanged(const ui::NativeTheme* theme) { + ActionableView::OnNativeThemeChanged(theme); + UpdateStyle(); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_item_more.h b/ash/common/system/tray/tray_item_more.h new file mode 100644 index 0000000..fbbd721 --- /dev/null +++ b/ash/common/system/tray/tray_item_more.h
@@ -0,0 +1,75 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_ITEM_MORE_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_ITEM_MORE_H_ + +#include <memory> + +#include "ash/common/system/tray/actionable_view.h" +#include "base/macros.h" +#include "ui/views/view.h" + +namespace views { +class ImageView; +class Label; +class View; +} + +namespace ash { +class SystemTrayItem; +class TrayPopupItemStyle; +class TriView; + +// A view with a more arrow on the right edge. Clicking on the view brings up +// the detailed view of the tray-item that owns it. If the view is disabled, it +// will not show the more arrow. +class TrayItemMore : public ActionableView { + public: + explicit TrayItemMore(SystemTrayItem* owner); + ~TrayItemMore() override; + + void SetLabel(const base::string16& label); + void SetImage(const gfx::ImageSkia& image_skia); + void SetAccessibleName(const base::string16& name); + + protected: + // Returns a style that will be applied to the elements in the UpdateStyle() + // method if |this| is enabled; otherwise, we force |this| to use + // ColorStyle::DISABLED. + std::unique_ptr<TrayPopupItemStyle> CreateStyle() const; + + // Called by CreateStyle() to give descendants a chance to customize the + // style; e.g. to change the style's ColorStyle based on whether Bluetooth is + // enabled/disabled. + virtual std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const; + + // Applies the style created from CreateStyle(). Should be called whenever any + // input state changes that changes the style configuration created by + // CreateStyle(). E.g. if Bluetooth is changed between enabled/disabled then + // a differently configured style will be returned from CreateStyle() and thus + // it will need to be applied. + virtual void UpdateStyle(); + + private: + // Overridden from ActionableView. + bool PerformAction(const ui::Event& event) override; + + // Overridden from views::View. + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void OnEnabledChanged() override; + void OnNativeThemeChanged(const ui::NativeTheme* theme) override; + + TriView* tri_view_; + views::ImageView* icon_; + views::Label* label_; + views::ImageView* more_; + base::string16 accessible_name_; + + DISALLOW_COPY_AND_ASSIGN(TrayItemMore); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_ITEM_MORE_H_
diff --git a/ash/common/system/tray/tray_item_view.cc b/ash/common/system/tray/tray_item_view.cc new file mode 100644 index 0000000..65ad50c --- /dev/null +++ b/ash/common/system/tray/tray_item_view.cc
@@ -0,0 +1,150 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_item_view.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/public/cpp/shelf_types.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/widget/widget.h" + +namespace { +const int kTrayIconHeight = 29; +const int kTrayIconWidth = 29; +const int kTrayItemAnimationDurationMS = 200; + +// Animations can be disabled for testing. +bool animations_enabled = true; +} + +namespace ash { + +TrayItemView::TrayItemView(SystemTrayItem* owner) + : owner_(owner), label_(NULL), image_view_(NULL) { + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + SetLayoutManager(new views::FillLayout()); +} + +TrayItemView::~TrayItemView() {} + +// static +void TrayItemView::DisableAnimationsForTest() { + animations_enabled = false; +} + +void TrayItemView::CreateLabel() { + label_ = new views::Label; + AddChildView(label_); + PreferredSizeChanged(); +} + +void TrayItemView::CreateImageView() { + image_view_ = new views::ImageView; + AddChildView(image_view_); + PreferredSizeChanged(); +} + +void TrayItemView::SetVisible(bool set_visible) { + if (!GetWidget() || !animations_enabled) { + views::View::SetVisible(set_visible); + return; + } + + if (!animation_) { + animation_.reset(new gfx::SlideAnimation(this)); + animation_->SetSlideDuration(GetAnimationDurationMS()); + animation_->SetTweenType(gfx::Tween::LINEAR); + animation_->Reset(visible() ? 1.0 : 0.0); + } + + if (!set_visible) { + animation_->Hide(); + AnimationProgressed(animation_.get()); + } else { + animation_->Show(); + AnimationProgressed(animation_.get()); + views::View::SetVisible(true); + } +} + +// static +bool TrayItemView::UseMd() { + return MaterialDesignController::UseMaterialDesignSystemIcons(); +} + +int TrayItemView::GetAnimationDurationMS() { + return kTrayItemAnimationDurationMS; +} + +gfx::Size TrayItemView::GetPreferredSize() const { + DCHECK_EQ(1, child_count()); + gfx::Size size; + if (UseMd()) { + gfx::Size inner_size = views::View::GetPreferredSize(); + if (image_view_) + inner_size = gfx::Size(kTrayIconSize, kTrayIconSize); + gfx::Rect rect(inner_size); + rect.Inset(gfx::Insets(-kTrayImageItemPadding)); + size = rect.size(); + } else { + size = views::View::GetPreferredSize(); + if (IsHorizontalAlignment(owner()->system_tray()->shelf_alignment())) + size.set_height(kTrayIconHeight); + else + size.set_width(kTrayIconWidth); + } + if (!animation_.get() || !animation_->is_animating()) + return size; + if (IsHorizontalAlignment(owner()->system_tray()->shelf_alignment())) { + size.set_width(std::max( + 1, static_cast<int>(size.width() * animation_->GetCurrentValue()))); + } else { + size.set_height(std::max( + 1, static_cast<int>(size.height() * animation_->GetCurrentValue()))); + } + return size; +} + +int TrayItemView::GetHeightForWidth(int width) const { + return GetPreferredSize().height(); +} + +void TrayItemView::ChildPreferredSizeChanged(views::View* child) { + PreferredSizeChanged(); +} + +void TrayItemView::AnimationProgressed(const gfx::Animation* animation) { + gfx::Transform transform; + if (IsHorizontalAlignment(owner()->system_tray()->shelf_alignment())) { + transform.Translate(0, animation->CurrentValueBetween( + static_cast<double>(height()) / 2, 0.)); + } else { + transform.Translate( + animation->CurrentValueBetween(static_cast<double>(width() / 2), 0.), + 0); + } + transform.Scale(animation->GetCurrentValue(), animation->GetCurrentValue()); + layer()->SetTransform(transform); + PreferredSizeChanged(); +} + +void TrayItemView::AnimationEnded(const gfx::Animation* animation) { + if (animation->GetCurrentValue() < 0.1) + views::View::SetVisible(false); +} + +void TrayItemView::AnimationCanceled(const gfx::Animation* animation) { + AnimationEnded(animation); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_item_view.h b/ash/common/system/tray/tray_item_view.h new file mode 100644 index 0000000..ab295d96 --- /dev/null +++ b/ash/common/system/tray/tray_item_view.h
@@ -0,0 +1,78 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_ITEM_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_ITEM_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/gfx/animation/animation_delegate.h" +#include "ui/views/view.h" + +namespace gfx { +class SlideAnimation; +} + +namespace views { +class ImageView; +class Label; +} + +namespace ash { +class SystemTrayItem; + +// Base-class for items in the tray. It makes sure the widget is updated +// correctly when the visibility/size of the tray item changes. It also adds +// animation when showing/hiding the item in the tray. +class ASH_EXPORT TrayItemView : public views::View, + public gfx::AnimationDelegate { + public: + explicit TrayItemView(SystemTrayItem* owner); + ~TrayItemView() override; + + static void DisableAnimationsForTest(); + + // Convenience function for creating a child Label or ImageView. + // Only one of the two should be called. + void CreateLabel(); + void CreateImageView(); + + SystemTrayItem* owner() const { return owner_; } + views::Label* label() const { return label_; } + views::ImageView* image_view() const { return image_view_; } + + // Overridden from views::View. + void SetVisible(bool visible) override; + gfx::Size GetPreferredSize() const override; + int GetHeightForWidth(int width) const override; + + protected: + static bool UseMd(); + + // The default animation duration is 200ms. But each view can customize this. + virtual int GetAnimationDurationMS(); + + private: + // Overridden from views::View. + void ChildPreferredSizeChanged(View* child) override; + + // Overridden from gfx::AnimationDelegate. + void AnimationProgressed(const gfx::Animation* animation) override; + void AnimationEnded(const gfx::Animation* animation) override; + void AnimationCanceled(const gfx::Animation* animation) override; + + SystemTrayItem* owner_; + std::unique_ptr<gfx::SlideAnimation> animation_; + // Only one of |label_| and |image_view_| should be non-null. + views::Label* label_; + views::ImageView* image_view_; + + DISALLOW_COPY_AND_ASSIGN(TrayItemView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_ITEM_VIEW_H_
diff --git a/ash/common/system/tray/tray_notification_view.cc b/ash/common/system/tray/tray_notification_view.cc new file mode 100644 index 0000000..b1d67f549 --- /dev/null +++ b/ash/common/system/tray/tray_notification_view.cc
@@ -0,0 +1,96 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_notification_view.h" + +#include "ash/common/system/tray/tray_constants.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/resources/grit/ui_resources.h" +#include "ui/views/background.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/layout/grid_layout.h" + +namespace ash { + +namespace { + +// Maps a non-MD PNG resource id to its corresponding MD vector icon. +// TODO(tdanderson): Remove this once material design is enabled by +// default. See crbug.com/614453. +const gfx::VectorIcon& ResourceIdToVectorIcon(int resource_id) { + switch (resource_id) { + case IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK: + return kSystemMenuAccessibilityIcon; + default: + NOTREACHED(); + break; + } + + return gfx::kNoneIcon; +} + +} // namespace + +TrayNotificationView::TrayNotificationView(int icon_id) + : icon_id_(icon_id), icon_(NULL) {} + +TrayNotificationView::~TrayNotificationView() {} + +void TrayNotificationView::InitView(views::View* contents) { + set_background(views::Background::CreateSolidBackground(kBackgroundColor)); + + views::GridLayout* layout = new views::GridLayout(this); + SetLayoutManager(layout); + + views::ImageView* close_button = new views::ImageView(); + close_button->SetImage( + ResourceBundle::GetSharedInstance().GetImageSkiaNamed(IDR_MESSAGE_CLOSE)); + close_button->SetHorizontalAlignment(views::ImageView::CENTER); + close_button->SetVerticalAlignment(views::ImageView::CENTER); + + icon_ = new views::ImageView; + if (icon_id_ != 0) { + icon_->SetImage(gfx::CreateVectorIcon(ResourceIdToVectorIcon(icon_id_), + kMenuIconColor)); + } + + views::ColumnSet* columns = layout->AddColumnSet(0); + + columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2); + + // Icon + columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, + 0, /* resize percent */ + views::GridLayout::FIXED, kNotificationIconWidth, + kNotificationIconWidth); + + columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2); + + // Contents + columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, + 100, /* resize percent */ + views::GridLayout::FIXED, kTrayNotificationContentsWidth, + kTrayNotificationContentsWidth); + + columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2); + + // Close button + columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING, + 0, /* resize percent */ + views::GridLayout::FIXED, kNotificationButtonWidth, + kNotificationButtonWidth); + + // Layout rows + layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems); + layout->StartRow(0, 0); + layout->AddView(icon_); + layout->AddView(contents); + layout->AddView(close_button); + layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_notification_view.h b/ash/common/system/tray/tray_notification_view.h new file mode 100644 index 0000000..58e29667 --- /dev/null +++ b/ash/common/system/tray/tray_notification_view.h
@@ -0,0 +1,39 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_NOTIFICATION_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_NOTIFICATION_VIEW_H_ + +#include "ui/views/view.h" + +namespace views { +class ImageView; +} + +namespace ash { + +// A view for closable notification views, laid out like: +// ------------------- +// | icon contents x | +// ----------------v-- +// The close button will call OnClose() when clicked. +class TrayNotificationView : public views::View { + public: + // If icon_id is 0, no icon image will be set. + explicit TrayNotificationView(int icon_id); + ~TrayNotificationView() override; + + // InitView must be called once with the contents to be displayed. + void InitView(views::View* contents); + + private: + int icon_id_; + views::ImageView* icon_; + + DISALLOW_COPY_AND_ASSIGN(TrayNotificationView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_NOTIFICATION_VIEW_H_
diff --git a/ash/common/system/tray/tray_popup_header_button.cc b/ash/common/system/tray/tray_popup_header_button.cc new file mode 100644 index 0000000..07334c6 --- /dev/null +++ b/ash/common/system/tray/tray_popup_header_button.cc
@@ -0,0 +1,86 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_popup_header_button.h" + +#include "ash/common/ash_constants.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/views/background.h" +#include "ui/views/painter.h" + +namespace ash { + +namespace { + +const gfx::ImageSkia* GetImageForResourceId(int resource_id) { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + return bundle.GetImageNamed(resource_id).ToImageSkia(); +} + +} // namespace + +// static +const char TrayPopupHeaderButton::kViewClassName[] = + "tray/TrayPopupHeaderButton"; + +TrayPopupHeaderButton::TrayPopupHeaderButton(views::ButtonListener* listener, + const gfx::ImageSkia& icon, + int accessible_name_id) + : views::ToggleImageButton(listener) { + Initialize(icon, accessible_name_id); +} + +TrayPopupHeaderButton::TrayPopupHeaderButton(views::ButtonListener* listener, + int enabled_resource_id, + int disabled_resource_id, + int enabled_resource_id_hover, + int disabled_resource_id_hover, + int accessible_name_id) + : views::ToggleImageButton(listener) { + Initialize(*GetImageForResourceId(enabled_resource_id), accessible_name_id); + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + SetToggledImage(views::Button::STATE_NORMAL, + bundle.GetImageNamed(disabled_resource_id).ToImageSkia()); + SetImage(views::Button::STATE_HOVERED, + *bundle.GetImageNamed(enabled_resource_id_hover).ToImageSkia()); + SetToggledImage( + views::Button::STATE_HOVERED, + bundle.GetImageNamed(disabled_resource_id_hover).ToImageSkia()); +} + +TrayPopupHeaderButton::~TrayPopupHeaderButton() {} + +const char* TrayPopupHeaderButton::GetClassName() const { + return kViewClassName; +} + +gfx::Size TrayPopupHeaderButton::GetPreferredSize() const { + return gfx::Size(kTrayPopupItemMinHeight, kTrayPopupItemMinHeight); +} + +void TrayPopupHeaderButton::StateChanged(ButtonState old_state) { + if (state() == STATE_HOVERED || state() == STATE_PRESSED) { + set_background(views::Background::CreateSolidBackground( + kTrayPopupHoverBackgroundColor)); + } else { + set_background(nullptr); + } + SchedulePaint(); +} + +void TrayPopupHeaderButton::Initialize(const gfx::ImageSkia& icon, + int accessible_name_id) { + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + SetImage(views::Button::STATE_NORMAL, icon); + SetImageAlignment(views::ImageButton::ALIGN_CENTER, + views::ImageButton::ALIGN_MIDDLE); + SetAccessibleName(bundle.GetLocalizedString(accessible_name_id)); + SetFocusForPlatform(); + + SetFocusPainter(views::Painter::CreateSolidFocusPainter( + kFocusBorderColor, gfx::Insets(1, 2, 2, 3))); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_popup_header_button.h b/ash/common/system/tray/tray_popup_header_button.h new file mode 100644 index 0000000..6a2ffb1 --- /dev/null +++ b/ash/common/system/tray/tray_popup_header_button.h
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_HEADER_BUTTON_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_HEADER_BUTTON_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/views/controls/button/image_button.h" + +namespace ash { + +// A ToggleImageButton with fixed size, paddings and hover effects. These +// buttons are used in the header. +class ASH_EXPORT TrayPopupHeaderButton : public views::ToggleImageButton { + public: + static const char kViewClassName[]; + + TrayPopupHeaderButton(views::ButtonListener* listener, + const gfx::ImageSkia& icon, + int accessible_name_id); + TrayPopupHeaderButton(views::ButtonListener* listener, + int enabled_resource_id, + int disabled_resource_id, + int enabled_resource_id_hover, + int disabled_resource_id_hover, + int accessible_name_id); + ~TrayPopupHeaderButton() override; + + private: + // Overridden from views::View: + const char* GetClassName() const override; + gfx::Size GetPreferredSize() const override; + + // Overridden from views::CustomButton: + void StateChanged(ButtonState old_state) override; + + void Initialize(const gfx::ImageSkia& icon, int accessible_name_id); + + DISALLOW_COPY_AND_ASSIGN(TrayPopupHeaderButton); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_HEADER_BUTTON_H_
diff --git a/ash/common/system/tray/tray_popup_ink_drop_style.h b/ash/common/system/tray/tray_popup_ink_drop_style.h new file mode 100644 index 0000000..94de103 --- /dev/null +++ b/ash/common/system/tray/tray_popup_ink_drop_style.h
@@ -0,0 +1,27 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_INK_DROP_STYLE_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_INK_DROP_STYLE_H_ + +namespace ash { + +// The different styles of ink drops applied to the system menu. +enum class TrayPopupInkDropStyle { + // Used for targets where the user doesn't need to know the exact targetable + // area and they are expected to target an icon centered in the targetable + // space. Highlight and ripple are drawn as a circle. + HOST_CENTERED, + // Used for targets where the user should know the targetable bounds but + // where the ink drop shouldn't fill the entire bounds. e.g. row of buttons + // separated with separators. + INSET_BOUNDS, + // Used for targets that should indicate to the user what the actual + // targetable bounds are. e.g. a full system menu row. + FILL_BOUNDS +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_INK_DROP_STYLE_H_
diff --git a/ash/common/system/tray/tray_popup_item_container.cc b/ash/common/system/tray/tray_popup_item_container.cc new file mode 100644 index 0000000..3a3d0d5 --- /dev/null +++ b/ash/common/system/tray/tray_popup_item_container.cc
@@ -0,0 +1,77 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_popup_item_container.h" + +#include "ash/common/system/tray/tray_constants.h" +#include "ui/gfx/canvas.h" +#include "ui/views/layout/box_layout.h" + +namespace ash { + +TrayPopupItemContainer::TrayPopupItemContainer(views::View* view, + bool change_background) + : active_(false), change_background_(change_background) { + set_notify_enter_exit_on_child(true); + views::BoxLayout* layout = + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); + layout->SetDefaultFlex(1); + SetLayoutManager(layout); + if (view->layer()) { + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(view->layer()->fills_bounds_opaquely()); + } + AddChildView(view); + SetVisible(view->visible()); +} + +TrayPopupItemContainer::~TrayPopupItemContainer() {} + +void TrayPopupItemContainer::SetActive(bool active) { + if (!change_background_ || active_ == active) + return; + active_ = active; + SchedulePaint(); +} + +void TrayPopupItemContainer::ChildVisibilityChanged(View* child) { + if (visible() == child->visible()) + return; + SetVisible(child->visible()); + PreferredSizeChanged(); +} + +void TrayPopupItemContainer::ChildPreferredSizeChanged(View* child) { + PreferredSizeChanged(); +} + +void TrayPopupItemContainer::OnMouseEntered(const ui::MouseEvent& event) { + SetActive(true); +} + +void TrayPopupItemContainer::OnMouseExited(const ui::MouseEvent& event) { + SetActive(false); +} + +void TrayPopupItemContainer::OnGestureEvent(ui::GestureEvent* event) { + if (event->type() == ui::ET_GESTURE_TAP_DOWN) { + SetActive(true); + } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || + event->type() == ui::ET_GESTURE_TAP) { + SetActive(false); + } +} + +void TrayPopupItemContainer::OnPaintBackground(gfx::Canvas* canvas) { + if (child_count() == 0) + return; + + views::View* view = child_at(0); + if (!view->background()) { + canvas->FillRect(gfx::Rect(size()), + (active_) ? kHoverBackgroundColor : kBackgroundColor); + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_popup_item_container.h b/ash/common/system/tray/tray_popup_item_container.h new file mode 100644 index 0000000..2fdddb7f --- /dev/null +++ b/ash/common/system/tray/tray_popup_item_container.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_ITEM_CONTAINER_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_ITEM_CONTAINER_H_ + +#include "base/macros.h" +#include "ui/views/view.h" + +namespace ash { + +// A view which can optionally change the background color when a mouse is +// hovering or a user is interacting via touch. +class TrayPopupItemContainer : public views::View { + public: + TrayPopupItemContainer(views::View* view, bool change_background); + + ~TrayPopupItemContainer() override; + + bool active() { return active_; } + + private: + // Sets whether the active background is to be used, and triggers a paint. + void SetActive(bool active); + + // views::View: + void ChildVisibilityChanged(views::View* child) override; + void ChildPreferredSizeChanged(views::View* child) override; + void OnMouseEntered(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + void OnGestureEvent(ui::GestureEvent* event) override; + void OnPaintBackground(gfx::Canvas* canvas) override; + + // True if either a mouse is hovering over this view, or if a user has touched + // down. + bool active_; + + // True if mouse hover and touch feedback can alter the background color of + // the container. + bool change_background_; + + DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_ITEM_CONTAINER_H_
diff --git a/ash/common/system/tray/tray_popup_item_style.cc b/ash/common/system/tray/tray_popup_item_style.cc new file mode 100644 index 0000000..ee5a8ce --- /dev/null +++ b/ash/common/system/tray/tray_popup_item_style.cc
@@ -0,0 +1,103 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_popup_item_style.h" + +#include "third_party/skia/include/core/SkColor.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/font.h" +#include "ui/gfx/font_list.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/controls/label.h" + +namespace ash { +namespace { + +const int kInactiveAlpha = 0x8A; +const int kDisabledAlpha = 0x61; + +} // namespace + +// static +SkColor TrayPopupItemStyle::GetIconColor(ColorStyle color_style) { + switch (color_style) { + case ColorStyle::ACTIVE: + return gfx::kChromeIconGrey; + case ColorStyle::INACTIVE: + return SkColorSetA(gfx::kChromeIconGrey, kInactiveAlpha); + case ColorStyle::DISABLED: + return SkColorSetA(gfx::kChromeIconGrey, kDisabledAlpha); + case ColorStyle::CONNECTED: + return gfx::kPlaceholderColor; + } + NOTREACHED(); + return gfx::kPlaceholderColor; +} + +TrayPopupItemStyle::TrayPopupItemStyle(FontStyle font_style) + : font_style_(font_style), color_style_(ColorStyle::ACTIVE) { + if (font_style_ == FontStyle::SYSTEM_INFO) + color_style_ = ColorStyle::INACTIVE; +} + +TrayPopupItemStyle::~TrayPopupItemStyle() {} + +SkColor TrayPopupItemStyle::GetTextColor() const { + const SkColor kBaseTextColor = SkColorSetA(SK_ColorBLACK, 0xDE); + + switch (color_style_) { + case ColorStyle::ACTIVE: + return kBaseTextColor; + case ColorStyle::INACTIVE: + return SkColorSetA(kBaseTextColor, kInactiveAlpha); + case ColorStyle::DISABLED: + return SkColorSetA(kBaseTextColor, kDisabledAlpha); + case ColorStyle::CONNECTED: + return gfx::kGoogleGreen700; + } + NOTREACHED(); + return gfx::kPlaceholderColor; +} + +SkColor TrayPopupItemStyle::GetIconColor() const { + return GetIconColor(color_style_); +} + +void TrayPopupItemStyle::SetupLabel(views::Label* label) const { + label->SetEnabledColor(GetTextColor()); + + const gfx::FontList& base_font_list = views::Label::GetDefaultFontList(); + switch (font_style_) { + case FontStyle::TITLE: + label->SetFontList(base_font_list.Derive(2, gfx::Font::NORMAL, + gfx::Font::Weight::MEDIUM)); + break; + case FontStyle::DEFAULT_VIEW_LABEL: + label->SetFontList(base_font_list.Derive(2, gfx::Font::NORMAL, + gfx::Font::Weight::NORMAL)); + break; + case FontStyle::SUB_HEADER: + label->SetFontList(base_font_list.Derive(1, gfx::Font::NORMAL, + gfx::Font::Weight::MEDIUM)); + label->SetEnabledColor(label->GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_ProminentButtonColor)); + label->SetAutoColorReadabilityEnabled(false); + break; + case FontStyle::DETAILED_VIEW_LABEL: + case FontStyle::SYSTEM_INFO: + label->SetFontList(base_font_list.Derive(1, gfx::Font::NORMAL, + gfx::Font::Weight::NORMAL)); + break; + case FontStyle::BUTTON: + label->SetFontList(base_font_list.Derive(0, gfx::Font::NORMAL, + gfx::Font::Weight::MEDIUM)); + break; + case FontStyle::CAPTION: + label->SetFontList(base_font_list.Derive(0, gfx::Font::NORMAL, + gfx::Font::Weight::NORMAL)); + break; + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_popup_item_style.h b/ash/common/system/tray/tray_popup_item_style.h new file mode 100644 index 0000000..bb9465ea --- /dev/null +++ b/ash/common/system/tray/tray_popup_item_style.h
@@ -0,0 +1,83 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_ITEM_STYLE_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_ITEM_STYLE_H_ + +#include "base/macros.h" +#include "third_party/skia/include/core/SkColor.h" + +namespace views { +class Label; +} // namespace views + +namespace ash { + +// Central style provider for the system tray menu. Makes it easier to ensure +// all visuals are consistent and easily updated in one spot instead of being +// defined in multiple places throughout the code. +class TrayPopupItemStyle { + public: + // The different visual styles that a row can have. + enum class ColorStyle { + // Active and clickable. + ACTIVE, + // Inactive but clickable. + INACTIVE, + // Disabled and not clickable. + DISABLED, + // Color for "Connected" labels. + CONNECTED, + }; + + // The different font styles that row text can have. + enum class FontStyle { + // Topmost header rows for default view and detailed view. + TITLE, + // Main text used by default view rows. + DEFAULT_VIEW_LABEL, + // Text in sub-section header rows in detailed views. + SUB_HEADER, + // Main text used by detailed view rows. + DETAILED_VIEW_LABEL, + // System information text (e.g. date/time, battery status, etc). + SYSTEM_INFO, + // Child buttons within rows that have a visible border (e.g. Cast's + // "Stop", etc). + BUTTON, + // Sub text within a row (e.g. user name in user row). + CAPTION, + }; + + static SkColor GetIconColor(ColorStyle color_style); + + explicit TrayPopupItemStyle(FontStyle font_style); + ~TrayPopupItemStyle(); + + ColorStyle color_style() const { return color_style_; } + + void set_color_style(ColorStyle color_style) { color_style_ = color_style; } + + FontStyle font_style() const { return font_style_; } + + void set_font_style(FontStyle font_style) { font_style_ = font_style; } + + SkColor GetTextColor() const; + + SkColor GetIconColor() const; + + // Configures a Label as per the style (e.g. color, font). + void SetupLabel(views::Label* label) const; + + private: + FontStyle font_style_; + + ColorStyle color_style_; + + DISALLOW_COPY_AND_ASSIGN(TrayPopupItemStyle); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_ITEM_STYLE_H_
diff --git a/ash/common/system/tray/tray_popup_utils.cc b/ash/common/system/tray/tray_popup_utils.cc new file mode 100644 index 0000000..4e065c6 --- /dev/null +++ b/ash/common/system/tray/tray_popup_utils.cc
@@ -0,0 +1,437 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_popup_utils.h" + +#include <algorithm> +#include <utility> + +#include "ash/common/ash_constants.h" +#include "ash/common/ash_view_ids.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/size_range_layout.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "base/memory/ptr_util.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop_highlight.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/animation/square_ink_drop_ripple.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/button/md_text_button.h" +#include "ui/views/controls/button/toggle_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/controls/slider.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" + +namespace ash { + +namespace { + +// Creates a layout manager that positions Views vertically. The Views will be +// stretched horizontally and centered vertically. +std::unique_ptr<views::LayoutManager> CreateDefaultCenterLayoutManager() { + // TODO(bruthig): Use constants instead of magic numbers. + auto box_layout = + base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical, 4, 8, 0); + box_layout->set_main_axis_alignment( + views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); + box_layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); + return std::move(box_layout); +} + +// Creates a layout manager that positions Views horizontally. The Views will be +// centered along the horizontal and vertical axis. +std::unique_ptr<views::LayoutManager> CreateDefaultEndsLayoutManager() { + auto box_layout = base::MakeUnique<views::BoxLayout>( + views::BoxLayout::kHorizontal, 0, 0, 0); + box_layout->set_main_axis_alignment( + views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); + box_layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + return std::move(box_layout); +} + +std::unique_ptr<views::LayoutManager> CreateDefaultLayoutManager( + TriView::Container container) { + switch (container) { + case TriView::Container::START: + case TriView::Container::END: + return CreateDefaultEndsLayoutManager(); + case TriView::Container::CENTER: + return CreateDefaultCenterLayoutManager(); + } + // Required by some compilers. + NOTREACHED(); + return nullptr; +} + +// Configures the default size and flex value for the specified |container| +// of the given |tri_view|. Used by CreateDefaultRowView(). +void ConfigureDefaultSizeAndFlex(TriView* tri_view, + TriView::Container container) { + int min_width = 0; + switch (container) { + case TriView::Container::START: + min_width = kTrayPopupItemMinStartWidth; + break; + case TriView::Container::CENTER: + tri_view->SetFlexForContainer(TriView::Container::CENTER, 1.f); + break; + case TriView::Container::END: + min_width = kTrayPopupItemMinEndWidth; + break; + } + + tri_view->SetMinSize(container, + gfx::Size(min_width, kTrayPopupItemMinHeight)); + constexpr int kTrayPopupItemMaxHeight = 144; + tri_view->SetMaxSize( + container, + gfx::Size(SizeRangeLayout::kAbsoluteMaxSize, kTrayPopupItemMaxHeight)); +} + +class BorderlessLabelButton : public views::LabelButton { + public: + BorderlessLabelButton(views::ButtonListener* listener, + const base::string16& text) + : LabelButton(listener, text) { + const int kHorizontalPadding = 20; + SetBorder(views::CreateEmptyBorder(gfx::Insets(0, kHorizontalPadding))); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::BUTTON); + style.SetupLabel(label()); + SetHorizontalAlignment(gfx::ALIGN_CENTER); + SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + + TrayPopupUtils::ConfigureTrayPopupButton(this); + } + + ~BorderlessLabelButton() override {} + + // views::LabelButton: + int GetHeightForWidth(int width) const override { return kMenuButtonSize; } + + private: + // TODO(estade,bruthig): there's a lot in common here with ActionableView. + // Find a way to share. See related TODO on InkDropHostView::SetInkDropMode(). + std::unique_ptr<views::InkDrop> CreateInkDrop() override { + return TrayPopupUtils::CreateInkDrop(TrayPopupInkDropStyle::INSET_BOUNDS, + this); + } + + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override { + return TrayPopupUtils::CreateInkDropRipple( + TrayPopupInkDropStyle::INSET_BOUNDS, this, + GetInkDropCenterBasedOnLastEvent()); + } + + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override { + return TrayPopupUtils::CreateInkDropHighlight( + TrayPopupInkDropStyle::INSET_BOUNDS, this); + } + + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override { + return TrayPopupUtils::CreateInkDropMask( + TrayPopupInkDropStyle::INSET_BOUNDS, this); + } + + DISALLOW_COPY_AND_ASSIGN(BorderlessLabelButton); +}; + +} // namespace + +TriView* TrayPopupUtils::CreateDefaultRowView() { + TriView* tri_view = CreateMultiTargetRowView(); + + tri_view->SetContainerLayout( + TriView::Container::START, + CreateDefaultLayoutManager(TriView::Container::START)); + tri_view->SetContainerLayout( + TriView::Container::CENTER, + CreateDefaultLayoutManager(TriView::Container::CENTER)); + tri_view->SetContainerLayout( + TriView::Container::END, + CreateDefaultLayoutManager(TriView::Container::END)); + + return tri_view; +} + +TriView* TrayPopupUtils::CreateSubHeaderRowView() { + TriView* tri_view = CreateMultiTargetRowView(); + tri_view->SetInsets(gfx::Insets(0, kTrayPopupPaddingHorizontal, 0, 0)); + tri_view->SetContainerVisible(TriView::Container::START, false); + tri_view->SetContainerLayout( + TriView::Container::END, + CreateDefaultLayoutManager(TriView::Container::END)); + return tri_view; +} + +TriView* TrayPopupUtils::CreateMultiTargetRowView() { + TriView* tri_view = new TriView(0 /* padding_between_items */); + + tri_view->SetInsets(gfx::Insets(0, kMenuExtraMarginFromLeftEdge, 0, 0)); + + ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::START); + ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::CENTER); + ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::END); + + tri_view->SetContainerLayout(TriView::Container::START, + base::MakeUnique<views::FillLayout>()); + tri_view->SetContainerLayout(TriView::Container::CENTER, + base::MakeUnique<views::FillLayout>()); + tri_view->SetContainerLayout(TriView::Container::END, + base::MakeUnique<views::FillLayout>()); + + return tri_view; +} + +views::Label* TrayPopupUtils::CreateDefaultLabel() { + views::Label* label = new views::Label(); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label->SetBorder( + views::CreateEmptyBorder(0, 0, 0, kTrayPopupLabelRightPadding)); + // Frequently the label will paint to a layer that's non-opaque, so subpixel + // rendering won't work unless we explicitly set a background. See + // crbug.com/686363 + label->set_background( + views::Background::CreateSolidBackground(kBackgroundColor)); + label->SetBackgroundColor(kBackgroundColor); + return label; +} + +views::ImageView* TrayPopupUtils::CreateMainImageView() { + return new FixedSizedImageView(kTrayPopupItemMinStartWidth, + kTrayPopupItemMinHeight); +} + +views::ImageView* TrayPopupUtils::CreateMoreImageView() { + views::ImageView* image = + new FixedSizedImageView(kMenuIconSize, kMenuIconSize); + image->EnableCanvasFlippingForRTLUI(true); + image->SetImage( + gfx::CreateVectorIcon(kSystemMenuArrowRightIcon, kMenuIconColor)); + return image; +} + +views::Slider* TrayPopupUtils::CreateSlider(views::SliderListener* listener) { + views::Slider* slider = new views::Slider(listener); + slider->SetBorder(views::CreateEmptyBorder(gfx::Insets(0, 16))); + return slider; +} + +views::ToggleButton* TrayPopupUtils::CreateToggleButton( + views::ButtonListener* listener, + int accessible_name_id) { + views::ToggleButton* toggle = new views::ToggleButton(listener); + const gfx::Size toggle_size(toggle->GetPreferredSize()); + const int vertical_padding = (kMenuButtonSize - toggle_size.height()) / 2; + const int horizontal_padding = + (kTrayToggleButtonWidth - toggle_size.width()) / 2; + toggle->SetBorder(views::CreateEmptyBorder( + gfx::Insets(vertical_padding, horizontal_padding))); + toggle->SetFocusPainter(CreateFocusPainter()); + toggle->SetAccessibleName(l10n_util::GetStringUTF16(accessible_name_id)); + return toggle; +} + +std::unique_ptr<views::Painter> TrayPopupUtils::CreateFocusPainter() { + return views::Painter::CreateSolidFocusPainter( + kFocusBorderColor, kFocusBorderThickness, gfx::InsetsF()); +} + +void TrayPopupUtils::ConfigureTrayPopupButton(views::CustomButton* button) { + // All buttons that call into here want this focus painter, but + // SetFocusPainter is defined separately on derived classes and isn't part of + // CustomButton. TODO(estade): Address this. + // button->SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); + button->SetFocusForPlatform(); + + button->SetInkDropMode(views::InkDropHostView::InkDropMode::ON); + button->set_has_ink_drop_action_on_click(true); + button->set_ink_drop_base_color(kTrayPopupInkDropBaseColor); + button->set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); +} + +void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) { + view->set_id(VIEW_ID_STICKY_HEADER); + view->set_background( + views::Background::CreateSolidBackground(kBackgroundColor)); + view->SetBorder( + views::CreateEmptyBorder(gfx::Insets(kMenuSeparatorVerticalPadding, 0))); + view->SetPaintToLayer(); + view->layer()->SetFillsBoundsOpaquely(false); +} + +void TrayPopupUtils::ShowStickyHeaderSeparator(views::View* view, + bool show_separator) { + if (show_separator) { + view->SetBorder(views::CreatePaddedBorder( + views::CreateSolidSidedBorder(0, 0, kSeparatorWidth, 0, + kMenuSeparatorColor), + gfx::Insets(kMenuSeparatorVerticalPadding, 0, + kMenuSeparatorVerticalPadding - kSeparatorWidth, 0))); + } else { + view->SetBorder(views::CreateEmptyBorder( + gfx::Insets(kMenuSeparatorVerticalPadding, 0))); + } + view->SchedulePaint(); +} + +void TrayPopupUtils::ConfigureContainer(TriView::Container container, + views::View* container_view) { + container_view->SetLayoutManager( + CreateDefaultLayoutManager(container).release()); +} + +views::LabelButton* TrayPopupUtils::CreateTrayPopupBorderlessButton( + views::ButtonListener* listener, + const base::string16& text) { + return new BorderlessLabelButton(listener, text); +} + +views::LabelButton* TrayPopupUtils::CreateTrayPopupButton( + views::ButtonListener* listener, + const base::string16& text) { + auto* button = views::MdTextButton::Create(listener, text); + button->SetProminent(true); + return button; +} + +views::Separator* TrayPopupUtils::CreateVerticalSeparator() { + views::Separator* separator = new views::Separator(); + separator->SetPreferredHeight(24); + separator->SetColor(kMenuSeparatorColor); + return separator; +} + +std::unique_ptr<views::InkDrop> TrayPopupUtils::CreateInkDrop( + TrayPopupInkDropStyle ink_drop_style, + views::InkDropHostView* host) { + std::unique_ptr<views::InkDropImpl> ink_drop = + base::MakeUnique<views::InkDropImpl>(host, host->size()); + ink_drop->SetAutoHighlightMode( + views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE); + ink_drop->SetShowHighlightOnHover(false); + + return std::move(ink_drop); +} + +std::unique_ptr<views::InkDropRipple> TrayPopupUtils::CreateInkDropRipple( + TrayPopupInkDropStyle ink_drop_style, + const views::View* host, + const gfx::Point& center_point, + SkColor color) { + return base::MakeUnique<views::FloodFillInkDropRipple>( + host->size(), TrayPopupUtils::GetInkDropInsets(ink_drop_style), + center_point, color, kTrayPopupInkDropRippleOpacity); +} + +std::unique_ptr<views::InkDropHighlight> TrayPopupUtils::CreateInkDropHighlight( + TrayPopupInkDropStyle ink_drop_style, + const views::View* host, + SkColor color) { + const gfx::Rect bounds = + TrayPopupUtils::GetInkDropBounds(ink_drop_style, host); + std::unique_ptr<views::InkDropHighlight> highlight( + new views::InkDropHighlight(bounds.size(), 0, + gfx::PointF(bounds.CenterPoint()), color)); + highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity); + return highlight; +} + +std::unique_ptr<views::InkDropMask> TrayPopupUtils::CreateInkDropMask( + TrayPopupInkDropStyle ink_drop_style, + const views::View* host) { + if (ink_drop_style == TrayPopupInkDropStyle::FILL_BOUNDS) + return nullptr; + + const gfx::Size layer_size = host->size(); + switch (ink_drop_style) { + case TrayPopupInkDropStyle::HOST_CENTERED: { + const gfx::Rect mask_bounds = + GetInkDropBounds(TrayPopupInkDropStyle::HOST_CENTERED, host); + const int radius = + std::min(mask_bounds.width(), mask_bounds.height()) / 2; + return base::MakeUnique<views::CircleInkDropMask>( + layer_size, mask_bounds.CenterPoint(), radius); + } + case TrayPopupInkDropStyle::INSET_BOUNDS: { + const gfx::Insets mask_insets = + GetInkDropInsets(TrayPopupInkDropStyle::INSET_BOUNDS); + return base::MakeUnique<views::RoundRectInkDropMask>( + layer_size, mask_insets, kTrayPopupInkDropCornerRadius); + } + case TrayPopupInkDropStyle::FILL_BOUNDS: + // Handled by quick return above. + break; + } + // Required by some compilers. + NOTREACHED(); + return nullptr; +} + +gfx::Insets TrayPopupUtils::GetInkDropInsets( + TrayPopupInkDropStyle ink_drop_style) { + gfx::Insets insets; + if (ink_drop_style == TrayPopupInkDropStyle::HOST_CENTERED || + ink_drop_style == TrayPopupInkDropStyle::INSET_BOUNDS) { + insets.Set(kTrayPopupInkDropInset, kTrayPopupInkDropInset, + kTrayPopupInkDropInset, kTrayPopupInkDropInset); + } + return insets; +} + +gfx::Rect TrayPopupUtils::GetInkDropBounds(TrayPopupInkDropStyle ink_drop_style, + const views::View* host) { + gfx::Rect bounds = host->GetLocalBounds(); + bounds.Inset(GetInkDropInsets(ink_drop_style)); + return bounds; +} + +views::Separator* TrayPopupUtils::CreateListItemSeparator(bool left_inset) { + views::Separator* separator = new views::Separator(); + separator->SetColor(kMenuSeparatorColor); + separator->SetBorder(views::CreateEmptyBorder( + kMenuSeparatorVerticalPadding - views::Separator::kThickness, + left_inset + ? kMenuExtraMarginFromLeftEdge + kMenuButtonSize + + kTrayPopupLabelHorizontalPadding + : 0, + kMenuSeparatorVerticalPadding, 0)); + return separator; +} + +views::Separator* TrayPopupUtils::CreateListSubHeaderSeparator() { + views::Separator* separator = new views::Separator(); + separator->SetColor(kMenuSeparatorColor); + separator->SetBorder(views::CreateEmptyBorder( + kMenuSeparatorVerticalPadding - views::Separator::kThickness, 0, 0, 0)); + return separator; +} + +bool TrayPopupUtils::CanOpenWebUISettings(LoginStatus status) { + // TODO(tdanderson): Consider moving this into WmShell, or introduce a + // CanShowSettings() method in each delegate type that has a + // ShowSettings() method. + return status != LoginStatus::NOT_LOGGED_IN && + status != LoginStatus::LOCKED && + !WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_popup_utils.h b/ash/common/system/tray/tray_popup_utils.h new file mode 100644 index 0000000..ecec2227 --- /dev/null +++ b/ash/common/system/tray/tray_popup_utils.h
@@ -0,0 +1,221 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_UTILS_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_UTILS_H_ + +#include <memory> + +#include "ash/common/login_status.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_ink_drop_style.h" +#include "ash/common/system/tray/tri_view.h" +#include "base/strings/string16.h" + +namespace views { +class ButtonListener; +class CustomButton; +class ImageView; +class InkDrop; +class InkDropRipple; +class InkDropHighlight; +class InkDropHostView; +class InkDropMask; +class Label; +class LabelButton; +class Painter; +class Separator; +class Slider; +class SliderListener; +class ToggleButton; +} // namespace views + +namespace ash { + +// Factory/utility functions used by the system menu. +class TrayPopupUtils { + public: + // Creates a default container view to be used by system menu rows that are + // either a single targetable area or not targetable at all. The caller takes + // over ownership of the created view. + // + // The returned view consists of 3 regions: START, CENTER, and END. Any child + // Views added to the START and END containers will be added horizontally and + // any Views added to the CENTER container will be added vertically. + // + // The START and END containers have a fixed minimum width but can grow into + // the CENTER container if space is required and available. + // + // The CENTER container has a flexible width. + static TriView* CreateDefaultRowView(); + + // Creates a container view to be used by system menu sub-section header rows. + // The caller takes over ownership of the created view. + // + // The returned view consists of 2 regions: CENTER, and END having the same + // properties as when using |CreateMultiTargetRowView|. The START container is + // hidden. + // The END container has a fixed minimum width but can grow into the CENTER + // container if space is required and available. The CENTER container has a + // flexible width. + static TriView* CreateSubHeaderRowView(); + + // Creates a container view to be used by system menu rows that want to embed + // a targetable area within one (or more) of the containers OR by any row + // that requires a non-default layout within the container views. The returned + // view will have the following configurations: + // - default minimum row height + // - default minimum width for the START and END containers + // - default left and right insets + // - default container flex values + // - Each container view will have a FillLayout installed on it + // + // The caller takes over ownership of the created view. + // + // The START and END containers have a fixed minimum width but can grow into + // the CENTER container if space is required and available. The CENTER + // container has a flexible width. + // + // Clients can use ConfigureContainer() to configure their own container views + // before adding them to the returned TriView. + static TriView* CreateMultiTargetRowView(); + + // Returns a label that has been configured for system menu layout. This + // should be used by all rows that require a label, i.e. both default and + // detailed rows should use this. + // + // TODO(bruthig): Update all system menu rows to use this. + static views::Label* CreateDefaultLabel(); + + // Returns an image view to be used in the main image region of a system menu + // row. This should be used by all rows that have a main image, i.e. both + // default and detailed rows should use this. + // + // TODO(bruthig): Update all system menu rows to use this. + static views::ImageView* CreateMainImageView(); + + // Returns an image view to be used in the 'more' region of default rows. This + // is used for all 'more' images as well as other images that appear in this + // region, e.g. audio output icon. + // + // TODO(bruthig): Update all default rows to use this. + static views::ImageView* CreateMoreImageView(); + + // Returns a slider configured for proper layout within a TriView container + // with a FillLayout. + static views::Slider* CreateSlider(views::SliderListener* listener); + + // Returns a ToggleButton that has been configured for system menu layout. + static views::ToggleButton* CreateToggleButton( + views::ButtonListener* listener, + int accessible_name_id); + + // Creates a default focus painter used for most things in tray popups. + static std::unique_ptr<views::Painter> CreateFocusPainter(); + + // Common setup for various buttons in the system menu. + static void ConfigureTrayPopupButton(views::CustomButton* button); + + // Sets up |view| to be a sticky header in a tray detail scroll view. + static void ConfigureAsStickyHeader(views::View* view); + + // Configures a |view| to have a visible separator below. + static void ShowStickyHeaderSeparator(views::View* view, bool show_separator); + + // Configures |container_view| just like CreateDefaultRowView() would + // configure |container| on its returned TriView. To be used when mutliple + // targetable areas are required within a single row. + static void ConfigureContainer(TriView::Container container, + views::View* container_view); + + // Creates a button for use in the system menu that only has a visible border + // when being hovered/clicked. Caller assumes ownership. + static views::LabelButton* CreateTrayPopupBorderlessButton( + views::ButtonListener* listener, + const base::string16& text); + + // Creates a button for use in the system menu. For MD, this is a prominent + // text + // button. For non-MD, this does the same thing as the above. Caller assumes + // ownership. + static views::LabelButton* CreateTrayPopupButton( + views::ButtonListener* listener, + const base::string16& text); + + // Creates and returns a vertical separator to be used between two items in a + // material design system menu row. The caller assumes ownership of the + // returned separator. + static views::Separator* CreateVerticalSeparator(); + + // Creates in InkDrop instance for |host| according to the |ink_drop_style|. + // All styles are configured to show the highlight when the ripple is visible. + // + // All targetable views in the system menu should delegate + // InkDropHost::CreateInkDrop() calls here. + static std::unique_ptr<views::InkDrop> CreateInkDrop( + TrayPopupInkDropStyle ink_drop_style, + views::InkDropHostView* host); + + // Creates an InkDropRipple instance for |host| according to the + // |ink_drop_style|. The ripple will be centered on |center_point|. + // + // All targetable views in the system menu should delegate + // InkDropHost::CreateInkDropRipple() calls here. + static std::unique_ptr<views::InkDropRipple> CreateInkDropRipple( + TrayPopupInkDropStyle ink_drop_style, + const views::View* host, + const gfx::Point& center_point, + SkColor color = kTrayPopupInkDropBaseColor); + + // Creates in InkDropHighlight instance for |host| according to the + // |ink_drop_style|. + // + // All targetable views in the system menu should delegate + // InkDropHost::CreateInkDropHighlight() calls here. + static std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight( + TrayPopupInkDropStyle ink_drop_style, + const views::View* host, + SkColor color = kTrayPopupInkDropBaseColor); + + // Creates in InkDropMask instance for |host| according to the + // |ink_drop_style|. May return null. + // + // All targetable views in the system menu should delegate + // InkDropHost::CreateInkDropMask() calls here. + static std::unique_ptr<views::InkDropMask> CreateInkDropMask( + TrayPopupInkDropStyle ink_drop_style, + const views::View* host); + + // Creates and returns a horizontal separator line to be drawn between rows + // in a detailed view. If |left_inset| is true, then the separator is inset on + // the left by the width normally occupied by an icon. Caller assumes + // ownership of the returned separator. + static views::Separator* CreateListItemSeparator(bool left_inset); + + // Creates and returns a horizontal separator line to be drawn between rows + // in a detailed view above the sub-header rows. Caller assumes ownership of + // the returned separator. + static views::Separator* CreateListSubHeaderSeparator(); + + // Returns true if it is possible to open WebUI settings in a browser window, + // i.e., the user is logged in, not on the lock screen, and not in a secondary + // account flow. + static bool CanOpenWebUISettings(LoginStatus status); + + private: + // Returns the effective ink drop insets for |host| according to the + // |ink_drop_style|. + static gfx::Insets GetInkDropInsets(TrayPopupInkDropStyle ink_drop_style); + + // Returns the effective ink drop bounds for |host| according to the + // |ink_drop_style|. + static gfx::Rect GetInkDropBounds(TrayPopupInkDropStyle ink_drop_style, + const views::View* host); + + DISALLOW_IMPLICIT_CONSTRUCTORS(TrayPopupUtils); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_POPUP_UTILS_H_
diff --git a/ash/common/system/tray/tray_utils.cc b/ash/common/system/tray/tray_utils.cc new file mode 100644 index 0000000..0276fd3 --- /dev/null +++ b/ash/common/system/tray/tray_utils.cc
@@ -0,0 +1,74 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tray_utils.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/views/border.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/button/md_text_button.h" +#include "ui/views/controls/label.h" + +namespace ash { + +void SetupLabelForTray(views::Label* label) { + if (MaterialDesignController::IsShelfMaterial()) { + // The text is drawn on an transparent bg, so we must disable subpixel + // rendering. + label->SetSubpixelRenderingEnabled(false); + label->SetFontList(gfx::FontList().Derive(2, gfx::Font::NORMAL, + gfx::Font::Weight::MEDIUM)); + } else { + label->SetFontList( + gfx::FontList().Derive(1, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)); + label->SetShadows(gfx::ShadowValues( + 1, + gfx::ShadowValue(gfx::Vector2d(0, 1), 0, SkColorSetARGB(64, 0, 0, 0)))); + label->SetAutoColorReadabilityEnabled(false); + label->SetEnabledColor(SK_ColorWHITE); + label->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255)); + } +} + +void SetTrayImageItemBorder(views::View* tray_view, ShelfAlignment alignment) { + if (MaterialDesignController::IsShelfMaterial()) + return; + + if (IsHorizontalAlignment(alignment)) { + tray_view->SetBorder( + views::CreateEmptyBorder(gfx::Insets(0, kTrayImageItemPadding))); + } else { + tray_view->SetBorder(views::CreateEmptyBorder(gfx::Insets( + kTrayImageItemPadding, + kTrayImageItemHorizontalPaddingVerticalAlignment))); + } +} + +void SetTrayLabelItemBorder(TrayItemView* tray_view, ShelfAlignment alignment) { + if (MaterialDesignController::IsShelfMaterial()) + return; + + if (IsHorizontalAlignment(alignment)) { + tray_view->SetBorder(views::CreateEmptyBorder( + 0, kTrayLabelItemHorizontalPaddingBottomAlignment, 0, + kTrayLabelItemHorizontalPaddingBottomAlignment)); + } else { + // Center the label for vertical launcher alignment. + int horizontal_padding = + std::max(0, (tray_view->GetPreferredSize().width() - + tray_view->label()->GetPreferredSize().width()) / + 2); + tray_view->SetBorder(views::CreateEmptyBorder( + kTrayLabelItemVerticalPaddingVerticalAlignment, horizontal_padding, + kTrayLabelItemVerticalPaddingVerticalAlignment, horizontal_padding)); + } +} + +} // namespace ash
diff --git a/ash/common/system/tray/tray_utils.h b/ash/common/system/tray/tray_utils.h new file mode 100644 index 0000000..8c0c136 --- /dev/null +++ b/ash/common/system/tray/tray_utils.h
@@ -0,0 +1,35 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRAY_UTILS_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRAY_UTILS_H_ + +#include <vector> + +#include "ash/public/cpp/shelf_types.h" +#include "base/strings/string16.h" + +namespace views { +class Label; +class View; +} + +namespace ash { + +class TrayItemView; + +// Sets up a Label properly for the tray (sets color, font etc.). +void SetupLabelForTray(views::Label* label); + +// TODO(jennyz): refactor these two functions to SystemTrayItem. +// Sets the empty border of an image tray item for adjusting the space +// around it. +void SetTrayImageItemBorder(views::View* tray_view, ShelfAlignment alignment); +// Sets the empty border around a label tray item for adjusting the space +// around it. +void SetTrayLabelItemBorder(TrayItemView* tray_view, ShelfAlignment alignment); + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRAY_UTILS_H_
diff --git a/ash/common/system/tray/tri_view.cc b/ash/common/system/tray/tri_view.cc new file mode 100644 index 0000000..2f0f55b9 --- /dev/null +++ b/ash/common/system/tray/tri_view.cc
@@ -0,0 +1,179 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray/tri_view.h" + +#include "ash/common/system/tray/size_range_layout.h" +#include "base/logging.h" +#include "ui/views/border.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/layout/layout_manager.h" + +namespace ash { +namespace { + +// Converts TriView::Orientation values to views::BoxLayout::Orientation values. +views::BoxLayout::Orientation GetOrientation(TriView::Orientation orientation) { + switch (orientation) { + case TriView::Orientation::HORIZONTAL: + return views::BoxLayout::kHorizontal; + case TriView::Orientation::VERTICAL: + return views::BoxLayout::kVertical; + } + // Required for some compilers. + NOTREACHED(); + return views::BoxLayout::kHorizontal; +} + +// A View that will perform a layout if a child view's preferred size changes. +class RelayoutView : public views::View { + public: + RelayoutView() {} + + // views::View: + void ChildPreferredSizeChanged(View* child) override { Layout(); } + + private: + DISALLOW_COPY_AND_ASSIGN(RelayoutView); +}; + +} // namespace + +TriView::TriView() : TriView(0) {} + +TriView::TriView(int padding_between_containers) + : TriView(Orientation::HORIZONTAL, padding_between_containers) {} + +TriView::TriView(Orientation orientation) : TriView(orientation, 0) {} + +TriView::TriView(Orientation orientation, int padding_between_containers) + : box_layout_(new views::BoxLayout(GetOrientation(orientation), + 0, + 0, + padding_between_containers)), + start_container_layout_manager_(new SizeRangeLayout), + center_container_layout_manager_(new SizeRangeLayout), + end_container_layout_manager_(new SizeRangeLayout) { + AddChildView(new RelayoutView); + AddChildView(new RelayoutView); + AddChildView(new RelayoutView); + + GetContainer(Container::START) + ->SetLayoutManager(GetLayoutManager(Container::START)); + GetContainer(Container::CENTER) + ->SetLayoutManager(GetLayoutManager(Container::CENTER)); + GetContainer(Container::END) + ->SetLayoutManager(GetLayoutManager(Container::END)); + + box_layout_->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); + SetLayoutManager(box_layout_); + + enable_hierarchy_changed_dcheck_ = true; +} + +TriView::~TriView() { + enable_hierarchy_changed_dcheck_ = false; +} + +void TriView::SetMinHeight(int height) { + gfx::Size min_size; + + min_size = GetMinSize(TriView::Container::START); + min_size.set_height(height); + SetMinSize(TriView::Container::START, min_size); + + min_size = GetMinSize(TriView::Container::CENTER); + min_size.set_height(height); + SetMinSize(TriView::Container::CENTER, min_size); + + min_size = GetMinSize(TriView::Container::END); + min_size.set_height(height); + SetMinSize(TriView::Container::END, min_size); +} + +void TriView::SetMinSize(Container container, const gfx::Size& size) { + GetLayoutManager(container)->SetMinSize(size); +} + +gfx::Size TriView::GetMinSize(Container container) { + return GetLayoutManager(container)->min_size(); +} + +void TriView::SetMaxSize(Container container, const gfx::Size& size) { + GetLayoutManager(container)->SetMaxSize(size); +} + +void TriView::AddView(Container container, views::View* view) { + GetContainer(container)->AddChildView(view); +} + +void TriView::RemoveAllChildren(Container container, bool delete_children) { + GetContainer(container)->RemoveAllChildViews(delete_children); +} + +void TriView::SetInsets(const gfx::Insets& insets) { + box_layout_->set_inside_border_insets(insets); +} + +void TriView::SetContainerBorder(Container container, + std::unique_ptr<views::Border> border) { + GetContainer(container)->SetBorder(std::move(border)); +} + +void TriView::SetContainerVisible(Container container, bool visible) { + GetContainer(container)->SetVisible(visible); +} + +void TriView::SetFlexForContainer(Container container, int flex) { + box_layout_->SetFlexForView(GetContainer(container), flex); +} + +void TriView::SetContainerLayout( + Container container, + std::unique_ptr<views::LayoutManager> layout_manager) { + GetLayoutManager(container)->SetLayoutManager(std::move(layout_manager)); +} + +void TriView::ViewHierarchyChanged( + const views::View::ViewHierarchyChangedDetails& details) { + views::View::ViewHierarchyChanged(details); + if (!enable_hierarchy_changed_dcheck_) + return; + + if (details.parent == this) { + if (details.is_add) { + DCHECK(false) + << "Child views should not be added directly. They should be added " + "using TriView::AddView()."; + } else { + DCHECK(false) << "Container views should not be removed."; + } + } +} + +const char* TriView::GetClassName() const { + return "TriView"; +} + +views::View* TriView::GetContainer(Container container) { + return child_at(static_cast<int>(container)); +} + +SizeRangeLayout* TriView::GetLayoutManager(Container container) { + switch (container) { + case Container::START: + return start_container_layout_manager_; + case Container::CENTER: + return center_container_layout_manager_; + case Container::END: + return end_container_layout_manager_; + } + // Required for some compilers. + NOTREACHED(); + return nullptr; +} + +} // namespace ash
diff --git a/ash/common/system/tray/tri_view.h b/ash/common/system/tray/tri_view.h new file mode 100644 index 0000000..5774467 --- /dev/null +++ b/ash/common/system/tray/tri_view.h
@@ -0,0 +1,157 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_TRI_VIEW_H_ +#define ASH_COMMON_SYSTEM_TRAY_TRI_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/size.h" +#include "ui/views/view.h" + +namespace views { +class Border; +class BoxLayout; +class LayoutManager; +} // namespace views + +namespace ash { +class SizeRangeLayout; + +// A View which has 3 child containers (START, CENTER, END) which can be +// arranged vertically or horizontally. The child containers can have minimum +// and/or maximum preferred size defined as well as a flex weight that is used +// to distribute excess space across the main axis, i.e. flexible width for the +// horizontal orientation. By default all the containers have a flex weight of +// 0, meaning no flexibility, and no minimum or maximum size. +// +// Child views should not be added to |this| directly via View::AddChildView() +// or View::AddChildViewAt() and will fail a DCHECK() if attempted. +// +// Views added to the containers are laid out as per the LayoutManager that has +// been installed on that container. By default a BoxLayout manager is installed +// on each container with the same orientation as |this| has been created with. +// The default BoxLayout will use a center alignment for both the main axis and +// cross axis alignment. +class ASH_EXPORT TriView : public views::View { + public: + enum class Orientation { + HORIZONTAL, + VERTICAL, + }; + + // The different containers that child Views can be added to. + enum class Container { START = 0, CENTER = 1, END = 2 }; + + // Constructs a layout with horizontal orientation and 0 padding between + // containers. + TriView(); + + // Creates |this| with a Horizontal orientation and the specified padding + // between containers. + // + // TODO(bruthig): The |padding_between_containers| can only be set on + // BoxLayouts during construction. Investigate whether this can be a mutable + // property of BoxLayouts and if so consider dropping it as a constructor + // parameter here. + explicit TriView(int padding_between_containers); + + // Creates |this| with the specified orientation and 0 padding between + // containers. + explicit TriView(Orientation orientation); + + // Creates this with the specified |orientation| and + // |padding_between_containers|. + TriView(Orientation orientation, int padding_between_containers); + + ~TriView() override; + + // Set the minimum height for all containers to |height|. + void SetMinHeight(int height); + + // Set the minimum size for the given |container|. + void SetMinSize(Container container, const gfx::Size& size); + + // Get the minimum size for the given |container|. + gfx::Size GetMinSize(Container container); + + // Set the maximum size for the given |container|. + void SetMaxSize(Container container, const gfx::Size& size); + + // Adds the child |view| to the specified |container|. + void AddView(Container container, views::View* view); + + // Removes all the children from the specified |container|. If + // |delete_children| is true, the views are deleted, unless marked as not + // parent owned. + void RemoveAllChildren(Container container, bool delete_children); + + // During layout the |insets| are applied to the host views entire space + // before allocating the remaining space to the container views. + void SetInsets(const gfx::Insets& insets); + + // Sets the border for the given |container|. + void SetContainerBorder(Container container, + std::unique_ptr<views::Border> border); + + // Sets whether the |container| is visible. During a layout the space will be + // allocated to the visible containers only. i.e. non-visible containers will + // not be allocated any space. + void SetContainerVisible(Container container, bool visible); + + // Sets the flex weight for the given |container|. Using the preferred size as + // the basis, free space along the main axis is distributed to views in the + // ratio of their flex weights. Similarly, if the views will overflow the + // parent, space is subtracted in these ratios. + // + // A flex of 0 means this view is not resized. Flex values must not be + // negative. + // + // Note that non-zero flex values will take precedence over size constraints. + // i.e. even if |container| has a max size set the space allocated during + // layout may be larger if |flex| > 0 and similar for min size constraints. + void SetFlexForContainer(Container container, int flex); + + // Sets the |layout_manager| used by the given |container|. + void SetContainerLayout(Container container, + std::unique_ptr<views::LayoutManager> layout_manager); + + protected: + // View: + void ViewHierarchyChanged( + const views::View::ViewHierarchyChangedDetails& details) override; + const char* GetClassName() const override; + + private: + friend class TriViewTest; + + // Returns the View for the given |container|. + views::View* GetContainer(Container container); + + // Returns the layout manager for the given |container|. + SizeRangeLayout* GetLayoutManager(Container container); + + // Type spcific layout manager installed on |this|. Responsible for laying out + // the container Views. + views::BoxLayout* box_layout_; + + SizeRangeLayout* start_container_layout_manager_; + SizeRangeLayout* center_container_layout_manager_; + SizeRangeLayout* end_container_layout_manager_; + + // In order to detect direct manipulation of child views the + // ViewHierarchyChanged() event override fails on a DCHECK. However, we need + // to manipulate the child views during construction/destruction so this flag + // is used to disable the DCHECK during construction/destruction. + bool enable_hierarchy_changed_dcheck_ = false; + + DISALLOW_COPY_AND_ASSIGN(TriView); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_TRI_VIEW_H_
diff --git a/ash/common/system/tray/tri_view_unittest.cc b/ash/common/system/tray/tri_view_unittest.cc new file mode 100644 index 0000000..6e2885fd --- /dev/null +++ b/ash/common/system/tray/tri_view_unittest.cc
@@ -0,0 +1,380 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "ash/common/system/tray/tri_view.h" +#include "base/memory/ptr_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/test/test_layout_manager.h" +#include "ui/views/test/test_views.h" +#include "ui/views/view.h" + +namespace ash { +namespace { + +// Returns a layout manager that will size views according to their preferred +// size. +std::unique_ptr<views::LayoutManager> CreatePreferredSizeLayoutManager() { + auto layout = base::MakeUnique<views::BoxLayout>( + views::BoxLayout::kHorizontal, 0, 0, 0); + layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); + return std::move(layout); +} + +} // namespace + +class TriViewTest : public testing::Test { + public: + TriViewTest(); + + protected: + // Convenience function to get the minimum height of |container|. + int GetMinHeight(TriView::Container container) const; + + // Returns the bounds of |child| in the coordinate space of + // |tri_view_|. + gfx::Rect GetBoundsInHost(const views::View* child) const; + + // Wrapper functions to access the internals of |tri_view_|. + views::View* GetContainer(TriView::Container container) const; + + // The test target. + std::unique_ptr<TriView> tri_view_; + + private: + DISALLOW_COPY_AND_ASSIGN(TriViewTest); +}; + +TriViewTest::TriViewTest() : tri_view_(base::MakeUnique<TriView>()) {} + +int TriViewTest::GetMinHeight(TriView::Container container) const { + return tri_view_->GetMinSize(container).height(); +} + +gfx::Rect TriViewTest::GetBoundsInHost(const views::View* child) const { + gfx::RectF rect_f(child->bounds()); + views::View::ConvertRectToTarget(child, tri_view_.get(), &rect_f); + return ToNearestRect(rect_f); +} + +views::View* TriViewTest::GetContainer(TriView::Container container) const { + return tri_view_->GetContainer(container); +} + +TEST_F(TriViewTest, PaddingBetweenContainers) { + const int kPaddingBetweenContainers = 3; + const int kViewWidth = 10; + const int kViewHeight = 10; + const gfx::Size kViewSize(kViewWidth, kViewHeight); + const int kStartChildExpectedX = 0; + const int kCenterChildExpectedX = + kStartChildExpectedX + kViewWidth + kPaddingBetweenContainers; + const int kEndChildExpectedX = + kCenterChildExpectedX + kViewWidth + kPaddingBetweenContainers; + + tri_view_ = base::MakeUnique<TriView>(kPaddingBetweenContainers); + tri_view_->SetBounds(0, 0, 100, 10); + + views::View* start_child = new views::StaticSizedView(kViewSize); + views::View* center_child = new views::StaticSizedView(kViewSize); + views::View* end_child = new views::StaticSizedView(kViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->Layout(); + + EXPECT_EQ(kStartChildExpectedX, GetBoundsInHost(start_child).x()); + EXPECT_EQ(kCenterChildExpectedX, GetBoundsInHost(center_child).x()); + EXPECT_EQ(kEndChildExpectedX, GetBoundsInHost(end_child).x()); +} + +TEST_F(TriViewTest, VerticalOrientation) { + const int kViewWidth = 10; + const int kViewHeight = 10; + const gfx::Size kViewSize(kViewWidth, kViewHeight); + + tri_view_ = base::MakeUnique<TriView>(TriView::Orientation::VERTICAL); + tri_view_->SetBounds(0, 0, 10, 100); + + views::View* start_child = new views::StaticSizedView(kViewSize); + views::View* center_child = new views::StaticSizedView(kViewSize); + views::View* end_child = new views::StaticSizedView(kViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->Layout(); + + EXPECT_EQ(0, GetBoundsInHost(start_child).y()); + EXPECT_EQ(kViewWidth, GetBoundsInHost(center_child).y()); + EXPECT_EQ(kViewWidth * 2, GetBoundsInHost(end_child).y()); +} + +TEST_F(TriViewTest, MainAxisMinSize) { + tri_view_->SetBounds(0, 0, 100, 10); + const gfx::Size kMinSize(15, 10); + tri_view_->SetMinSize(TriView::Container::START, kMinSize); + views::View* child = new views::StaticSizedView(gfx::Size(10, 10)); + tri_view_->AddView(TriView::Container::CENTER, child); + + tri_view_->Layout(); + + EXPECT_EQ(kMinSize.width(), GetBoundsInHost(child).x()); +} + +TEST_F(TriViewTest, MainAxisMaxSize) { + tri_view_->SetBounds(0, 0, 100, 10); + const gfx::Size kMaxSize(10, 10); + + tri_view_->SetMaxSize(TriView::Container::START, kMaxSize); + views::View* start_child = new views::StaticSizedView(gfx::Size(20, 20)); + tri_view_->AddView(TriView::Container::START, start_child); + + views::View* center_child = new views::StaticSizedView(gfx::Size(10, 10)); + tri_view_->AddView(TriView::Container::CENTER, center_child); + + tri_view_->Layout(); + + EXPECT_EQ(kMaxSize.width(), GetBoundsInHost(center_child).x()); +} + +TEST_F(TriViewTest, ViewsAddedToCorrectContainers) { + views::View* start_child = new views::StaticSizedView(); + views::View* center_child = new views::StaticSizedView(); + views::View* end_child = new views::StaticSizedView(); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(start_child)); + EXPECT_EQ(1, GetContainer(TriView::Container::START)->child_count()); + + EXPECT_TRUE(GetContainer(TriView::Container::CENTER)->Contains(center_child)); + EXPECT_EQ(1, GetContainer(TriView::Container::CENTER)->child_count()); + + EXPECT_TRUE(GetContainer(TriView::Container::END)->Contains(end_child)); + EXPECT_EQ(1, GetContainer(TriView::Container::END)->child_count()); +} + +TEST_F(TriViewTest, MultipleViewsAddedToTheSameContainer) { + views::View* child1 = new views::StaticSizedView(); + views::View* child2 = new views::StaticSizedView(); + + tri_view_->AddView(TriView::Container::START, child1); + tri_view_->AddView(TriView::Container::START, child2); + + EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child1)); + EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child2)); +} + +TEST_F(TriViewTest, ViewsRemovedOnRemoveAllChildren) { + views::View* child1 = new views::StaticSizedView(); + views::View* child2 = new views::StaticSizedView(); + + tri_view_->AddView(TriView::Container::START, child1); + tri_view_->AddView(TriView::Container::START, child2); + + EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child1)); + EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child2)); + EXPECT_EQ(2, GetContainer(TriView::Container::START)->child_count()); + + tri_view_->RemoveAllChildren(TriView::Container::START, false); + + EXPECT_FALSE(GetContainer(TriView::Container::START)->Contains(child1)); + EXPECT_FALSE(GetContainer(TriView::Container::START)->Contains(child2)); + EXPECT_EQ(0, GetContainer(TriView::Container::START)->child_count()); + + delete child1; + delete child2; +} + +TEST_F(TriViewTest, Insets) { + const int kInset = 3; + const int kViewHeight = 10; + const int kExpectedViewHeight = kViewHeight - 2 * kInset; + const gfx::Size kStartViewSize(10, kViewHeight); + const gfx::Size kCenterViewSize(100, kViewHeight); + const gfx::Size kEndViewSize(10, kViewHeight); + const int kHostWidth = 100; + + tri_view_->SetBounds(0, 0, kHostWidth, kViewHeight); + tri_view_->SetInsets(gfx::Insets(kInset)); + + views::View* start_child = new views::StaticSizedView(kStartViewSize); + views::View* center_child = new views::StaticSizedView(kCenterViewSize); + views::View* end_child = new views::StaticSizedView(kEndViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); + tri_view_->Layout(); + + EXPECT_EQ( + gfx::Rect(kInset, kInset, kStartViewSize.width(), kExpectedViewHeight), + GetBoundsInHost(start_child)); + EXPECT_EQ(gfx::Rect(kInset + kStartViewSize.width(), kInset, + kHostWidth - kStartViewSize.width() - + kEndViewSize.width() - 2 * kInset, + kExpectedViewHeight), + GetBoundsInHost(center_child)); + EXPECT_EQ(gfx::Rect(kHostWidth - kEndViewSize.width() - kInset, kInset, + kEndViewSize.width(), kExpectedViewHeight), + GetBoundsInHost(end_child)); +} + +TEST_F(TriViewTest, InvisibleContainerDoesntTakeUpSpace) { + const int kViewWidth = 10; + const int kViewHeight = 10; + const gfx::Size kViewSize(kViewWidth, kViewHeight); + + tri_view_->SetBounds(0, 0, 30, 10); + + views::View* start_child = new views::StaticSizedView(kViewSize); + views::View* center_child = new views::StaticSizedView(kViewSize); + views::View* end_child = new views::StaticSizedView(kViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->SetContainerVisible(TriView::Container::START, false); + tri_view_->Layout(); + + EXPECT_EQ(gfx::Rect(0, 0, 0, 0), GetBoundsInHost(start_child)); + EXPECT_EQ(0, GetBoundsInHost(center_child).x()); + EXPECT_EQ(kViewWidth, GetBoundsInHost(end_child).x()); + + tri_view_->SetContainerVisible(TriView::Container::START, true); + tri_view_->Layout(); + + EXPECT_EQ(0, GetBoundsInHost(start_child).x()); + EXPECT_EQ(kViewWidth, GetBoundsInHost(center_child).x()); + EXPECT_EQ(kViewWidth * 2, GetBoundsInHost(end_child).x()); +} + +TEST_F(TriViewTest, NonZeroFlex) { + const int kHostWidth = 100; + const gfx::Size kDefaultViewSize(10, 10); + const gfx::Size kCenterViewSize(100, 10); + const gfx::Size kExpectedCenterViewSize( + kHostWidth - 2 * kDefaultViewSize.width(), 10); + + tri_view_->SetBounds(0, 0, kHostWidth, 10); + + views::View* start_child = new views::StaticSizedView(kDefaultViewSize); + views::View* center_child = new views::StaticSizedView(kCenterViewSize); + views::View* end_child = new views::StaticSizedView(kDefaultViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); + tri_view_->Layout(); + + EXPECT_EQ(kDefaultViewSize, GetBoundsInHost(start_child).size()); + EXPECT_EQ(kExpectedCenterViewSize, GetBoundsInHost(center_child).size()); + EXPECT_EQ(kDefaultViewSize, GetBoundsInHost(end_child).size()); +} + +TEST_F(TriViewTest, NonZeroFlexTakesPrecedenceOverMinSize) { + const int kHostWidth = 25; + const gfx::Size kViewSize(10, 10); + const gfx::Size kMinCenterSize = kViewSize; + const gfx::Size kExpectedCenterSize(kHostWidth - 2 * kViewSize.width(), 10); + + tri_view_->SetBounds(0, 0, kHostWidth, 10); + + views::View* start_child = new views::StaticSizedView(kViewSize); + views::View* center_child = new views::StaticSizedView(kViewSize); + views::View* end_child = new views::StaticSizedView(kViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); + tri_view_->SetMinSize(TriView::Container::CENTER, kMinCenterSize); + tri_view_->Layout(); + + EXPECT_EQ(kViewSize, GetBoundsInHost(start_child).size()); + EXPECT_EQ(kExpectedCenterSize, + GetBoundsInHost(GetContainer(TriView::Container::CENTER)).size()); + EXPECT_EQ(kViewSize, GetBoundsInHost(end_child).size()); +} + +TEST_F(TriViewTest, NonZeroFlexTakesPrecedenceOverMaxSize) { + const int kHostWidth = 100; + const gfx::Size kViewSize(10, 10); + const gfx::Size kMaxCenterSize(20, 10); + const gfx::Size kExpectedCenterSize(kHostWidth - 2 * kViewSize.width(), 10); + + tri_view_->SetBounds(0, 0, kHostWidth, 10); + + views::View* start_child = new views::StaticSizedView(kViewSize); + views::View* center_child = new views::StaticSizedView(kViewSize); + views::View* end_child = new views::StaticSizedView(kViewSize); + + tri_view_->AddView(TriView::Container::START, start_child); + tri_view_->AddView(TriView::Container::CENTER, center_child); + tri_view_->AddView(TriView::Container::END, end_child); + + tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); + tri_view_->SetMaxSize(TriView::Container::CENTER, kMaxCenterSize); + tri_view_->Layout(); + + EXPECT_EQ(kViewSize, GetBoundsInHost(start_child).size()); + EXPECT_EQ(kExpectedCenterSize, + GetBoundsInHost(GetContainer(TriView::Container::CENTER)).size()); + EXPECT_EQ(kViewSize, GetBoundsInHost(end_child).size()); +} + +TEST_F(TriViewTest, ChildViewsPreferredSizeChanged) { + const int kHostWidth = 500; + const gfx::Size kMinStartSize(100, 10); + + tri_view_->SetBounds(0, 0, kHostWidth, 10); + tri_view_->SetMinSize(TriView::Container::START, kMinStartSize); + tri_view_->SetContainerLayout(TriView::Container::START, + CreatePreferredSizeLayoutManager()); + tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); + tri_view_->Layout(); + + views::ProportionallySizedView* child_view = + new views::ProportionallySizedView(1); + tri_view_->AddView(TriView::Container::START, child_view); + + child_view->SetPreferredWidth(1); + EXPECT_EQ(child_view->GetPreferredSize(), child_view->size()); + + child_view->SetPreferredWidth(2); + EXPECT_EQ(child_view->GetPreferredSize(), child_view->size()); +} + +TEST_F(TriViewTest, SetMinHeight) { + const int kMinHeight = 10; + + EXPECT_NE(kMinHeight, GetMinHeight(TriView::Container::START)); + EXPECT_NE(kMinHeight, GetMinHeight(TriView::Container::CENTER)); + EXPECT_NE(kMinHeight, GetMinHeight(TriView::Container::END)); + + tri_view_->SetMinHeight(kMinHeight); + + EXPECT_EQ(kMinHeight, GetMinHeight(TriView::Container::START)); + EXPECT_EQ(kMinHeight, GetMinHeight(TriView::Container::CENTER)); + EXPECT_EQ(kMinHeight, GetMinHeight(TriView::Container::END)); +} + +} // namespace ash
diff --git a/ash/common/system/tray/view_click_listener.h b/ash/common/system/tray/view_click_listener.h new file mode 100644 index 0000000..09f1aed --- /dev/null +++ b/ash/common/system/tray/view_click_listener.h
@@ -0,0 +1,26 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_VIEW_CLICK_LISTENER_H_ +#define ASH_COMMON_SYSTEM_TRAY_VIEW_CLICK_LISTENER_H_ + +#include "ash/ash_export.h" + +namespace views { +class View; +} + +namespace ash { + +class ASH_EXPORT ViewClickListener { + public: + virtual void OnViewClicked(views::View* sender) = 0; + + protected: + virtual ~ViewClickListener() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_VIEW_CLICK_LISTENER_H_
diff --git a/ash/common/system/tray_accessibility.cc b/ash/common/system/tray_accessibility.cc new file mode 100644 index 0000000..1c127cc --- /dev/null +++ b/ash/common/system/tray_accessibility.cc
@@ -0,0 +1,444 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/tray_accessibility.h" + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/accessibility_types.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/hover_highlight_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_item_more.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/views/controls/button/custom_button.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +enum AccessibilityState { + A11Y_NONE = 0, + A11Y_SPOKEN_FEEDBACK = 1 << 0, + A11Y_HIGH_CONTRAST = 1 << 1, + A11Y_SCREEN_MAGNIFIER = 1 << 2, + A11Y_LARGE_CURSOR = 1 << 3, + A11Y_AUTOCLICK = 1 << 4, + A11Y_VIRTUAL_KEYBOARD = 1 << 5, + A11Y_BRAILLE_DISPLAY_CONNECTED = 1 << 6, +}; + +uint32_t GetAccessibilityState() { + AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); + uint32_t state = A11Y_NONE; + if (delegate->IsSpokenFeedbackEnabled()) + state |= A11Y_SPOKEN_FEEDBACK; + if (delegate->IsHighContrastEnabled()) + state |= A11Y_HIGH_CONTRAST; + if (delegate->IsMagnifierEnabled()) + state |= A11Y_SCREEN_MAGNIFIER; + if (delegate->IsLargeCursorEnabled()) + state |= A11Y_LARGE_CURSOR; + if (delegate->IsAutoclickEnabled()) + state |= A11Y_AUTOCLICK; + if (delegate->IsVirtualKeyboardEnabled()) + state |= A11Y_VIRTUAL_KEYBOARD; + if (delegate->IsBrailleDisplayConnected()) + state |= A11Y_BRAILLE_DISPLAY_CONNECTED; + return state; +} + +LoginStatus GetCurrentLoginStatus() { + return WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); +} + +} // namespace + +namespace tray { + +class DefaultAccessibilityView : public TrayItemMore { + public: + explicit DefaultAccessibilityView(SystemTrayItem* owner) + : TrayItemMore(owner) { + base::string16 label = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY); + SetLabel(label); + SetAccessibleName(label); + set_id(test::kAccessibilityTrayItemViewId); + } + + ~DefaultAccessibilityView() override {} + + protected: + // TrayItemMore: + void UpdateStyle() override { + TrayItemMore::UpdateStyle(); + std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); + SetImage(gfx::CreateVectorIcon(kSystemMenuAccessibilityIcon, + style->GetIconColor())); + } + + private: + DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityView); +}; + +//////////////////////////////////////////////////////////////////////////////// +// ash::tray::AccessibilityPopupView + +AccessibilityPopupView::AccessibilityPopupView(uint32_t enabled_state_bits) + : TrayNotificationView(IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK), + label_(CreateLabel(enabled_state_bits)) { + InitView(label_); +} + +views::Label* AccessibilityPopupView::CreateLabel(uint32_t enabled_state_bits) { + DCHECK((enabled_state_bits & + (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED)) != 0); + base::string16 text; + if (enabled_state_bits & A11Y_BRAILLE_DISPLAY_CONNECTED) { + text.append(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED_BUBBLE)); + } + if (enabled_state_bits & A11Y_SPOKEN_FEEDBACK) { + if (!text.empty()) + text.append(base::ASCIIToUTF16(" ")); + text.append(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_BUBBLE)); + } + views::Label* label = new views::Label(text); + label->SetMultiLine(true); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + return label; +} + +//////////////////////////////////////////////////////////////////////////////// +// ash::tray::AccessibilityDetailedView + +AccessibilityDetailedView::AccessibilityDetailedView(SystemTrayItem* owner, + LoginStatus login) + : TrayDetailsView(owner), + spoken_feedback_view_(nullptr), + high_contrast_view_(nullptr), + screen_magnifier_view_(nullptr), + large_cursor_view_(nullptr), + help_view_(nullptr), + settings_view_(nullptr), + autoclick_view_(nullptr), + virtual_keyboard_view_(nullptr), + spoken_feedback_enabled_(false), + high_contrast_enabled_(false), + screen_magnifier_enabled_(false), + large_cursor_enabled_(false), + autoclick_enabled_(false), + virtual_keyboard_enabled_(false), + login_(login) { + Reset(); + AppendAccessibilityList(); + CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE); + Layout(); +} + +void AccessibilityDetailedView::AppendAccessibilityList() { + CreateScrollableList(); + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + + AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); + spoken_feedback_enabled_ = delegate->IsSpokenFeedbackEnabled(); + spoken_feedback_view_ = + AddScrollListItem(bundle.GetLocalizedString( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK), + spoken_feedback_enabled_, spoken_feedback_enabled_, + kSystemMenuAccessibilityChromevoxIcon); + + // Large Cursor item is shown only in Login screen. + if (login_ == LoginStatus::NOT_LOGGED_IN) { + large_cursor_enabled_ = delegate->IsLargeCursorEnabled(); + large_cursor_view_ = + AddScrollListItem(bundle.GetLocalizedString( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR), + large_cursor_enabled_, large_cursor_enabled_, + kSystemMenuAccessibilityLargeCursorIcon); + } + + high_contrast_enabled_ = delegate->IsHighContrastEnabled(); + high_contrast_view_ = AddScrollListItem( + bundle.GetLocalizedString( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE), + high_contrast_enabled_, high_contrast_enabled_, + kSystemMenuAccessibilityContrastIcon); + screen_magnifier_enabled_ = delegate->IsMagnifierEnabled(); + screen_magnifier_view_ = + AddScrollListItem(bundle.GetLocalizedString( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER), + screen_magnifier_enabled_, screen_magnifier_enabled_, + kSystemMenuAccessibilityScreenMagnifierIcon); + + // Don't show autoclick option at login screen. + if (login_ != LoginStatus::NOT_LOGGED_IN) { + autoclick_enabled_ = delegate->IsAutoclickEnabled(); + autoclick_view_ = AddScrollListItem( + bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK), + autoclick_enabled_, autoclick_enabled_, + kSystemMenuAccessibilityAutoClickIcon); + } + + virtual_keyboard_enabled_ = delegate->IsVirtualKeyboardEnabled(); + virtual_keyboard_view_ = + AddScrollListItem(bundle.GetLocalizedString( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD), + virtual_keyboard_enabled_, virtual_keyboard_enabled_, + kSystemMenuKeyboardIcon); +} + +HoverHighlightView* AccessibilityDetailedView::AddScrollListItem( + const base::string16& text, + bool highlight, + bool checked, + const gfx::VectorIcon& icon) { + HoverHighlightView* container = new HoverHighlightView(this); + gfx::ImageSkia image = CreateVectorIcon(icon, kMenuIconColor); + const int padding = (kMenuButtonSize - image.width()) / 2; + container->AddIconAndLabelCustomSize( + image, text, highlight, image.width() + kMenuSeparatorVerticalPadding * 2, + padding, padding); + + if (checked) { + gfx::ImageSkia check_mark = + CreateVectorIcon(gfx::VectorIconId::CHECK_CIRCLE, gfx::kGoogleGreen700); + container->AddRightIcon(check_mark, check_mark.width()); + container->SetRightViewVisible(true); + container->SetAccessiblityState( + HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); + } else { + container->SetAccessiblityState( + HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); + } + + scroll_content()->AddChildView(container); + return container; +} + +void AccessibilityDetailedView::HandleViewClicked(views::View* view) { + AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); + UserMetricsAction user_action; + if (view == spoken_feedback_view_) { + user_action = delegate->IsSpokenFeedbackEnabled() + ? ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK + : ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK; + delegate->ToggleSpokenFeedback(A11Y_NOTIFICATION_NONE); + } else if (view == high_contrast_view_) { + user_action = delegate->IsHighContrastEnabled() + ? ash::UMA_STATUS_AREA_DISABLE_HIGH_CONTRAST + : ash::UMA_STATUS_AREA_ENABLE_HIGH_CONTRAST; + delegate->ToggleHighContrast(); + } else if (view == screen_magnifier_view_) { + user_action = delegate->IsMagnifierEnabled() + ? ash::UMA_STATUS_AREA_DISABLE_MAGNIFIER + : ash::UMA_STATUS_AREA_ENABLE_MAGNIFIER; + delegate->SetMagnifierEnabled(!delegate->IsMagnifierEnabled()); + } else if (large_cursor_view_ && view == large_cursor_view_) { + user_action = delegate->IsLargeCursorEnabled() + ? ash::UMA_STATUS_AREA_DISABLE_LARGE_CURSOR + : ash::UMA_STATUS_AREA_ENABLE_LARGE_CURSOR; + delegate->SetLargeCursorEnabled(!delegate->IsLargeCursorEnabled()); + } else if (autoclick_view_ && view == autoclick_view_) { + user_action = delegate->IsAutoclickEnabled() + ? ash::UMA_STATUS_AREA_DISABLE_AUTO_CLICK + : ash::UMA_STATUS_AREA_ENABLE_AUTO_CLICK; + delegate->SetAutoclickEnabled(!delegate->IsAutoclickEnabled()); + } else if (virtual_keyboard_view_ && view == virtual_keyboard_view_) { + user_action = delegate->IsVirtualKeyboardEnabled() + ? ash::UMA_STATUS_AREA_DISABLE_VIRTUAL_KEYBOARD + : ash::UMA_STATUS_AREA_ENABLE_VIRTUAL_KEYBOARD; + delegate->SetVirtualKeyboardEnabled(!delegate->IsVirtualKeyboardEnabled()); + } else { + return; + } + WmShell::Get()->RecordUserMetricsAction(user_action); +} + +void AccessibilityDetailedView::HandleButtonPressed(views::Button* sender, + const ui::Event& event) { + if (sender == help_view_) + ShowHelp(); + else if (sender == settings_view_) + ShowSettings(); +} + +void AccessibilityDetailedView::CreateExtraTitleRowButtons() { + DCHECK(!help_view_); + DCHECK(!settings_view_); + + tri_view()->SetContainerVisible(TriView::Container::END, true); + + help_view_ = CreateHelpButton(login_); + settings_view_ = + CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS); + tri_view()->AddView(TriView::Container::END, help_view_); + tri_view()->AddView(TriView::Container::END, settings_view_); +} + +void AccessibilityDetailedView::ShowSettings() { + if (TrayPopupUtils::CanOpenWebUISettings(login_)) { + WmShell::Get()->system_tray_controller()->ShowAccessibilitySettings(); + owner()->system_tray()->CloseSystemBubble(); + } +} + +void AccessibilityDetailedView::ShowHelp() { + if (TrayPopupUtils::CanOpenWebUISettings(login_)) { + WmShell::Get()->system_tray_controller()->ShowAccessibilityHelp(); + owner()->system_tray()->CloseSystemBubble(); + } +} + +} // namespace tray + +//////////////////////////////////////////////////////////////////////////////// +// ash::TrayAccessibility + +TrayAccessibility::TrayAccessibility(SystemTray* system_tray) + : TrayImageItem(system_tray, + kSystemTrayAccessibilityIcon, + UMA_ACCESSIBILITY), + default_(NULL), + detailed_popup_(NULL), + detailed_menu_(NULL), + request_popup_view_state_(A11Y_NONE), + tray_icon_visible_(false), + login_(GetCurrentLoginStatus()), + previous_accessibility_state_(GetAccessibilityState()), + show_a11y_menu_on_lock_screen_(true) { + DCHECK(system_tray); + WmShell::Get()->system_tray_notifier()->AddAccessibilityObserver(this); +} + +TrayAccessibility::~TrayAccessibility() { + WmShell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this); +} + +void TrayAccessibility::SetTrayIconVisible(bool visible) { + if (tray_view()) + tray_view()->SetVisible(visible); + tray_icon_visible_ = visible; +} + +tray::AccessibilityDetailedView* TrayAccessibility::CreateDetailedMenu() { + return new tray::AccessibilityDetailedView(this, login_); +} + +bool TrayAccessibility::GetInitialVisibility() { + // Shows accessibility icon if any accessibility feature is enabled. + // Otherwise, doen't show it. + return GetAccessibilityState() != A11Y_NONE; +} + +views::View* TrayAccessibility::CreateDefaultView(LoginStatus status) { + CHECK(default_ == NULL); + + // Shows accessibility menu if: + // - on login screen (not logged in); + // - "Enable accessibility menu" on chrome://settings is checked; + // - or any of accessibility features is enabled + // Otherwise, not shows it. + AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); + if (login_ != LoginStatus::NOT_LOGGED_IN && + !delegate->ShouldShowAccessibilityMenu() && + // On login screen, keeps the initial visibility of the menu. + (status != LoginStatus::LOCKED || !show_a11y_menu_on_lock_screen_)) + return NULL; + + CHECK(default_ == NULL); + default_ = new tray::DefaultAccessibilityView(this); + + return default_; +} + +views::View* TrayAccessibility::CreateDetailedView(LoginStatus status) { + CHECK(detailed_popup_ == NULL); + CHECK(detailed_menu_ == NULL); + + if (request_popup_view_state_) { + detailed_popup_ = + new tray::AccessibilityPopupView(request_popup_view_state_); + request_popup_view_state_ = A11Y_NONE; + return detailed_popup_; + } else { + WmShell::Get()->RecordUserMetricsAction( + ash::UMA_STATUS_AREA_DETAILED_ACCESSABILITY); + detailed_menu_ = CreateDetailedMenu(); + return detailed_menu_; + } +} + +void TrayAccessibility::DestroyDefaultView() { + default_ = NULL; +} + +void TrayAccessibility::DestroyDetailedView() { + detailed_popup_ = NULL; + detailed_menu_ = NULL; +} + +void TrayAccessibility::UpdateAfterLoginStatusChange(LoginStatus status) { + // Stores the a11y feature status on just entering the lock screen. + if (login_ != LoginStatus::LOCKED && status == LoginStatus::LOCKED) + show_a11y_menu_on_lock_screen_ = (GetAccessibilityState() != A11Y_NONE); + + login_ = status; + SetTrayIconVisible(GetInitialVisibility()); +} + +void TrayAccessibility::OnAccessibilityModeChanged( + AccessibilityNotificationVisibility notify) { + SetTrayIconVisible(GetInitialVisibility()); + + uint32_t accessibility_state = GetAccessibilityState(); + // We'll get an extra notification if a braille display is connected when + // spoken feedback wasn't already enabled. This is because the braille + // connection state is already updated when spoken feedback is enabled so + // that the notifications can be consolidated into one. Therefore, we + // return early if there's no change in the state that we keep track of. + if (accessibility_state == previous_accessibility_state_) + return; + // Contains bits for spoken feedback and braille display connected currently + // being enabled. + uint32_t being_enabled = + (accessibility_state & ~previous_accessibility_state_) & + (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED); + if ((notify == A11Y_NOTIFICATION_SHOW) && being_enabled != A11Y_NONE) { + // Shows popup if |notify| is true and the spoken feedback is being enabled. + request_popup_view_state_ = being_enabled; + PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); + } else { + if (detailed_popup_) + detailed_popup_->GetWidget()->Close(); + if (detailed_menu_) + detailed_menu_->GetWidget()->Close(); + } + + previous_accessibility_state_ = accessibility_state; +} + +} // namespace ash
diff --git a/ash/common/system/tray_accessibility.h b/ash/common/system/tray_accessibility.h new file mode 100644 index 0000000..472ab0f9 --- /dev/null +++ b/ash/common/system/tray_accessibility.h
@@ -0,0 +1,151 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_TRAY_ACCESSIBILITY_H_ +#define ASH_COMMON_SYSTEM_TRAY_ACCESSIBILITY_H_ + +#include <stdint.h> + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/shell_observer.h" +#include "ash/common/system/accessibility_observer.h" +#include "ash/common/system/tray/tray_details_view.h" +#include "ash/common/system/tray/tray_image_item.h" +#include "ash/common/system/tray/tray_notification_view.h" +#include "base/macros.h" +#include "ui/gfx/font.h" +#include "ui/views/controls/button/button.h" + +namespace chromeos { +class TrayAccessibilityTest; +} + +namespace gfx { +struct VectorIcon; +} + +namespace views { +class Button; +class CustomButton; +class Label; +class View; +} + +namespace ash { +class HoverHighlightView; +class SystemTrayItem; + +namespace tray { + +class AccessibilityPopupView : public TrayNotificationView { + public: + explicit AccessibilityPopupView(uint32_t enabled_state_bits); + + const views::Label* label_for_test() const { return label_; } + + private: + views::Label* CreateLabel(uint32_t enabled_state_bits); + + views::Label* label_; + + DISALLOW_COPY_AND_ASSIGN(AccessibilityPopupView); +}; + +// Create the detailed view of accessibility tray. +class AccessibilityDetailedView : public TrayDetailsView, + public ShellObserver { + public: + AccessibilityDetailedView(SystemTrayItem* owner, LoginStatus login); + ~AccessibilityDetailedView() override {} + + private: + // TrayDetailsView: + void HandleViewClicked(views::View* view) override; + void HandleButtonPressed(views::Button* sender, + const ui::Event& event) override; + void CreateExtraTitleRowButtons() override; + + // Launches the WebUI settings in a browser and closes the system menu. + void ShowSettings(); + + // Launches the a11y help article in a browser and closes the system menu. + void ShowHelp(); + + // Add the accessibility feature list. + void AppendAccessibilityList(); + + // Helper function to create entries in the detailed accessibility view. + HoverHighlightView* AddScrollListItem(const base::string16& text, + bool highlight, + bool checked, + const gfx::VectorIcon& icon); + + views::View* spoken_feedback_view_; + views::View* high_contrast_view_; + views::View* screen_magnifier_view_; + views::View* large_cursor_view_; + views::CustomButton* help_view_; + views::CustomButton* settings_view_; + views::View* autoclick_view_; + views::View* virtual_keyboard_view_; + + bool spoken_feedback_enabled_; + bool high_contrast_enabled_; + bool screen_magnifier_enabled_; + bool large_cursor_enabled_; + bool autoclick_enabled_; + bool virtual_keyboard_enabled_; + LoginStatus login_; + + friend class chromeos::TrayAccessibilityTest; + DISALLOW_COPY_AND_ASSIGN(AccessibilityDetailedView); +}; + +} // namespace tray + +class TrayAccessibility : public TrayImageItem, public AccessibilityObserver { + public: + explicit TrayAccessibility(SystemTray* system_tray); + ~TrayAccessibility() override; + + private: + void SetTrayIconVisible(bool visible); + tray::AccessibilityDetailedView* CreateDetailedMenu(); + + // Overridden from TrayImageItem. + bool GetInitialVisibility() override; + views::View* CreateDefaultView(LoginStatus status) override; + views::View* CreateDetailedView(LoginStatus status) override; + void DestroyDefaultView() override; + void DestroyDetailedView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + + // Overridden from AccessibilityObserver. + void OnAccessibilityModeChanged( + AccessibilityNotificationVisibility notify) override; + + views::View* default_; + tray::AccessibilityPopupView* detailed_popup_; + tray::AccessibilityDetailedView* detailed_menu_; + + // Bitmap of fvalues from AccessibilityState. Can contain any or + // both of A11Y_SPOKEN_FEEDBACK A11Y_BRAILLE_DISPLAY_CONNECTED. + uint32_t request_popup_view_state_; + + bool tray_icon_visible_; + LoginStatus login_; + + // Bitmap of values from AccessibilityState enum. + uint32_t previous_accessibility_state_; + + // A11y feature status on just entering the lock screen. + bool show_a11y_menu_on_lock_screen_; + + friend class chromeos::TrayAccessibilityTest; + DISALLOW_COPY_AND_ASSIGN(TrayAccessibility); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_TRAY_ACCESSIBILITY_H_
diff --git a/ash/common/system/update/tray_update.cc b/ash/common/system/update/tray_update.cc new file mode 100644 index 0000000..54b7d70 --- /dev/null +++ b/ash/common/system/update/tray_update.cc
@@ -0,0 +1,136 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/update/tray_update.h" + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/wm_shell.h" +#include "ash/public/interfaces/update.mojom.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { +namespace { + +// Returns the color to use for the update icon when the update severity is +// |severity|. If |for_menu| is true, the icon color for the system menu is +// given, otherwise the icon color for the system tray is given. +SkColor IconColorForUpdateSeverity(mojom::UpdateSeverity severity, + bool for_menu) { + const SkColor default_color = for_menu ? kMenuIconColor : kTrayIconColor; + switch (severity) { + case mojom::UpdateSeverity::NONE: + return default_color; + case mojom::UpdateSeverity::LOW: + return for_menu ? gfx::kGoogleGreen700 : kTrayIconColor; + case mojom::UpdateSeverity::ELEVATED: + return for_menu ? gfx::kGoogleYellow700 : gfx::kGoogleYellow300; + case mojom::UpdateSeverity::HIGH: + case mojom::UpdateSeverity::SEVERE: + case mojom::UpdateSeverity::CRITICAL: + return for_menu ? gfx::kGoogleRed700 : gfx::kGoogleRed300; + default: + NOTREACHED(); + break; + } + return default_color; +} + +} // namespace + +// static +bool TrayUpdate::update_required_ = false; +// static +mojom::UpdateSeverity TrayUpdate::severity_ = mojom::UpdateSeverity::NONE; +// static +bool TrayUpdate::factory_reset_required_ = false; + +// The "restart to update" item in the system tray menu. +class TrayUpdate::UpdateView : public ActionableView { + public: + explicit UpdateView(TrayUpdate* owner) + : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS) { + SetLayoutManager(new views::FillLayout); + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view); + views::ImageView* image = TrayPopupUtils::CreateMainImageView(); + image->SetImage(gfx::CreateVectorIcon( + kSystemMenuUpdateIcon, + IconColorForUpdateSeverity(owner->severity_, true))); + tri_view->AddView(TriView::Container::START, image); + + base::string16 label_text = + owner->factory_reset_required_ + ? bundle.GetLocalizedString( + IDS_ASH_STATUS_TRAY_RESTART_AND_POWERWASH_TO_UPDATE) + : bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_UPDATE); + SetAccessibleName(label_text); + auto* label = TrayPopupUtils::CreateDefaultLabel(); + label->SetText(label_text); + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + style.SetupLabel(label); + tri_view->AddView(TriView::Container::CENTER, label); + + SetInkDropMode(InkDropHostView::InkDropMode::ON); + } + + ~UpdateView() override {} + + private: + // Overridden from ActionableView. + bool PerformAction(const ui::Event& event) override { + WmShell::Get()->system_tray_controller()->RequestRestartForUpdate(); + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_OS_UPDATE_DEFAULT_SELECTED); + CloseSystemBubble(); + return true; + } + + DISALLOW_COPY_AND_ASSIGN(UpdateView); +}; + +TrayUpdate::TrayUpdate(SystemTray* system_tray) + : TrayImageItem(system_tray, kSystemTrayUpdateIcon, UMA_UPDATE) {} + +TrayUpdate::~TrayUpdate() {} + +bool TrayUpdate::GetInitialVisibility() { + // If chrome tells ash there is an update available before this item's system + // tray is constructed then show the icon. + return update_required_; +} + +views::View* TrayUpdate::CreateDefaultView(LoginStatus status) { + return update_required_ ? new UpdateView(this) : nullptr; +} + +void TrayUpdate::ShowUpdateIcon(mojom::UpdateSeverity severity, + bool factory_reset_required) { + // Cache update info so we can create the default view when the menu opens. + update_required_ = true; + severity_ = severity; + factory_reset_required_ = factory_reset_required; + + // Show the icon in the tray. + SetIconColor(IconColorForUpdateSeverity(severity_, false)); + tray_view()->SetVisible(true); +} + +} // namespace ash
diff --git a/ash/common/system/update/tray_update.h b/ash/common/system/update/tray_update.h new file mode 100644 index 0000000..3850804b --- /dev/null +++ b/ash/common/system/update/tray_update.h
@@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_UPDATE_TRAY_UPDATE_H_ +#define ASH_COMMON_SYSTEM_UPDATE_TRAY_UPDATE_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/tray_image_item.h" +#include "base/macros.h" + +namespace views { +class View; +} + +namespace ash { + +namespace mojom { +enum class UpdateSeverity; +} + +// The system update tray item. The tray icon stays visible once an update +// notification is received. The icon only disappears after a reboot to apply +// the update. Exported for test. +class ASH_EXPORT TrayUpdate : public TrayImageItem { + public: + explicit TrayUpdate(SystemTray* system_tray); + ~TrayUpdate() override; + + // Shows an icon in the system tray indicating that a software update is + // available. Once shown the icon persists until reboot. |severity| and + // |factory_reset_required| are used to set the icon, color, and tooltip. + void ShowUpdateIcon(mojom::UpdateSeverity severity, + bool factory_reset_required); + + private: + class UpdateView; + + // Overridden from TrayImageItem. + bool GetInitialVisibility() override; + views::View* CreateDefaultView(LoginStatus status) override; + + // If an external monitor is connected then the system tray may be created + // after the update data is sent from chrome, so share the update info between + // all instances. + static bool update_required_; + static mojom::UpdateSeverity severity_; + static bool factory_reset_required_; + + DISALLOW_COPY_AND_ASSIGN(TrayUpdate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_UPDATE_TRAY_UPDATE_H_
diff --git a/ash/common/system/update/tray_update_unittest.cc b/ash/common/system/update/tray_update_unittest.cc new file mode 100644 index 0000000..18007c8 --- /dev/null +++ b/ash/common/system/update/tray_update_unittest.cc
@@ -0,0 +1,33 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/update/tray_update.h" + +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/test/ash_test.h" +#include "ash/common/wm_shell.h" +#include "ash/public/interfaces/update.mojom.h" + +namespace ash { + +using TrayUpdateTest = AshTest; + +// Tests that the update icon becomes visible when an update becomes +// available. +TEST_F(TrayUpdateTest, VisibilityAfterUpdate) { + TrayUpdate* tray_update = GetPrimarySystemTray()->tray_update(); + + // The system starts with no update pending, so the icon isn't visible. + EXPECT_FALSE(tray_update->tray_view()->visible()); + + // Simulate an update. + WmShell::Get()->system_tray_controller()->ShowUpdateIcon( + mojom::UpdateSeverity::LOW, false); + + // Tray item is now visible. + EXPECT_TRUE(tray_update->tray_view()->visible()); +} + +} // namespace ash
diff --git a/ash/common/system/user/button_from_view.cc b/ash/common/system/user/button_from_view.cc new file mode 100644 index 0000000..c39610d --- /dev/null +++ b/ash/common/system/user/button_from_view.cc
@@ -0,0 +1,133 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "ash/common/system/user/button_from_view.h" + +#include "ash/common/ash_constants.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/gfx/canvas.h" +#include "ui/views/animation/flood_fill_ink_drop_ripple.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/animation/ink_drop_highlight.h" +#include "ui/views/animation/ink_drop_impl.h" +#include "ui/views/animation/ink_drop_mask.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { +namespace tray { + +ButtonFromView::ButtonFromView(views::View* content, + views::ButtonListener* listener, + TrayPopupInkDropStyle ink_drop_style) + : CustomButton(listener), + content_(content), + ink_drop_style_(ink_drop_style), + button_hovered_(false), + ink_drop_container_(nullptr) { + set_has_ink_drop_action_on_click(true); + set_notify_enter_exit_on_child(true); + ink_drop_container_ = new views::InkDropContainerView(); + AddChildView(ink_drop_container_); + SetLayoutManager(new views::FillLayout()); + SetInkDropMode(InkDropHostView::InkDropMode::ON); + AddChildView(content_); + // Only make it focusable when we are active/interested in clicks. + if (listener) + SetFocusForPlatform(); +} + +ButtonFromView::~ButtonFromView() {} + +void ButtonFromView::OnMouseEntered(const ui::MouseEvent& event) { + button_hovered_ = true; +} + +void ButtonFromView::OnMouseExited(const ui::MouseEvent& event) { + button_hovered_ = false; +} + +void ButtonFromView::OnPaint(gfx::Canvas* canvas) { + View::OnPaint(canvas); + if (HasFocus()) { + gfx::RectF rect(GetLocalBounds()); + canvas->DrawSolidFocusRect(rect, kFocusBorderColor, kFocusBorderThickness); + } +} + +void ButtonFromView::OnFocus() { + View::OnFocus(); + // Adding focus frame. + SchedulePaint(); +} + +void ButtonFromView::OnBlur() { + View::OnBlur(); + // Removing focus frame. + SchedulePaint(); +} + +void ButtonFromView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + views::CustomButton::GetAccessibleNodeData(node_data); + // If no label has been explicitly set via CustomButton::SetAccessibleName(), + // use the content's label. + if (node_data->GetStringAttribute(ui::AX_ATTR_NAME).empty()) { + ui::AXNodeData content_data; + content_->GetAccessibleNodeData(&content_data); + node_data->SetName(content_data.GetStringAttribute(ui::AX_ATTR_NAME)); + } +} + +void ButtonFromView::Layout() { + CustomButton::Layout(); + if (ink_drop_container_) + ink_drop_container_->SetBoundsRect(GetLocalBounds()); +} + +void ButtonFromView::AddInkDropLayer(ui::Layer* ink_drop_layer) { + // TODO(bruthig): Rework InkDropHostView so that it can still manage the + // creation/application of the mask while allowing subclasses to use an + // InkDropContainer. + ink_drop_mask_ = CreateInkDropMask(); + if (ink_drop_mask_) + ink_drop_layer->SetMaskLayer(ink_drop_mask_->layer()); + ink_drop_container_->AddInkDropLayer(ink_drop_layer); +} + +void ButtonFromView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { + // TODO(bruthig): Rework InkDropHostView so that it can still manage the + // creation/application of the mask while allowing subclasses to use an + // InkDropContainer. + // Layers safely handle destroying a mask layer before the masked layer. + ink_drop_mask_.reset(); + ink_drop_container_->RemoveInkDropLayer(ink_drop_layer); +} + +std::unique_ptr<views::InkDrop> ButtonFromView::CreateInkDrop() { + return TrayPopupUtils::CreateInkDrop(TrayPopupInkDropStyle::INSET_BOUNDS, + this); +} + +std::unique_ptr<views::InkDropRipple> ButtonFromView::CreateInkDropRipple() + const { + return TrayPopupUtils::CreateInkDropRipple( + ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent()); +} + +std::unique_ptr<views::InkDropHighlight> +ButtonFromView::CreateInkDropHighlight() const { + return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this); +} + +std::unique_ptr<views::InkDropMask> ButtonFromView::CreateInkDropMask() const { + return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/user/button_from_view.h b/ash/common/system/user/button_from_view.h new file mode 100644 index 0000000..9a0ec25c --- /dev/null +++ b/ash/common/system/user/button_from_view.h
@@ -0,0 +1,76 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_BUTTON_FROM_VIEW_H_ +#define ASH_COMMON_SYSTEM_USER_BUTTON_FROM_VIEW_H_ + +#include <memory> + +#include "ash/common/system/tray/tray_popup_ink_drop_style.h" +#include "base/macros.h" +#include "ui/views/controls/button/custom_button.h" + +namespace views { +class InkDropContainerView; +} // namespace views + +namespace ash { +namespace tray { + +// This view is used to wrap it's content and transform it into button. +class ButtonFromView : public views::CustomButton { + public: + // The |content| is the content which is shown within the button. The + // |button_listener| will be informed - if provided - when a button was + // pressed. + ButtonFromView(views::View* content, + views::ButtonListener* listener, + TrayPopupInkDropStyle ink_drop_style); + ~ButtonFromView() override; + + // views::View: + void OnMouseEntered(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; + void OnPaint(gfx::Canvas* canvas) override; + void OnFocus() override; + void OnBlur() override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void Layout() override; + + // Check if the item is hovered. + bool is_hovered_for_test() { return button_hovered_; } + + protected: + // views::CustomButton: + void AddInkDropLayer(ui::Layer* ink_drop_layer) override; + void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; + std::unique_ptr<views::InkDrop> CreateInkDrop() override; + std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; + std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() + const override; + std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; + + private: + // Content of button. + views::View* content_; + + // Defines the flavor of ink drop ripple/highlight that should be constructed. + TrayPopupInkDropStyle ink_drop_style_; + + // True if button is hovered. + bool button_hovered_; + + // A separate view is necessary to hold the ink drop layer so that |this| can + // host labels with subpixel anti-aliasing enabled. + views::InkDropContainerView* ink_drop_container_; + + std::unique_ptr<views::InkDropMask> ink_drop_mask_; + + DISALLOW_COPY_AND_ASSIGN(ButtonFromView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_BUTTON_FROM_VIEW_H_
diff --git a/ash/common/system/user/login_status.cc b/ash/common/system/user/login_status.cc new file mode 100644 index 0000000..742bb91 --- /dev/null +++ b/ash/common/system/user/login_status.cc
@@ -0,0 +1,48 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/user/login_status.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/resource/resource_bundle.h" + +namespace ash { +namespace user { + +base::string16 GetLocalizedSignOutStringForStatus(LoginStatus status, + bool multiline) { + int message_id; + switch (status) { + case LoginStatus::GUEST: + message_id = IDS_ASH_STATUS_TRAY_EXIT_GUEST; + break; + case LoginStatus::PUBLIC: + message_id = IDS_ASH_STATUS_TRAY_EXIT_PUBLIC; + break; + default: + message_id = + WmShell::Get()->GetSessionStateDelegate()->NumberOfLoggedInUsers() > 1 + ? IDS_ASH_STATUS_TRAY_SIGN_OUT_ALL + : IDS_ASH_STATUS_TRAY_SIGN_OUT; + break; + } + base::string16 message = + ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id); + // Desirable line breaking points are marked using \n. As the resource + // framework does not evaluate escape sequences, the \n need to be explicitly + // handled. Depending on the value of |multiline|, actual line breaks or + // spaces are substituted. + base::string16 newline = + multiline ? base::ASCIIToUTF16("\n") : base::ASCIIToUTF16(" "); + base::ReplaceSubstringsAfterOffset(&message, 0, base::ASCIIToUTF16("\\n"), + newline); + return message; +} + +} // namespace user +} // namespace ash
diff --git a/ash/common/system/user/login_status.h b/ash/common/system/user/login_status.h new file mode 100644 index 0000000..5170d2fc --- /dev/null +++ b/ash/common/system/user/login_status.h
@@ -0,0 +1,20 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_LOGIN_STATUS_H_ +#define ASH_COMMON_SYSTEM_USER_LOGIN_STATUS_H_ + +#include "ash/common/login_status.h" +#include "base/strings/string16.h" + +namespace ash { +namespace user { + +base::string16 GetLocalizedSignOutStringForStatus(LoginStatus status, + bool multiline); + +} // namespace user +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_LOGIN_STATUS_H_
diff --git a/ash/common/system/user/rounded_image_view.cc b/ash/common/system/user/rounded_image_view.cc new file mode 100644 index 0000000..cef8154 --- /dev/null +++ b/ash/common/system/user/rounded_image_view.cc
@@ -0,0 +1,71 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/user/rounded_image_view.h" + +#include "skia/ext/image_operations.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/skia_util.h" + +namespace ash { +namespace tray { + +RoundedImageView::RoundedImageView(int corner_radius) { + for (int i = 0; i < 4; ++i) + corner_radius_[i] = corner_radius; +} + +RoundedImageView::~RoundedImageView() {} + +void RoundedImageView::SetImage(const gfx::ImageSkia& img, + const gfx::Size& size) { + image_ = img; + image_size_ = size; + + // Try to get the best image quality for the avatar. + resized_ = gfx::ImageSkiaOperations::CreateResizedImage( + image_, skia::ImageOperations::RESIZE_BEST, size); + if (GetWidget() && visible()) { + PreferredSizeChanged(); + SchedulePaint(); + } +} + +void RoundedImageView::SetCornerRadii(int top_left, + int top_right, + int bottom_right, + int bottom_left) { + corner_radius_[0] = top_left; + corner_radius_[1] = top_right; + corner_radius_[2] = bottom_right; + corner_radius_[3] = bottom_left; +} + +gfx::Size RoundedImageView::GetPreferredSize() const { + return gfx::Size(image_size_.width() + GetInsets().width(), + image_size_.height() + GetInsets().height()); +} + +void RoundedImageView::OnPaint(gfx::Canvas* canvas) { + View::OnPaint(canvas); + gfx::Rect image_bounds(size()); + image_bounds.ClampToCenteredSize(GetPreferredSize()); + image_bounds.Inset(GetInsets()); + const SkScalar kRadius[8] = { + SkIntToScalar(corner_radius_[0]), SkIntToScalar(corner_radius_[0]), + SkIntToScalar(corner_radius_[1]), SkIntToScalar(corner_radius_[1]), + SkIntToScalar(corner_radius_[2]), SkIntToScalar(corner_radius_[2]), + SkIntToScalar(corner_radius_[3]), SkIntToScalar(corner_radius_[3])}; + SkPath path; + path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius); + cc::PaintFlags flags; + flags.setAntiAlias(true); + canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(), path, + flags); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/user/rounded_image_view.h b/ash/common/system/user/rounded_image_view.h new file mode 100644 index 0000000..c424777 --- /dev/null +++ b/ash/common/system/user/rounded_image_view.h
@@ -0,0 +1,50 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_ROUNDED_IMAGE_VIEW_H_ +#define ASH_COMMON_SYSTEM_USER_ROUNDED_IMAGE_VIEW_H_ + +#include "base/macros.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/view.h" + +namespace ash { +namespace tray { + +// A custom image view with rounded edges. +class RoundedImageView : public views::View { + public: + // Constructs a new rounded image view with rounded corners of radius + // |corner_radius|. + explicit RoundedImageView(int corner_radius); + ~RoundedImageView() override; + + // Set the image that should be displayed. The image contents is copied to the + // receiver's image. + void SetImage(const gfx::ImageSkia& img, const gfx::Size& size); + + // Set the radii of the corners independently. + void SetCornerRadii(int top_left, + int top_right, + int bottom_right, + int bottom_left); + + // Overridden from views::View. + gfx::Size GetPreferredSize() const override; + void OnPaint(gfx::Canvas* canvas) override; + + private: + gfx::ImageSkia image_; + gfx::ImageSkia resized_; + gfx::Size image_size_; + int corner_radius_[4]; + + DISALLOW_COPY_AND_ASSIGN(RoundedImageView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_ROUNDED_IMAGE_VIEW_H_
diff --git a/ash/common/system/user/tray_user.cc b/ash/common/system/user/tray_user.cc new file mode 100644 index 0000000..6537921 --- /dev/null +++ b/ash/common/system/user/tray_user.cc
@@ -0,0 +1,262 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/user/tray_user.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_item_view.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/system/user/rounded_image_view.h" +#include "ash/common/system/user/user_view.h" +#include "ash/common/wm_shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/logging.h" +#include "base/strings/string16.h" +#include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/user_info.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/image/image.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace { + +const int kUserLabelToIconPadding = 5; + +} // namespace + +namespace ash { + +TrayUser::TrayUser(SystemTray* system_tray, UserIndex index) + : SystemTrayItem(system_tray, UMA_USER), + user_index_(index), + user_(nullptr), + layout_view_(nullptr), + avatar_(nullptr), + label_(nullptr) { + WmShell::Get()->system_tray_notifier()->AddUserObserver(this); +} + +TrayUser::~TrayUser() { + WmShell::Get()->system_tray_notifier()->RemoveUserObserver(this); +} + +TrayUser::TestState TrayUser::GetStateForTest() const { + if (!user_) + return HIDDEN; + return user_->GetStateForTest(); +} + +gfx::Size TrayUser::GetLayoutSizeForTest() const { + return layout_view_ ? layout_view_->size() : gfx::Size(); +} + +gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const { + DCHECK(user_); + return user_->GetBoundsInScreenOfUserButtonForTest(); +} + +void TrayUser::UpdateAfterLoginStatusChangeForTest(LoginStatus status) { + UpdateAfterLoginStatusChange(status); +} + +views::View* TrayUser::CreateTrayView(LoginStatus status) { + CHECK(layout_view_ == nullptr); + + layout_view_ = new views::View; + UpdateAfterLoginStatusChange(status); + return layout_view_; +} + +views::View* TrayUser::CreateDefaultView(LoginStatus status) { + if (status == LoginStatus::NOT_LOGGED_IN) + return nullptr; + const SessionStateDelegate* session_state_delegate = + WmShell::Get()->GetSessionStateDelegate(); + + // If the screen is locked or a system modal dialog box is shown, show only + // the currently active user. + if (user_index_ && (session_state_delegate->IsUserSessionBlocked() || + WmShell::Get()->IsSystemModalWindowOpen())) + return nullptr; + + CHECK(user_ == nullptr); + + int logged_in_users = session_state_delegate->NumberOfLoggedInUsers(); + + // Do not show more UserView's then there are logged in users. + if (user_index_ >= logged_in_users) + return nullptr; + + user_ = new tray::UserView(this, status, user_index_); + return user_; +} + +void TrayUser::DestroyTrayView() { + layout_view_ = nullptr; + avatar_ = nullptr; + label_ = nullptr; +} + +void TrayUser::DestroyDefaultView() { + user_ = nullptr; +} + +void TrayUser::UpdateAfterLoginStatusChange(LoginStatus status) { + // Only the active user is represented in the tray. + if (!layout_view_) + return; + if (user_index_ > 0) + return; + bool need_label = false; + bool need_avatar = false; + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (delegate->IsUserSupervised()) + need_label = true; + switch (status) { + case LoginStatus::LOCKED: + case LoginStatus::USER: + case LoginStatus::OWNER: + case LoginStatus::PUBLIC: + need_avatar = true; + break; + case LoginStatus::SUPERVISED: + need_avatar = true; + need_label = true; + break; + case LoginStatus::GUEST: + need_label = true; + break; + case LoginStatus::KIOSK_APP: + case LoginStatus::ARC_KIOSK_APP: + case LoginStatus::NOT_LOGGED_IN: + break; + } + + if ((need_avatar != (avatar_ != nullptr)) || + (need_label != (label_ != nullptr))) { + delete label_; + delete avatar_; + + if (need_label) { + label_ = new views::Label; + SetupLabelForTray(label_); + layout_view_->AddChildView(label_); + } else { + label_ = nullptr; + } + if (need_avatar) { + avatar_ = new tray::RoundedImageView(kTrayRoundedBorderRadius); + avatar_->SetPaintToLayer(); + avatar_->layer()->SetFillsBoundsOpaquely(false); + layout_view_->AddChildView(avatar_); + } else { + avatar_ = nullptr; + } + } + + if (delegate->IsUserSupervised()) { + label_->SetText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL)); + } else if (status == LoginStatus::GUEST) { + label_->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL)); + } + + UpdateAvatarImage(status); + + // Update layout after setting label_ and avatar_ with new login status. + UpdateLayoutOfItem(); +} + +void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { + // Inactive users won't have a layout. + if (!layout_view_) + return; + if (IsHorizontalAlignment(alignment)) { + if (avatar_) { + avatar_->SetCornerRadii(0, kTrayRoundedBorderRadius, + kTrayRoundedBorderRadius, 0); + } + if (label_) { + // If label_ hasn't figured out its size yet, do that first. + if (label_->GetContentsBounds().height() == 0) + label_->SizeToPreferredSize(); + int height = label_->GetContentsBounds().height(); + int vertical_pad = (kTrayItemSize - height) / 2; + int remainder = height % 2; + label_->SetBorder(views::CreateEmptyBorder( + vertical_pad + remainder, + kTrayLabelItemHorizontalPaddingBottomAlignment, vertical_pad, + kTrayLabelItemHorizontalPaddingBottomAlignment)); + } + layout_view_->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kHorizontal, 0, 0, kUserLabelToIconPadding)); + } else { + if (avatar_) { + avatar_->SetCornerRadii(0, 0, kTrayRoundedBorderRadius, + kTrayRoundedBorderRadius); + } + if (label_) { + label_->SetBorder(views::CreateEmptyBorder( + kTrayLabelItemVerticalPaddingVerticalAlignment, + kTrayLabelItemHorizontalPaddingBottomAlignment, + kTrayLabelItemVerticalPaddingVerticalAlignment, + kTrayLabelItemHorizontalPaddingBottomAlignment)); + } + layout_view_->SetLayoutManager(new views::BoxLayout( + views::BoxLayout::kVertical, 0, 0, kUserLabelToIconPadding)); + } +} + +void TrayUser::OnUserUpdate() { + UpdateAvatarImage( + WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()); +} + +void TrayUser::OnUserAddedToSession() { + SessionStateDelegate* session_state_delegate = + WmShell::Get()->GetSessionStateDelegate(); + // Only create views for user items which are logged in. + if (user_index_ >= session_state_delegate->NumberOfLoggedInUsers()) + return; + + // Enforce a layout change that newly added items become visible. + UpdateLayoutOfItem(); + + // Update the user item. + UpdateAvatarImage( + WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()); +} + +void TrayUser::UpdateAvatarImage(LoginStatus status) { + SessionStateDelegate* session_state_delegate = + WmShell::Get()->GetSessionStateDelegate(); + if (!avatar_ || + user_index_ >= session_state_delegate->NumberOfLoggedInUsers()) + return; + + const user_manager::UserInfo* user_info = + session_state_delegate->GetUserInfo(user_index_); + CHECK(user_info); + avatar_->SetImage(user_info->GetImage(), + gfx::Size(kTrayItemSize, kTrayItemSize)); + + // Unit tests might come here with no images for some users. + if (avatar_->size().IsEmpty()) + avatar_->SetSize(gfx::Size(kTrayItemSize, kTrayItemSize)); +} + +void TrayUser::UpdateLayoutOfItem() { + UpdateAfterShelfAlignmentChange(system_tray()->shelf_alignment()); +} + +} // namespace ash
diff --git a/ash/common/system/user/tray_user.h b/ash/common/system/user/tray_user.h new file mode 100644 index 0000000..2b3573d7 --- /dev/null +++ b/ash/common/system/user/tray_user.h
@@ -0,0 +1,95 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_TRAY_USER_H_ +#define ASH_COMMON_SYSTEM_USER_TRAY_USER_H_ + +#include "ash/ash_export.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/user/user_observer.h" +#include "ash/public/cpp/session_types.h" +#include "base/macros.h" + +namespace gfx { +class Rect; +class Size; +} + +namespace views { +class Label; +} + +namespace ash { + +namespace tray { +class RoundedImageView; +class UserView; +} + +class ASH_EXPORT TrayUser : public SystemTrayItem, public UserObserver { + public: + // The given |index| is the user index in a multi profile scenario. Index #0 + // is the active user, the other indices are other logged in users (if there + // are any). Depending on the multi user mode, there will be either one (index + // #0) or all users be visible in the system tray. + TrayUser(SystemTray* system_tray, UserIndex index); + ~TrayUser() override; + + // Allows unit tests to see if the item was created. + enum TestState { + HIDDEN, // The item is hidden. + SHOWN, // The item gets presented to the user. + HOVERED, // The item is hovered and presented to the user. + ACTIVE, // The item was clicked and can add a user. + ACTIVE_BUT_DISABLED // The item was clicked anc cannot add a user. + }; + TestState GetStateForTest() const; + + // Returns the size of layout_view_. + gfx::Size GetLayoutSizeForTest() const; + + // Returns the bounds of the user panel in screen coordinates. + // Note: This only works when the panel shown. + gfx::Rect GetUserPanelBoundsInScreenForTest() const; + + // Update the TrayUser as if the current LoginStatus is |status|. + void UpdateAfterLoginStatusChangeForTest(LoginStatus status); + + // Use for access inside of tests. + tray::UserView* user_view_for_test() const { return user_; } + + private: + // Overridden from SystemTrayItem. + views::View* CreateTrayView(LoginStatus status) override; + views::View* CreateDefaultView(LoginStatus status) override; + void DestroyTrayView() override; + void DestroyDefaultView() override; + void UpdateAfterLoginStatusChange(LoginStatus status) override; + void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; + + // Overridden from UserObserver. + void OnUserUpdate() override; + void OnUserAddedToSession() override; + + void UpdateAvatarImage(LoginStatus status); + + // Updates the layout of this item. + void UpdateLayoutOfItem(); + + // The user index to use. + UserIndex user_index_; + + tray::UserView* user_; + + // View that contains label and/or avatar. + views::View* layout_view_; + tray::RoundedImageView* avatar_; + views::Label* label_; + + DISALLOW_COPY_AND_ASSIGN(TrayUser); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_TRAY_USER_H_
diff --git a/ash/common/system/user/tray_user_unittest.cc b/ash/common/system/user/tray_user_unittest.cc new file mode 100644 index 0000000..70c0423 --- /dev/null +++ b/ash/common/system/user/tray_user_unittest.cc
@@ -0,0 +1,254 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "ash/common/shell_delegate.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/user/tray_user.h" +#include "ash/common/system/user/user_view.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/ash_test_helper.h" +#include "ash/test/test_shell_delegate.h" +#include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/user_info.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/events/test/event_generator.h" +#include "ui/gfx/animation/animation_container_element.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace { + +class TrayUserTest : public test::AshTestBase { + public: + TrayUserTest() = default; + + // testing::Test: + void SetUp() override; + + // This has to be called prior to first use with the proper configuration. + void InitializeParameters(int users_logged_in, bool multiprofile); + + // Show the system tray menu using the provided event generator. + void ShowTrayMenu(ui::test::EventGenerator* generator); + + // Move the mouse over the user item. + void MoveOverUserItem(ui::test::EventGenerator* generator, int index); + + // Click on the user item. Note that the tray menu needs to be shown. + void ClickUserItem(ui::test::EventGenerator* generator, int index); + + // Accessors to various system components. + SystemTray* tray() { return tray_; } + test::TestSessionStateDelegate* delegate() { return delegate_; } + TrayUser* tray_user(int index) { return tray_user_[index]; } + + private: + SystemTray* tray_ = nullptr; + test::TestSessionStateDelegate* delegate_ = nullptr; + + // Note that the ownership of these items is on the shelf. + std::vector<TrayUser*> tray_user_; + + DISALLOW_COPY_AND_ASSIGN(TrayUserTest); +}; + +void TrayUserTest::SetUp() { + test::AshTestBase::SetUp(); + tray_ = GetPrimarySystemTray(); + delegate_ = test::AshTestHelper::GetTestSessionStateDelegate(); +} + +void TrayUserTest::InitializeParameters(int users_logged_in, + bool multiprofile) { + // Set our default assumptions. Note that it is sufficient to set these + // after everything was created. + delegate_->set_logged_in_users(users_logged_in); + test::TestShellDelegate* shell_delegate = + static_cast<test::TestShellDelegate*>(WmShell::Get()->delegate()); + shell_delegate->set_multi_profiles_enabled(multiprofile); + + // Instead of using the existing tray panels we create new ones which makes + // the access easier. + for (int i = 0; i < delegate_->GetMaximumNumberOfLoggedInUsers(); i++) { + tray_user_.push_back(new TrayUser(tray_, i)); + tray_->AddTrayItem(base::WrapUnique(tray_user_[i])); + } +} + +void TrayUserTest::ShowTrayMenu(ui::test::EventGenerator* generator) { + gfx::Point center = tray()->GetBoundsInScreen().CenterPoint(); + + generator->MoveMouseTo(center.x(), center.y()); + EXPECT_FALSE(tray()->IsSystemBubbleVisible()); + generator->ClickLeftButton(); +} + +void TrayUserTest::MoveOverUserItem(ui::test::EventGenerator* generator, + int index) { + gfx::Point center = + tray_user(index)->GetUserPanelBoundsInScreenForTest().CenterPoint(); + + generator->MoveMouseTo(center.x(), center.y()); +} + +void TrayUserTest::ClickUserItem(ui::test::EventGenerator* generator, + int index) { + MoveOverUserItem(generator, index); + generator->ClickLeftButton(); +} + +} // namespace + +// Make sure that we show items for all users in the tray accordingly. +TEST_F(TrayUserTest, CheckTrayItemSize) { + InitializeParameters(1, false); + tray_user(0)->UpdateAfterLoginStatusChangeForTest(LoginStatus::GUEST); + gfx::Size size = tray_user(0)->GetLayoutSizeForTest(); + EXPECT_EQ(kTrayItemSize, size.height()); + tray_user(0)->UpdateAfterLoginStatusChangeForTest(LoginStatus::USER); + size = tray_user(0)->GetLayoutSizeForTest(); + EXPECT_EQ(kTrayItemSize, size.height()); +} + +// Make sure that in single user mode the user panel cannot be activated. +TEST_F(TrayUserTest, SingleUserModeDoesNotAllowAddingUser) { + InitializeParameters(1, false); + + // Move the mouse over the status area and click to open the status menu. + ui::test::EventGenerator& generator = GetEventGenerator(); + + EXPECT_FALSE(tray()->IsSystemBubbleVisible()); + + for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) + EXPECT_EQ(TrayUser::HIDDEN, tray_user(i)->GetStateForTest()); + + ShowTrayMenu(&generator); + + EXPECT_TRUE(tray()->HasSystemBubble()); + EXPECT_TRUE(tray()->IsSystemBubbleVisible()); + + for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) + EXPECT_EQ(i == 0 ? TrayUser::SHOWN : TrayUser::HIDDEN, + tray_user(i)->GetStateForTest()); + tray()->CloseSystemBubble(); +} + +TEST_F(TrayUserTest, AccessibleLabelContainsSingleUserInfo) { + InitializeParameters(1, false); + ui::test::EventGenerator& generator = GetEventGenerator(); + ShowTrayMenu(&generator); + + views::View* view = + tray_user(0)->user_view_for_test()->user_card_view_for_test(); + ui::AXNodeData node_data; + view->GetAccessibleNodeData(&node_data); + EXPECT_EQ( + base::UTF8ToUTF16("Über tray Über tray Über tray Über tray First@tray"), + node_data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, node_data.role); +} + +TEST_F(TrayUserTest, AccessibleLabelContainsMultiUserInfo) { + InitializeParameters(1, true); + ui::test::EventGenerator& generator = GetEventGenerator(); + ShowTrayMenu(&generator); + + views::View* view = + tray_user(0)->user_view_for_test()->user_card_view_for_test(); + ui::AXNodeData node_data; + view->GetAccessibleNodeData(&node_data); + EXPECT_EQ( + base::UTF8ToUTF16("Über tray Über tray Über tray Über tray First@tray"), + node_data.GetString16Attribute(ui::AX_ATTR_NAME)); + EXPECT_EQ(ui::AX_ROLE_BUTTON, node_data.role); +} + +// Make sure that in multi user mode the user panel can be activated and there +// will be one panel for each user. +// Note: the mouse watcher (for automatic closing upon leave) cannot be tested +// here since it does not work with the event system in unit tests. +TEST_F(TrayUserTest, MultiUserModeDoesNotAllowToAddUser) { + InitializeParameters(1, true); + + // Move the mouse over the status area and click to open the status menu. + ui::test::EventGenerator& generator = GetEventGenerator(); + generator.set_async(false); + + int max_users = delegate()->GetMaximumNumberOfLoggedInUsers(); + // Checking now for each amount of users that the correct is done. + for (int j = 1; j < max_users; j++) { + // Set the number of logged in users. + delegate()->set_logged_in_users(j); + + // Verify that nothing is shown. + EXPECT_FALSE(tray()->IsSystemBubbleVisible()); + for (int i = 0; i < max_users; i++) + EXPECT_FALSE(tray_user(i)->GetStateForTest()); + // After clicking on the tray the menu should get shown and for each logged + // in user we should get a visible item. + ShowTrayMenu(&generator); + + EXPECT_TRUE(tray()->HasSystemBubble()); + EXPECT_TRUE(tray()->IsSystemBubbleVisible()); + for (int i = 0; i < max_users; i++) { + EXPECT_EQ(i < j ? TrayUser::SHOWN : TrayUser::HIDDEN, + tray_user(i)->GetStateForTest()); + } + + // Move the mouse over the user item and it should hover. + MoveOverUserItem(&generator, 0); + EXPECT_EQ(TrayUser::HOVERED, tray_user(0)->GetStateForTest()); + for (int i = 1; i < max_users; i++) { + EXPECT_EQ(i < j ? TrayUser::SHOWN : TrayUser::HIDDEN, + tray_user(i)->GetStateForTest()); + } + + // Check that clicking the button allows to add item if we have still room + // for one more user. + ClickUserItem(&generator, 0); + EXPECT_EQ(j == max_users ? TrayUser::ACTIVE_BUT_DISABLED : TrayUser::ACTIVE, + tray_user(0)->GetStateForTest()); + + // Click the button again to see that the menu goes away. + ClickUserItem(&generator, 0); + MoveOverUserItem(&generator, 0); + EXPECT_EQ(TrayUser::HOVERED, tray_user(0)->GetStateForTest()); + + // Close and check that everything is deleted. + tray()->CloseSystemBubble(); + EXPECT_FALSE(tray()->IsSystemBubbleVisible()); + for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) + EXPECT_EQ(TrayUser::HIDDEN, tray_user(i)->GetStateForTest()); + } +} + +// Make sure that user changing gets properly executed. +TEST_F(TrayUserTest, MultiUserModeButtonClicks) { + // Have two users. + InitializeParameters(2, true); + ui::test::EventGenerator& generator = GetEventGenerator(); + ShowTrayMenu(&generator); + + // Switch to a new user - which has a capitalized name. + ClickUserItem(&generator, 1); + const user_manager::UserInfo* active_user = delegate()->GetActiveUserInfo(); + const user_manager::UserInfo* second_user = delegate()->GetUserInfo(1); + EXPECT_EQ(active_user->GetAccountId(), second_user->GetAccountId()); + // Since the name is capitalized, the email should be different than the + // user_id. + EXPECT_NE(active_user->GetAccountId().GetUserEmail(), + second_user->GetDisplayEmail()); + tray()->CloseSystemBubble(); +} + +} // namespace ash
diff --git a/ash/common/system/user/user_card_view.cc b/ash/common/system/user/user_card_view.cc new file mode 100644 index 0000000..ff20defe --- /dev/null +++ b/ash/common/system/user/user_card_view.cc
@@ -0,0 +1,470 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/user/user_card_view.h" + +#include <algorithm> +#include <memory> +#include <vector> + +#include "ash/common/ash_view_ids.h" +#include "ash/common/login_status.h" +#include "ash/common/media_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/user/rounded_image_view.h" +#include "ash/common/wm_shell.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/i18n/rtl.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/user_manager/user_info.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/compositor/compositing_recorder.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/color_palette.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/range/range.h" +#include "ui/gfx/render_text.h" +#include "ui/gfx/text_elider.h" +#include "ui/gfx/text_utils.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/link.h" +#include "ui/views/controls/link_listener.h" +#include "ui/views/layout/box_layout.h" + +namespace ash { +namespace tray { + +namespace { + +const int kUserDetailsVerticalPadding = 5; + +// The invisible word joiner character, used as a marker to indicate the start +// and end of the user's display name in the public account user card's text. +const base::char16 kDisplayNameMark[] = {0x2060, 0}; + +views::View* CreateUserAvatarView(LoginStatus login_status, int user_index) { + RoundedImageView* image_view = new RoundedImageView(kTrayItemSize / 2); + if (login_status == LoginStatus::GUEST) { + gfx::ImageSkia icon = + gfx::CreateVectorIcon(kSystemMenuGuestIcon, kMenuIconColor); + image_view->SetImage(icon, icon.size()); + } else { + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + image_view->SetImage(delegate->GetUserInfo(user_index)->GetImage(), + gfx::Size(kTrayItemSize, kTrayItemSize)); + } + + image_view->SetBorder(views::CreateEmptyBorder(gfx::Insets( + (kTrayPopupItemMinStartWidth - image_view->GetPreferredSize().width()) / + 2))); + return image_view; +} + +// The user details shown in public account mode. This is essentially a label +// but with custom painting code as the text is styled with multiple colors and +// contains a link. +class PublicAccountUserDetails : public views::View, + public views::LinkListener { + public: + PublicAccountUserDetails(int max_width); + ~PublicAccountUserDetails() override; + + private: + // Overridden from views::View. + void Layout() override; + gfx::Size GetPreferredSize() const override; + void OnPaint(gfx::Canvas* canvas) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + // Overridden from views::LinkListener. + void LinkClicked(views::Link* source, int event_flags) override; + + // Calculate a preferred size that ensures the label text and the following + // link do not wrap over more than three lines in total for aesthetic reasons + // if possible. + void CalculatePreferredSize(); + + base::string16 text_; + views::Link* learn_more_; + gfx::Size preferred_size_; + std::vector<std::unique_ptr<gfx::RenderText>> lines_; + + DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails); +}; + +PublicAccountUserDetails::PublicAccountUserDetails(int max_width) + : learn_more_(NULL) { + const int inner_padding = + kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems; + const bool rtl = base::i18n::IsRTL(); + SetBorder(views::CreateEmptyBorder( + kUserDetailsVerticalPadding, rtl ? 0 : inner_padding, + kUserDetailsVerticalPadding, rtl ? inner_padding : 0)); + + // Retrieve the user's display name and wrap it with markers. + // Note that since this is a public account it always has to be the primary + // user. + base::string16 display_name = WmShell::Get() + ->GetSessionStateDelegate() + ->GetUserInfo(0) + ->GetDisplayName(); + base::RemoveChars(display_name, kDisplayNameMark, &display_name); + display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0]; + // Retrieve the domain managing the device and wrap it with markers. + base::string16 domain = base::UTF8ToUTF16( + WmShell::Get()->system_tray_delegate()->GetEnterpriseDomain()); + base::RemoveChars(domain, kDisplayNameMark, &domain); + base::i18n::WrapStringWithLTRFormatting(&domain); + // Retrieve the label text, inserting the display name and domain. + text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL, + display_name, domain); + + learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE)); + learn_more_->SetUnderline(false); + learn_more_->set_listener(this); + AddChildView(learn_more_); + + CalculatePreferredSize(); +} + +PublicAccountUserDetails::~PublicAccountUserDetails() {} + +void PublicAccountUserDetails::Layout() { + lines_.clear(); + const gfx::Rect contents_area = GetContentsBounds(); + if (contents_area.IsEmpty()) + return; + + // Word-wrap the label text. + const gfx::FontList font_list; + std::vector<base::string16> lines; + gfx::ElideRectangleText(text_, font_list, contents_area.width(), + contents_area.height(), gfx::ELIDE_LONG_WORDS, + &lines); + // Loop through the lines, creating a renderer for each. + gfx::Point position = contents_area.origin(); + gfx::Range display_name(gfx::Range::InvalidRange()); + for (auto it = lines.begin(); it != lines.end(); ++it) { + auto line = base::WrapUnique(gfx::RenderText::CreateInstance()); + line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI); + line->SetText(*it); + const gfx::Size size(contents_area.width(), line->GetStringSize().height()); + line->SetDisplayRect(gfx::Rect(position, size)); + position.set_y(position.y() + size.height()); + + // Set the default text color for the line. + line->SetColor(kPublicAccountUserCardTextColor); + + // If a range of the line contains the user's display name, apply a custom + // text color to it. + if (display_name.is_empty()) + display_name.set_start(it->find(kDisplayNameMark)); + if (!display_name.is_empty()) { + display_name.set_end( + it->find(kDisplayNameMark, display_name.start() + 1)); + gfx::Range line_range(0, it->size()); + line->ApplyColor(kPublicAccountUserCardNameColor, + display_name.Intersect(line_range)); + // Update the range for the next line. + if (display_name.end() >= line_range.end()) + display_name.set_start(0); + else + display_name = gfx::Range::InvalidRange(); + } + + lines_.push_back(std::move(line)); + } + + // Position the link after the label text, separated by a space. If it does + // not fit onto the last line of the text, wrap the link onto its own line. + const gfx::Size last_line_size = lines_.back()->GetStringSize(); + const int space_width = + gfx::GetStringWidth(base::ASCIIToUTF16(" "), font_list); + const gfx::Size link_size = learn_more_->GetPreferredSize(); + if (contents_area.width() - last_line_size.width() >= + space_width + link_size.width()) { + position.set_x(position.x() + last_line_size.width() + space_width); + position.set_y(position.y() - last_line_size.height()); + } + position.set_y(position.y() - learn_more_->GetInsets().top()); + gfx::Rect learn_more_bounds(position, link_size); + learn_more_bounds.Intersect(contents_area); + if (base::i18n::IsRTL()) { + const gfx::Insets insets = GetInsets(); + learn_more_bounds.Offset(insets.right() - insets.left(), 0); + } + learn_more_->SetBoundsRect(learn_more_bounds); +} + +gfx::Size PublicAccountUserDetails::GetPreferredSize() const { + return preferred_size_; +} + +void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) { + for (const auto& line : lines_) + line->Draw(canvas); + + views::View::OnPaint(canvas); +} + +void PublicAccountUserDetails::GetAccessibleNodeData( + ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_STATIC_TEXT; + node_data->SetName(text_); +} + +void PublicAccountUserDetails::LinkClicked(views::Link* source, + int event_flags) { + DCHECK_EQ(source, learn_more_); + WmShell::Get()->system_tray_controller()->ShowPublicAccountInfo(); +} + +void PublicAccountUserDetails::CalculatePreferredSize() { + const gfx::FontList font_list; + const gfx::Size link_size = learn_more_->GetPreferredSize(); + const int space_width = + gfx::GetStringWidth(base::ASCIIToUTF16(" "), font_list); + const gfx::Insets insets = GetInsets(); + int min_width = link_size.width(); + int max_width = + gfx::GetStringWidth(text_, font_list) + space_width + link_size.width(); + + // Do a binary search for the minimum width that ensures no more than three + // lines are needed. The lower bound is the minimum of the current bubble + // width and the width of the link (as no wrapping is permitted inside the + // link). The upper bound is the maximum of the largest allowed bubble width + // and the sum of the label text and link widths when put on a single line. + std::vector<base::string16> lines; + while (min_width < max_width) { + lines.clear(); + const int width = (min_width + max_width) / 2; + const bool too_narrow = + gfx::ElideRectangleText(text_, font_list, width, INT_MAX, + gfx::TRUNCATE_LONG_WORDS, &lines) != 0; + int line_count = lines.size(); + if (!too_narrow && line_count == 3 && + width - gfx::GetStringWidth(lines.back(), font_list) <= + space_width + link_size.width()) + ++line_count; + if (too_narrow || line_count > 3) + min_width = width + 1; + else + max_width = width; + } + + // Calculate the corresponding height and set the preferred size. + lines.clear(); + gfx::ElideRectangleText(text_, font_list, min_width, INT_MAX, + gfx::TRUNCATE_LONG_WORDS, &lines); + int line_count = lines.size(); + if (min_width - gfx::GetStringWidth(lines.back(), font_list) <= + space_width + link_size.width()) { + ++line_count; + } + const int line_height = font_list.GetHeight(); + const int link_extra_height = std::max( + link_size.height() - learn_more_->GetInsets().top() - line_height, 0); + preferred_size_ = + gfx::Size(min_width + insets.width(), + line_count * line_height + link_extra_height + insets.height()); +} + +} // namespace + +UserCardView::UserCardView(LoginStatus login_status, + int max_width, + int user_index) + : user_index_(user_index), + user_name_(nullptr), + media_capture_label_(nullptr), + media_capture_icon_(nullptr) { + auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, + kTrayPopupLabelHorizontalPadding); + SetLayoutManager(layout); + layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); + layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + // For active users, the left inset is provided by ActiveUserBorder, which + // is necessary to make sure the ripple does not cover that part of the row. + // For inactive users, we set the inset here and this causes the ripple to + // extend all the way to the edges of the menu. + if (!is_active_user()) + SetBorder(views::CreateEmptyBorder(0, kMenuExtraMarginFromLeftEdge, 0, 0)); + + WmShell::Get()->media_controller()->AddObserver(this); + + if (login_status == LoginStatus::PUBLIC) + AddPublicModeUserContent(max_width); + else + AddUserContent(layout, login_status); +} + +UserCardView::~UserCardView() { + WmShell::Get()->media_controller()->RemoveObserver(this); +} + +void UserCardView::PaintChildren(const ui::PaintContext& context) { + if (!is_active_user()) { + ui::CompositingRecorder alpha(context, 0xFF / 2, true); + View::PaintChildren(context); + } else { + View::PaintChildren(context); + } +} + +void UserCardView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + node_data->role = ui::AX_ROLE_STATIC_TEXT; + std::vector<base::string16> labels; + + // Construct the name by concatenating descendants' names. + std::list<views::View*> descendants; + descendants.push_back(this); + while (!descendants.empty()) { + auto* view = descendants.front(); + descendants.pop_front(); + if (view != this) { + ui::AXNodeData descendant_data; + view->GetAccessibleNodeData(&descendant_data); + base::string16 label = + descendant_data.GetString16Attribute(ui::AX_ATTR_NAME); + // If we find a non-empty name, use that and don't descend further into + // the tree. + if (!label.empty()) { + labels.push_back(label); + continue; + } + } + + // This view didn't have its own name, so look over its children. + for (int i = view->child_count() - 1; i >= 0; --i) + descendants.push_front(view->child_at(i)); + } + node_data->SetName(base::JoinString(labels, base::ASCIIToUTF16(" "))); +} + +void UserCardView::OnMediaCaptureChanged( + const std::vector<mojom::MediaCaptureState>& capture_states) { + if (is_active_user()) + return; + + mojom::MediaCaptureState state = capture_states[user_index_]; + int res_id = 0; + switch (state) { + case mojom::MediaCaptureState::AUDIO_VIDEO: + res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO_VIDEO; + break; + case mojom::MediaCaptureState::AUDIO: + res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO; + break; + case mojom::MediaCaptureState::VIDEO: + res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_VIDEO; + break; + case mojom::MediaCaptureState::NONE: + break; + } + if (res_id) + media_capture_label_->SetText(l10n_util::GetStringUTF16(res_id)); + media_capture_label_->SetVisible(!!res_id); + media_capture_icon_->SetVisible(!!res_id); + user_name_->SetVisible(!res_id); + Layout(); +} + +void UserCardView::AddPublicModeUserContent(int max_width) { + views::View* avatar = CreateUserAvatarView(LoginStatus::PUBLIC, 0); + AddChildView(avatar); + int details_max_width = max_width - avatar->GetPreferredSize().width() - + kTrayPopupPaddingBetweenItems; + AddChildView(new PublicAccountUserDetails(details_max_width)); +} + +void UserCardView::AddUserContent(views::BoxLayout* layout, + LoginStatus login_status) { + AddChildView(CreateUserAvatarView(login_status, user_index_)); + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + base::string16 user_name_string = + login_status == LoginStatus::GUEST + ? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL) + : delegate->GetUserInfo(user_index_)->GetDisplayName(); + user_name_ = new views::Label(user_name_string); + user_name_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + TrayPopupItemStyle user_name_style( + TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + user_name_style.SetupLabel(user_name_); + + TrayPopupItemStyle user_email_style(TrayPopupItemStyle::FontStyle::CAPTION); + // Only the active user's email label is lightened (for the inactive user, the + // label starts as black and the entire row is 54% opacity). + if (is_active_user()) + user_email_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); + auto* user_email = new views::Label(); + base::string16 user_email_string; + if (login_status != LoginStatus::GUEST) { + user_email_string = + WmShell::Get()->system_tray_delegate()->IsUserSupervised() + ? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL) + : base::UTF8ToUTF16( + delegate->GetUserInfo(user_index_)->GetDisplayEmail()); + } + user_email->SetText(user_email_string); + user_email->SetHorizontalAlignment(gfx::ALIGN_LEFT); + user_email_style.SetupLabel(user_email); + user_email->SetVisible(!user_email_string.empty()); + user_email->set_collapse_when_hidden(true); + + views::View* stack_of_labels = new views::View; + AddChildView(stack_of_labels); + layout->SetFlexForView(stack_of_labels, 1); + stack_of_labels->SetLayoutManager( + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); + stack_of_labels->AddChildView(user_name_); + stack_of_labels->AddChildView(user_email); + // The name and email have different font sizes. This border is designed + // to make both views take up equal space so the whitespace between them + // is centered on the vertical midpoint. + int user_email_bottom_pad = user_name_->GetPreferredSize().height() - + user_email->GetPreferredSize().height(); + user_email->SetBorder( + views::CreateEmptyBorder(0, 0, user_email_bottom_pad, 0)); + + // Only inactive users need media capture indicators. + if (!is_active_user()) { + media_capture_label_ = new views::Label(); + media_capture_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + media_capture_label_->SetBorder( + views::CreateEmptyBorder(0, 0, user_email_bottom_pad, 0)); + user_email_style.SetupLabel(media_capture_label_); + stack_of_labels->AddChildView(media_capture_label_); + + media_capture_icon_ = new views::ImageView; + media_capture_icon_->SetImage( + gfx::CreateVectorIcon(kSystemTrayRecordingIcon, gfx::kGoogleRed700)); + const int media_capture_width = kTrayPopupItemMinEndWidth; + media_capture_icon_->SetBorder(views::CreateEmptyBorder( + gfx::Insets(0, (media_capture_width - + media_capture_icon_->GetPreferredSize().width()) / + 2))); + + media_capture_icon_->set_id(VIEW_ID_USER_VIEW_MEDIA_INDICATOR); + AddChildView(media_capture_icon_); + + WmShell::Get()->media_controller()->RequestCaptureState(); + } +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/user/user_card_view.h b/ash/common/system/user/user_card_view.h new file mode 100644 index 0000000..fa20e0a --- /dev/null +++ b/ash/common/system/user/user_card_view.h
@@ -0,0 +1,60 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_USER_CARD_VIEW_H_ +#define ASH_COMMON_SYSTEM_USER_USER_CARD_VIEW_H_ + +#include "ash/common/media_controller.h" +#include "base/macros.h" +#include "ui/views/view.h" + +namespace views { +class BoxLayout; +class ImageView; +class Label; +} + +namespace ash { + +enum class LoginStatus; + +namespace tray { + +// The view displaying information about the user, such as user's avatar, email +// address, name, and more. View has no borders. +class UserCardView : public views::View, public MediaCaptureObserver { + public: + // |max_width| takes effect only if |login_status| is LOGGED_IN_PUBLIC. + UserCardView(LoginStatus login_status, int max_width, int user_index); + ~UserCardView() override; + + // View: + void PaintChildren(const ui::PaintContext& context) override; + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + + // MediaCaptureObserver: + void OnMediaCaptureChanged( + const std::vector<mojom::MediaCaptureState>& capture_states) override; + + private: + // Creates the content for the public mode. + void AddPublicModeUserContent(int max_width); + + void AddUserContent(views::BoxLayout* layout, LoginStatus login_status); + + bool is_active_user() const { return !user_index_; } + + int user_index_; + + views::Label* user_name_; + views::Label* media_capture_label_; + views::ImageView* media_capture_icon_; + + DISALLOW_COPY_AND_ASSIGN(UserCardView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_USER_CARD_VIEW_H_
diff --git a/ash/common/system/user/user_observer.h b/ash/common/system/user/user_observer.h new file mode 100644 index 0000000..8c30606f --- /dev/null +++ b/ash/common/system/user/user_observer.h
@@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_USER_OBSERVER_H_ +#define ASH_COMMON_SYSTEM_USER_USER_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class ASH_EXPORT UserObserver { + public: + virtual ~UserObserver() {} + + // A user got updated / changed. + virtual void OnUserUpdate() = 0; + + // A user was added to the existing session. + virtual void OnUserAddedToSession() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_USER_OBSERVER_H_
diff --git a/ash/common/system/user/user_view.cc b/ash/common/system/user/user_view.cc new file mode 100644 index 0000000..63d1c42c --- /dev/null +++ b/ash/common/system/user/user_view.cc
@@ -0,0 +1,400 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/user/user_view.h" + +#include <algorithm> +#include <utility> + +#include "ash/common/multi_profile_uma.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shell_delegate.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/user/button_from_view.h" +#include "ash/common/system/user/login_status.h" +#include "ash/common/system/user/rounded_image_view.h" +#include "ash/common/system/user/user_card_view.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/memory/ptr_util.h" +#include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/user_info.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/separator.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/painter.h" + +namespace ash { +namespace tray { + +namespace { + +// Switch to a user with the given |user_index|. +void SwitchUser(UserIndex user_index) { + // Do not switch users when the log screen is presented. + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + if (delegate->IsUserSessionBlocked()) + return; + + DCHECK(user_index > 0); + MultiProfileUMA::RecordSwitchActiveUser( + MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY); + delegate->SwitchActiveUser(delegate->GetUserInfo(user_index)->GetAccountId()); +} + +bool IsMultiProfileSupportedAndUserActive() { + return WmShell::Get()->delegate()->IsMultiProfilesEnabled() && + !WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked(); +} + +// Creates the view shown in the user switcher popup ("AddUserMenuOption"). +views::View* CreateAddUserView(AddUserSessionPolicy policy, + views::ButtonListener* listener) { + auto* view = new views::View; + const int icon_padding = (kMenuButtonSize - kMenuIconSize) / 2; + auto* layout = + new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, + kTrayPopupLabelHorizontalPadding + icon_padding); + layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); + view->SetLayoutManager(layout); + view->set_background( + views::Background::CreateSolidBackground(kBackgroundColor)); + + int message_id = 0; + switch (policy) { + case AddUserSessionPolicy::ALLOWED: { + message_id = IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT; + + auto* icon = new views::ImageView(); + icon->SetImage( + gfx::CreateVectorIcon(kSystemMenuNewUserIcon, kMenuIconColor)); + view->AddChildView(icon); + break; + } + case AddUserSessionPolicy::ERROR_NOT_ALLOWED_PRIMARY_USER: + message_id = IDS_ASH_STATUS_TRAY_MESSAGE_NOT_ALLOWED_PRIMARY_USER; + break; + case AddUserSessionPolicy::ERROR_MAXIMUM_USERS_REACHED: + message_id = IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER; + break; + case AddUserSessionPolicy::ERROR_NO_ELIGIBLE_USERS: + message_id = IDS_ASH_STATUS_TRAY_MESSAGE_OUT_OF_USERS; + break; + } + + auto* command_label = new views::Label(l10n_util::GetStringUTF16(message_id)); + command_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + command_label->SetMultiLine(true); + + TrayPopupItemStyle label_style( + TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); + int vertical_padding = kMenuSeparatorVerticalPadding; + if (policy != AddUserSessionPolicy::ALLOWED) { + label_style.set_font_style(TrayPopupItemStyle::FontStyle::CAPTION); + label_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); + vertical_padding += kMenuSeparatorVerticalPadding; + } + label_style.SetupLabel(command_label); + view->AddChildView(command_label); + view->SetBorder(views::CreateEmptyBorder(vertical_padding, icon_padding, + vertical_padding, + kTrayPopupLabelHorizontalPadding)); + if (policy == AddUserSessionPolicy::ALLOWED) { + auto* button = + new ButtonFromView(view, listener, TrayPopupInkDropStyle::INSET_BOUNDS); + button->SetAccessibleName( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT)); + return button; + } + + return view; +} + +class UserViewMouseWatcherHost : public views::MouseWatcherHost { + public: + explicit UserViewMouseWatcherHost(const gfx::Rect& screen_area) + : screen_area_(screen_area) {} + ~UserViewMouseWatcherHost() override {} + + // Implementation of MouseWatcherHost. + bool Contains(const gfx::Point& screen_point, + views::MouseWatcherHost::MouseEventType type) override { + return screen_area_.Contains(screen_point); + } + + private: + gfx::Rect screen_area_; + + DISALLOW_COPY_AND_ASSIGN(UserViewMouseWatcherHost); +}; + +// A view that acts as the contents of the widget that appears when clicking +// the active user. If the mouse exits this view or an otherwise unhandled +// click is detected, it will invoke a closure passed at construction time. +class AddUserWidgetContents : public views::View { + public: + explicit AddUserWidgetContents(const base::Closure& close_widget) + : close_widget_(close_widget) { + // Don't want to receive a mouse exit event when the cursor enters a child. + set_notify_enter_exit_on_child(true); + } + + ~AddUserWidgetContents() override {} + + bool OnMousePressed(const ui::MouseEvent& event) override { return true; } + void OnMouseReleased(const ui::MouseEvent& event) override { + close_widget_.Run(); + } + void OnMouseExited(const ui::MouseEvent& event) override { + close_widget_.Run(); + } + void OnGestureEvent(ui::GestureEvent* event) override { close_widget_.Run(); } + + private: + base::Closure close_widget_; + + DISALLOW_COPY_AND_ASSIGN(AddUserWidgetContents); +}; + +// This border reserves 4dp above and 8dp below and paints a horizontal +// separator 3dp below the host view. +class ActiveUserBorder : public views::Border { + public: + ActiveUserBorder() {} + ~ActiveUserBorder() override {} + + // views::Border: + void Paint(const views::View& view, gfx::Canvas* canvas) override { + canvas->FillRect( + gfx::Rect( + 0, view.height() - kMenuSeparatorVerticalPadding - kSeparatorWidth, + view.width(), kSeparatorWidth), + kMenuSeparatorColor); + } + + gfx::Insets GetInsets() const override { + return gfx::Insets(kMenuSeparatorVerticalPadding, + kMenuExtraMarginFromLeftEdge, + kMenuSeparatorVerticalPadding * 2, 0); + } + + gfx::Size GetMinimumSize() const override { return gfx::Size(); } + + private: + DISALLOW_COPY_AND_ASSIGN(ActiveUserBorder); +}; + +} // namespace + +UserView::UserView(SystemTrayItem* owner, LoginStatus login, UserIndex index) + : user_index_(index), + user_card_view_(nullptr), + owner_(owner), + is_user_card_button_(false), + logout_button_(nullptr), + add_user_enabled_(true), + focus_manager_(nullptr) { + CHECK_NE(LoginStatus::NOT_LOGGED_IN, login); + // The logout button must be added before the user card so that the user card + // can correctly calculate the remaining available width. + // Note that only the current multiprofile user gets a button. + if (IsActiveUser()) + AddLogoutButton(login); + AddUserCard(login); + + auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); + SetLayoutManager(layout); + layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); + layout->SetFlexForView(user_card_view_, 1); + + if (IsActiveUser()) + SetBorder(base::MakeUnique<ActiveUserBorder>()); +} + +UserView::~UserView() { + RemoveAddUserMenuOption(); +} + +TrayUser::TestState UserView::GetStateForTest() const { + if (add_menu_option_) + return add_user_enabled_ ? TrayUser::ACTIVE : TrayUser::ACTIVE_BUT_DISABLED; + + if (!is_user_card_button_) + return TrayUser::SHOWN; + + return static_cast<ButtonFromView*>(user_card_view_)->is_hovered_for_test() + ? TrayUser::HOVERED + : TrayUser::SHOWN; +} + +gfx::Rect UserView::GetBoundsInScreenOfUserButtonForTest() { + DCHECK(user_card_view_); + return user_card_view_->GetBoundsInScreen(); +} + +bool UserView::IsActiveUser() const { + return user_index_ == 0; +} + +int UserView::GetHeightForWidth(int width) const { + return GetPreferredSize().height(); +} + +void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (sender == logout_button_) { + WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_SIGN_OUT); + RemoveAddUserMenuOption(); + WmShell::Get()->system_tray_controller()->SignOut(); + } else if (sender == user_card_view_ && + IsMultiProfileSupportedAndUserActive()) { + if (IsActiveUser()) { + ToggleAddUserMenuOption(); + } else { + RemoveAddUserMenuOption(); + SwitchUser(user_index_); + // Since the user list is about to change the system menu should get + // closed. + owner_->system_tray()->CloseSystemBubble(); + } + } else if (add_menu_option_ && + sender->GetWidget() == add_menu_option_.get()) { + RemoveAddUserMenuOption(); + // Let the user add another account to the session. + MultiProfileUMA::RecordSigninUser(MultiProfileUMA::SIGNIN_USER_BY_TRAY); + WmShell::Get()->system_tray_delegate()->ShowUserLogin(); + owner_->system_tray()->CloseSystemBubble(); + } else { + NOTREACHED(); + } +} + +void UserView::OnWillChangeFocus(View* focused_before, View* focused_now) { + if (focused_now) + RemoveAddUserMenuOption(); +} + +void UserView::OnDidChangeFocus(View* focused_before, View* focused_now) { + // Nothing to do here. +} + +void UserView::AddLogoutButton(LoginStatus login) { + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + logout_button_ = TrayPopupUtils::CreateTrayPopupBorderlessButton( + this, user::GetLocalizedSignOutStringForStatus(login, true)); + AddChildView(logout_button_); +} + +void UserView::AddUserCard(LoginStatus login) { + user_card_view_ = new UserCardView(login, -1, user_index_); + // The entry is clickable when no system modal dialog is open and the multi + // profile option is active. + bool clickable = !WmShell::Get()->IsSystemModalWindowOpen() && + IsMultiProfileSupportedAndUserActive(); + if (clickable) { + views::View* contents_view = user_card_view_; + auto* button = + new ButtonFromView(contents_view, this, + IsActiveUser() ? TrayPopupInkDropStyle::INSET_BOUNDS + : TrayPopupInkDropStyle::FILL_BOUNDS); + user_card_view_ = button; + is_user_card_button_ = true; + } + AddChildViewAt(user_card_view_, 0); +} + +void UserView::ToggleAddUserMenuOption() { + if (add_menu_option_) { + RemoveAddUserMenuOption(); + return; + } + + // Note: We do not need to install a global event handler to delete this + // item since it will destroyed automatically before the menu / user menu item + // gets destroyed.. + add_menu_option_.reset(new views::Widget); + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_TOOLTIP; + params.keep_on_top = true; + params.accept_events = true; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.name = "AddUserMenuOption"; + WmWindow::Get(GetWidget()->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + add_menu_option_.get(), kShellWindowId_DragImageAndTooltipContainer, + ¶ms); + add_menu_option_->Init(params); + + const SessionStateDelegate* delegate = + WmShell::Get()->GetSessionStateDelegate(); + const AddUserSessionPolicy add_user_policy = + delegate->GetAddUserSessionPolicy(); + add_user_enabled_ = add_user_policy == AddUserSessionPolicy::ALLOWED; + + // Position the widget on top of the user card view (which is still in the + // system menu). The top half of the widget will be transparent to allow + // the active user to show through. + gfx::Rect bounds = user_card_view_->GetBoundsInScreen(); + bounds.set_width(bounds.width() + kSeparatorWidth); + int row_height = bounds.height(); + + views::View* container = new AddUserWidgetContents( + base::Bind(&UserView::RemoveAddUserMenuOption, base::Unretained(this))); + container->SetBorder(views::CreatePaddedBorder( + views::CreateSolidSidedBorder(0, 0, 0, kSeparatorWidth, kBackgroundColor), + gfx::Insets(row_height, 0, 0, 0))); + views::View* add_user_padding = new views::View(); + add_user_padding->SetBorder(views::CreateSolidSidedBorder( + kMenuSeparatorVerticalPadding, 0, 0, 0, kBackgroundColor)); + views::View* add_user_view = CreateAddUserView(add_user_policy, this); + add_user_padding->AddChildView(add_user_view); + add_user_padding->SetLayoutManager(new views::FillLayout()); + container->AddChildView(add_user_padding); + container->SetLayoutManager(new views::FillLayout()); + add_menu_option_->SetContentsView(container); + + bounds.set_height(container->GetPreferredSize().height()); + add_menu_option_->SetBounds(bounds); + + // Show the content. + add_menu_option_->SetAlwaysOnTop(true); + add_menu_option_->Show(); + + // Install a listener to focus changes so that we can remove the card when + // the focus gets changed. When called through the destruction of the bubble, + // the FocusManager cannot be determined anymore and we remember it here. + focus_manager_ = user_card_view_->GetFocusManager(); + focus_manager_->AddFocusChangeListener(this); +} + +void UserView::RemoveAddUserMenuOption() { + if (!add_menu_option_) + return; + focus_manager_->RemoveFocusChangeListener(this); + focus_manager_ = nullptr; + if (user_card_view_->GetFocusManager()) + user_card_view_->GetFocusManager()->ClearFocus(); + add_menu_option_.reset(); +} + +} // namespace tray +} // namespace ash
diff --git a/ash/common/system/user/user_view.h b/ash/common/system/user/user_view.h new file mode 100644 index 0000000..56d4fb34 --- /dev/null +++ b/ash/common/system/user/user_view.h
@@ -0,0 +1,96 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_USER_USER_VIEW_H_ +#define ASH_COMMON_SYSTEM_USER_USER_VIEW_H_ + +#include <memory> + +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/user/tray_user.h" +#include "ash/public/cpp/session_types.h" +#include "base/macros.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/focus/focus_manager.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/view.h" + +namespace gfx { +class Rect; +} + +namespace views { +class FocusManager; +} + +namespace ash { + +enum class LoginStatus; +class SystemTrayItem; + +namespace tray { + +// The view of a user item in system tray bubble. +class UserView : public views::View, + public views::ButtonListener, + public views::FocusChangeListener { + public: + UserView(SystemTrayItem* owner, LoginStatus login, UserIndex index); + ~UserView() override; + + TrayUser::TestState GetStateForTest() const; + gfx::Rect GetBoundsInScreenOfUserButtonForTest(); + + views::View* user_card_view_for_test() const { return user_card_view_; } + + private: + // Retruns true if |this| view is for the currently active user, i.e. top row. + bool IsActiveUser() const; + + // Overridden from views::View. + int GetHeightForWidth(int width) const override; + + // Overridden from views::ButtonListener. + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + // Overridden from views::FocusChangeListener: + void OnWillChangeFocus(View* focused_before, View* focused_now) override; + void OnDidChangeFocus(View* focused_before, View* focused_now) override; + + void AddLogoutButton(LoginStatus login); + void AddUserCard(LoginStatus login); + + // Create the menu option to add another user. If |disabled| is set the user + // cannot actively click on the item. + void ToggleAddUserMenuOption(); + + // Removes the add user menu option. + void RemoveAddUserMenuOption(); + + const UserIndex user_index_; + views::View* user_card_view_; + + // This is the owner system tray item of this view. + SystemTrayItem* owner_; + + // True if |user_card_view_| is a |ButtonFromView| - otherwise it is only + // a |UserCardView|. + bool is_user_card_button_; + + views::View* logout_button_; + std::unique_ptr<views::Widget> add_menu_option_; + + // False when the add user panel is visible but not activatable. + bool add_user_enabled_; + + // The focus manager which we use to detect focus changes. + views::FocusManager* focus_manager_; + + DISALLOW_COPY_AND_ASSIGN(UserView); +}; + +} // namespace tray +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_USER_USER_VIEW_H_
diff --git a/ash/common/system/web_notification/ash_popup_alignment_delegate.cc b/ash/common/system/web_notification/ash_popup_alignment_delegate.cc new file mode 100644 index 0000000..46b2719 --- /dev/null +++ b/ash/common/system/web_notification/ash_popup_alignment_delegate.cc
@@ -0,0 +1,168 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/web_notification/ash_popup_alignment_delegate.h" + +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/i18n/rtl.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/message_center/message_center_style.h" +#include "ui/message_center/views/message_popup_collection.h" +#include "ui/wm/core/shadow_types.h" + +namespace ash { + +namespace { + +const int kToastMarginX = 7; + +// If there should be no margin for the first item, this value needs to be +// substracted to flush the message to the shelf (the width of the border + +// shadow). +const int kNoToastMarginBorderAndShadowOffset = 2; + +} // namespace + +AshPopupAlignmentDelegate::AshPopupAlignmentDelegate(WmShelf* shelf) + : screen_(NULL), shelf_(shelf), tray_bubble_height_(0) { + shelf_->AddObserver(this); +} + +AshPopupAlignmentDelegate::~AshPopupAlignmentDelegate() { + if (screen_) + screen_->RemoveObserver(this); + WmShell::Get()->RemoveShellObserver(this); + shelf_->RemoveObserver(this); +} + +void AshPopupAlignmentDelegate::StartObserving( + display::Screen* screen, + const display::Display& display) { + screen_ = screen; + work_area_ = display.work_area(); + screen->AddObserver(this); + WmShell::Get()->AddShellObserver(this); + if (tray_bubble_height_ > 0) + UpdateWorkArea(); +} + +void AshPopupAlignmentDelegate::SetTrayBubbleHeight(int height) { + tray_bubble_height_ = height; + + // If the shelf is shown during auto-hide state, the distance from the edge + // should be reduced by the height of shelf's shown height. + if (shelf_->GetVisibilityState() == SHELF_AUTO_HIDE && + shelf_->GetAutoHideState() == SHELF_AUTO_HIDE_SHOWN) { + tray_bubble_height_ -= GetShelfConstant(SHELF_SIZE) - + GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE); + } + + if (tray_bubble_height_ > 0) + tray_bubble_height_ += message_center::kMarginBetweenItems; + else + tray_bubble_height_ = 0; + + DoUpdateIfPossible(); +} + +int AshPopupAlignmentDelegate::GetToastOriginX( + const gfx::Rect& toast_bounds) const { + // In Ash, RTL UI language mirrors the whole ash layout, so the toast + // widgets should be at the bottom-left instead of bottom right. + if (base::i18n::IsRTL()) + return work_area_.x() + kToastMarginX; + + if (IsFromLeft()) + return work_area_.x() + kToastMarginX; + return work_area_.right() - kToastMarginX - toast_bounds.width(); +} + +int AshPopupAlignmentDelegate::GetBaseLine() const { + return work_area_.bottom() - kNoToastMarginBorderAndShadowOffset - + tray_bubble_height_; +} + +gfx::Rect AshPopupAlignmentDelegate::GetWorkArea() const { + gfx::Rect work_area_without_tray_bubble = work_area_; + work_area_without_tray_bubble.set_height( + work_area_without_tray_bubble.height() - tray_bubble_height_); + return work_area_without_tray_bubble; +} + +bool AshPopupAlignmentDelegate::IsTopDown() const { + return false; +} + +bool AshPopupAlignmentDelegate::IsFromLeft() const { + return GetAlignment() == SHELF_ALIGNMENT_LEFT; +} + +void AshPopupAlignmentDelegate::RecomputeAlignment( + const display::Display& display) { + // Nothing needs to be done. +} + +void AshPopupAlignmentDelegate::ConfigureWidgetInitParamsForContainer( + views::Widget* widget, + views::Widget::InitParams* init_params) { + init_params->shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP; + init_params->shadow_elevation = ::wm::ShadowElevation::MEDIUM; + // On ash, popups go in the status container. + shelf_->GetWindow() + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + widget, kShellWindowId_StatusContainer, init_params); +} + +ShelfAlignment AshPopupAlignmentDelegate::GetAlignment() const { + return shelf_->GetAlignment(); +} + +display::Display AshPopupAlignmentDelegate::GetCurrentDisplay() const { + return shelf_->GetWindow()->GetDisplayNearestWindow(); +} + +void AshPopupAlignmentDelegate::UpdateWorkArea() { + work_area_ = shelf_->GetUserWorkAreaBounds(); + DoUpdateIfPossible(); +} + +/////////////////////////////////////////////////////////////////////////////// +// WmShelfObserver: + +void AshPopupAlignmentDelegate::WillChangeVisibilityState( + ShelfVisibilityState new_state) { + UpdateWorkArea(); +} + +void AshPopupAlignmentDelegate::OnAutoHideStateChanged( + ShelfAutoHideState new_state) { + UpdateWorkArea(); +} + +/////////////////////////////////////////////////////////////////////////////// +// display::DisplayObserver: + +void AshPopupAlignmentDelegate::OnDisplayAdded( + const display::Display& new_display) {} + +void AshPopupAlignmentDelegate::OnDisplayRemoved( + const display::Display& old_display) {} + +void AshPopupAlignmentDelegate::OnDisplayMetricsChanged( + const display::Display& display, + uint32_t metrics) { + if (GetCurrentDisplay().id() == display.id()) + UpdateWorkArea(); +} + +} // namespace ash
diff --git a/ash/common/system/web_notification/ash_popup_alignment_delegate.h b/ash/common/system/web_notification/ash_popup_alignment_delegate.h new file mode 100644 index 0000000..920105d --- /dev/null +++ b/ash/common/system/web_notification/ash_popup_alignment_delegate.h
@@ -0,0 +1,94 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ +#define ASH_COMMON_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ + +#include <stdint.h> + +#include "ash/ash_export.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "ash/common/shell_observer.h" +#include "ash/public/cpp/shelf_types.h" +#include "base/macros.h" +#include "ui/display/display_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/message_center/views/popup_alignment_delegate.h" + +namespace display { +class Screen; +} + +namespace ash { + +class AshPopupAlignmentDelegateTest; +class WebNotificationTrayTest; +class WmShelf; + +// The PopupAlignmentDelegate subclass for Ash. It needs to handle alignment of +// the shelf and its autohide state. +class ASH_EXPORT AshPopupAlignmentDelegate + : public message_center::PopupAlignmentDelegate, + public WmShelfObserver, + public ShellObserver, + public display::DisplayObserver { + public: + explicit AshPopupAlignmentDelegate(WmShelf* shelf); + ~AshPopupAlignmentDelegate() override; + + // Start observing the system. + void StartObserving(display::Screen* screen, const display::Display& display); + + // Sets the current height of the system tray bubble (or legacy notification + // bubble) so that web notification toasts can avoid it. + void SetTrayBubbleHeight(int height); + + // Returns the current tray bubble height or 0 if there is no bubble. + int tray_bubble_height_for_test() const { return tray_bubble_height_; } + + // Overridden from message_center::PopupAlignmentDelegate: + int GetToastOriginX(const gfx::Rect& toast_bounds) const override; + int GetBaseLine() const override; + gfx::Rect GetWorkArea() const override; + bool IsTopDown() const override; + bool IsFromLeft() const override; + void RecomputeAlignment(const display::Display& display) override; + void ConfigureWidgetInitParamsForContainer( + views::Widget* widget, + views::Widget::InitParams* init_params) override; + + private: + friend class AshPopupAlignmentDelegateTest; + friend class WebNotificationTrayTest; + + // Get the current alignment of the shelf. + ShelfAlignment GetAlignment() const; + + // Utility function to get the display which should be care about. + display::Display GetCurrentDisplay() const; + + // Compute the new work area. + void UpdateWorkArea(); + + // WmShelfObserver: + void WillChangeVisibilityState(ShelfVisibilityState new_state) override; + void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; + + // Overridden from display::DisplayObserver: + void OnDisplayAdded(const display::Display& new_display) override; + void OnDisplayRemoved(const display::Display& old_display) override; + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t metrics) override; + + display::Screen* screen_; + gfx::Rect work_area_; + WmShelf* shelf_; + int tray_bubble_height_; + + DISALLOW_COPY_AND_ASSIGN(AshPopupAlignmentDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_
diff --git a/ash/common/system/web_notification/web_notification_tray.cc b/ash/common/system/web_notification/web_notification_tray.cc new file mode 100644 index 0000000..59bded4c --- /dev/null +++ b/ash/common/system/web_notification/web_notification_tray.cc
@@ -0,0 +1,662 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/system/web_notification/web_notification_tray.h" + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_bubble_wrapper.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_utils.h" +#include "ash/common/system/web_notification/ash_popup_alignment_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/auto_reset.h" +#include "base/i18n/number_formatting.h" +#include "base/i18n/rtl.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/message_center/message_center_style.h" +#include "ui/message_center/message_center_tray_delegate.h" +#include "ui/message_center/views/message_bubble_base.h" +#include "ui/message_center/views/message_center_bubble.h" +#include "ui/message_center/views/message_popup_collection.h" +#include "ui/strings/grit/ui_strings.h" +#include "ui/views/bubble/tray_bubble_view.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/menu/menu_runner.h" +#include "ui/views/layout/fill_layout.h" + +namespace message_center { + +MessageCenterTrayDelegate* CreateMessageCenterTray() { + // On non-CrOS, the Tray will not be hosted in ash::Shell. + NOTREACHED(); + return nullptr; +} + +} // namespace message_center + +namespace ash { +namespace { + +// Menu commands +constexpr int kToggleQuietMode = 0; +constexpr int kEnableQuietModeDay = 2; + +constexpr int kMaximumSmallIconCount = 3; + +constexpr gfx::Size kTrayItemInnerIconSize(16, 16); +constexpr gfx::Size kTrayItemInnerBellIconSizeNonMd(18, 18); +constexpr gfx::Size kTrayItemOuterSize(26, 26); +constexpr int kTrayMainAxisInset = 3; +constexpr int kTrayCrossAxisInset = 0; + +constexpr int kTrayItemAnimationDurationMS = 200; + +constexpr size_t kMaximumNotificationNumber = 99; + +// Flag to disable animation. Only for testing. +bool disable_animations_for_test = false; +} + +namespace { + +const SkColor kWebNotificationColorNoUnread = + SkColorSetARGB(128, 255, 255, 255); +const SkColor kWebNotificationColorWithUnread = SK_ColorWHITE; +const int kNoUnreadIconSize = 18; + +} // namespace + +// Class to initialize and manage the WebNotificationBubble and +// TrayBubbleWrapper instances for a bubble. +class WebNotificationBubbleWrapper { + public: + // Takes ownership of |bubble| and creates |bubble_wrapper_|. + WebNotificationBubbleWrapper(WebNotificationTray* tray, + TrayBackgroundView* anchor_tray, + message_center::MessageBubbleBase* bubble) { + bubble_.reset(bubble); + views::TrayBubbleView::AnchorAlignment anchor_alignment = + tray->GetAnchorAlignment(); + views::TrayBubbleView::InitParams init_params = + bubble->GetInitParams(anchor_alignment); + views::TrayBubbleView* bubble_view = views::TrayBubbleView::Create( + anchor_tray->GetBubbleAnchor(), tray, &init_params); + bubble_view->set_anchor_view_insets(anchor_tray->GetBubbleAnchorInsets()); + bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_view)); + bubble->InitializeContents(bubble_view); + } + + message_center::MessageBubbleBase* bubble() const { return bubble_.get(); } + + // Convenience accessors. + views::TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); } + + private: + std::unique_ptr<message_center::MessageBubbleBase> bubble_; + std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_; + + DISALLOW_COPY_AND_ASSIGN(WebNotificationBubbleWrapper); +}; + +class WebNotificationItem : public views::View, public gfx::AnimationDelegate { + public: + WebNotificationItem(gfx::AnimationContainer* container, + WebNotificationTray* tray) + : tray_(tray) { + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + views::View::SetVisible(false); + set_owned_by_client(); + + SetLayoutManager(new views::FillLayout); + + animation_.reset(new gfx::SlideAnimation(this)); + animation_->SetContainer(container); + animation_->SetSlideDuration(kTrayItemAnimationDurationMS); + animation_->SetTweenType(gfx::Tween::LINEAR); + } + + void SetVisible(bool set_visible) override { + if (!GetWidget() || disable_animations_for_test) { + views::View::SetVisible(set_visible); + return; + } + + if (!set_visible) { + animation_->Hide(); + AnimationProgressed(animation_.get()); + } else { + animation_->Show(); + AnimationProgressed(animation_.get()); + views::View::SetVisible(true); + } + } + + void HideAndDelete() { + SetVisible(false); + + if (!visible() && !animation_->is_animating()) { + if (parent()) + parent()->RemoveChildView(this); + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); + } else { + delete_after_animation_ = true; + } + } + + protected: + // Overridden from views::View: + gfx::Size GetPreferredSize() const override { + if (!animation_.get() || !animation_->is_animating()) + return kTrayItemOuterSize; + + // Animate the width (or height) when this item shows (or hides) so that + // the icons on the left are shifted with the animation. + // Note that TrayItemView does the same thing. + gfx::Size size = kTrayItemOuterSize; + if (IsHorizontalLayout()) { + size.set_width(std::max( + 1, gfx::ToRoundedInt(size.width() * animation_->GetCurrentValue()))); + } else { + size.set_height(std::max( + 1, gfx::ToRoundedInt(size.height() * animation_->GetCurrentValue()))); + } + return size; + } + + int GetHeightForWidth(int width) const override { + return GetPreferredSize().height(); + } + + bool IsHorizontalLayout() const { + return IsHorizontalAlignment(tray_->shelf_alignment()); + } + + private: + // gfx::AnimationDelegate: + void AnimationProgressed(const gfx::Animation* animation) override { + gfx::Transform transform; + if (IsHorizontalLayout()) { + transform.Translate(0, animation->CurrentValueBetween( + static_cast<double>(height()) / 2., 0.)); + } else { + transform.Translate( + animation->CurrentValueBetween(static_cast<double>(width() / 2.), 0.), + 0); + } + transform.Scale(animation->GetCurrentValue(), animation->GetCurrentValue()); + layer()->SetTransform(transform); + PreferredSizeChanged(); + } + void AnimationEnded(const gfx::Animation* animation) override { + if (animation->GetCurrentValue() < 0.1) + views::View::SetVisible(false); + + if (delete_after_animation_) { + if (parent()) + parent()->RemoveChildView(this); + base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); + } + } + void AnimationCanceled(const gfx::Animation* animation) override { + AnimationEnded(animation); + } + + std::unique_ptr<gfx::SlideAnimation> animation_; + bool delete_after_animation_ = false; + WebNotificationTray* tray_; + + DISALLOW_COPY_AND_ASSIGN(WebNotificationItem); +}; + +class WebNotificationImage : public WebNotificationItem { + public: + WebNotificationImage(const gfx::ImageSkia& image, + const gfx::Size& size, + gfx::AnimationContainer* container, + WebNotificationTray* tray) + : WebNotificationItem(container, tray) { + view_ = new views::ImageView(); + view_->SetImage(image); + view_->SetImageSize(size); + AddChildView(view_); + } + + private: + views::ImageView* view_; + + DISALLOW_COPY_AND_ASSIGN(WebNotificationImage); +}; + +class WebNotificationLabel : public WebNotificationItem { + public: + WebNotificationLabel(gfx::AnimationContainer* container, + WebNotificationTray* tray) + : WebNotificationItem(container, tray) { + view_ = new views::Label(); + SetupLabelForTray(view_); + AddChildView(view_); + } + + void SetNotificationCount(bool small_icons_exist, size_t notification_count) { + notification_count = std::min(notification_count, + kMaximumNotificationNumber); // cap with 99 + + // TODO(yoshiki): Use a string for "99" and "+99". + + base::string16 str = base::FormatNumber(notification_count); + if (small_icons_exist) { + if (!base::i18n::IsRTL()) + str = base::ASCIIToUTF16("+") + str; + else + str = str + base::ASCIIToUTF16("+"); + } + + view_->SetText(str); + view_->SetEnabledColor(kWebNotificationColorWithUnread); + SchedulePaint(); + } + + private: + views::Label* view_; + + DISALLOW_COPY_AND_ASSIGN(WebNotificationLabel); +}; + +WebNotificationTray::WebNotificationTray(WmShelf* shelf, + WmWindow* status_area_window, + SystemTray* system_tray) + : TrayBackgroundView(shelf), + status_area_window_(status_area_window), + system_tray_(system_tray), + show_message_center_on_unlock_(false), + should_update_tray_content_(false), + should_block_shelf_auto_hide_(false) { + DCHECK(shelf); + DCHECK(status_area_window_); + DCHECK(system_tray_); + + if (MaterialDesignController::IsShelfMaterial()) { + SetInkDropMode(InkDropMode::ON); + SetContentsBackground(false); + gfx::ImageSkia bell_image = + CreateVectorIcon(kShelfNotificationsIcon, kShelfIconColor); + const gfx::Size bell_icon_size = kTrayItemInnerIconSize; + bell_icon_.reset(new WebNotificationImage( + bell_image, bell_icon_size, animation_container_.get(), this)); + } else { + SetContentsBackground(true); + gfx::ImageSkia bell_image = + CreateVectorIcon(gfx::VectorIconId::NOTIFICATIONS, kNoUnreadIconSize, + kWebNotificationColorNoUnread); + const gfx::Size bell_icon_size = kTrayItemInnerBellIconSizeNonMd; + bell_icon_.reset(new WebNotificationImage( + bell_image, bell_icon_size, animation_container_.get(), this)); + } + tray_container()->AddChildView(bell_icon_.get()); + + counter_.reset(new WebNotificationLabel(animation_container_.get(), this)); + tray_container()->AddChildView(counter_.get()); + + message_center_tray_.reset(new message_center::MessageCenterTray( + this, message_center::MessageCenter::Get())); + popup_alignment_delegate_.reset(new AshPopupAlignmentDelegate(shelf)); + popup_collection_.reset(new message_center::MessagePopupCollection( + message_center(), message_center_tray_.get(), + popup_alignment_delegate_.get())); + const display::Display& display = + status_area_window_->GetDisplayNearestWindow(); + popup_alignment_delegate_->StartObserving(display::Screen::GetScreen(), + display); + OnMessageCenterTrayChanged(); + + tray_container()->SetMargin(kTrayMainAxisInset, kTrayCrossAxisInset); +} + +WebNotificationTray::~WebNotificationTray() { + // Release any child views that might have back pointers before ~View(). + message_center_bubble_.reset(); + popup_alignment_delegate_.reset(); + popup_collection_.reset(); +} + +// static +void WebNotificationTray::DisableAnimationsForTest(bool disable) { + disable_animations_for_test = disable; +} + +// Public methods. + +bool WebNotificationTray::ShowMessageCenterInternal(bool show_settings) { + if (!ShouldShowMessageCenter()) + return false; + + should_block_shelf_auto_hide_ = true; + message_center::MessageCenterBubble* message_center_bubble = + new message_center::MessageCenterBubble(message_center(), + message_center_tray_.get()); + + // In the horizontal case, message center starts from the top of the shelf. + // In the vertical case, it starts from the bottom of WebNotificationTray. + const int max_height = IsHorizontalAlignment(shelf_alignment()) + ? shelf()->GetIdealBounds().y() + : GetBoundsInScreen().bottom(); + message_center_bubble->SetMaxHeight(max_height); + + if (show_settings) + message_center_bubble->SetSettingsVisible(); + + // For vertical shelf alignments, anchor to the WebNotificationTray, but for + // horizontal (i.e. bottom) shelves, anchor to the system tray. + TrayBackgroundView* anchor_tray = this; + if (IsHorizontalAlignment(shelf_alignment())) { + anchor_tray = WmShelf::ForWindow(status_area_window_) + ->GetStatusAreaWidget() + ->system_tray(); + } + + message_center_bubble_.reset(new WebNotificationBubbleWrapper( + this, anchor_tray, message_center_bubble)); + + shelf()->UpdateAutoHideState(); + SetIsActive(true); + return true; +} + +bool WebNotificationTray::ShowMessageCenter() { + return ShowMessageCenterInternal(false /* show_settings */); +} + +void WebNotificationTray::HideMessageCenter() { + if (!message_center_bubble()) + return; + SetIsActive(false); + message_center_bubble_.reset(); + should_block_shelf_auto_hide_ = false; + show_message_center_on_unlock_ = false; + shelf()->UpdateAutoHideState(); +} + +void WebNotificationTray::SetTrayBubbleHeight(int height) { + popup_alignment_delegate_->SetTrayBubbleHeight(height); +} + +int WebNotificationTray::tray_bubble_height_for_test() const { + return popup_alignment_delegate_->tray_bubble_height_for_test(); +} + +bool WebNotificationTray::ShowPopups() { + if (message_center_bubble()) + return false; + + popup_collection_->DoUpdateIfPossible(); + return true; +} + +void WebNotificationTray::HidePopups() { + DCHECK(popup_collection_.get()); + popup_collection_->MarkAllPopupsShown(); +} + +// Private methods. + +bool WebNotificationTray::ShouldShowMessageCenter() { + return WmShell::Get()->system_tray_delegate()->ShouldShowNotificationTray(); +} + +bool WebNotificationTray::ShouldBlockShelfAutoHide() const { + return should_block_shelf_auto_hide_; +} + +bool WebNotificationTray::IsMessageCenterBubbleVisible() const { + return (message_center_bubble() && + message_center_bubble()->bubble()->IsVisible()); +} + +void WebNotificationTray::ShowMessageCenterBubble() { + if (!IsMessageCenterBubbleVisible()) + message_center_tray_->ShowMessageCenterBubble(); +} + +void WebNotificationTray::UpdateAfterLoginStatusChange( + LoginStatus login_status) { + message_center()->SetLockedState(login_status == LoginStatus::LOCKED); + OnMessageCenterTrayChanged(); +} + +void WebNotificationTray::SetShelfAlignment(ShelfAlignment alignment) { + if (alignment == shelf_alignment()) + return; + TrayBackgroundView::SetShelfAlignment(alignment); + // Destroy any existing bubble so that it will be rebuilt correctly. + message_center_tray_->HideMessageCenterBubble(); + message_center_tray_->HidePopupBubble(); +} + +void WebNotificationTray::AnchorUpdated() { + if (message_center_bubble()) { + message_center_bubble()->bubble_view()->UpdateBubble(); + UpdateBubbleViewArrow(message_center_bubble()->bubble_view()); + } +} + +base::string16 WebNotificationTray::GetAccessibleNameForTray() { + return l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_ACCESSIBLE_NAME); +} + +void WebNotificationTray::HideBubbleWithView( + const views::TrayBubbleView* bubble_view) { + if (message_center_bubble() && + bubble_view == message_center_bubble()->bubble_view()) { + message_center_tray_->HideMessageCenterBubble(); + } else if (popup_collection_.get()) { + message_center_tray_->HidePopupBubble(); + } +} + +bool WebNotificationTray::PerformAction(const ui::Event& event) { + if (message_center_bubble()) + message_center_tray_->HideMessageCenterBubble(); + else + message_center_tray_->ShowMessageCenterBubble(); + return true; +} + +void WebNotificationTray::BubbleViewDestroyed() { + if (message_center_bubble()) + message_center_bubble()->bubble()->BubbleViewDestroyed(); +} + +void WebNotificationTray::OnMouseEnteredView() {} + +void WebNotificationTray::OnMouseExitedView() {} + +base::string16 WebNotificationTray::GetAccessibleNameForBubble() { + return GetAccessibleNameForTray(); +} + +void WebNotificationTray::OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const { + // Place the bubble in the same root window as |anchor_widget|. + WmWindow::Get(anchor_widget->GetNativeWindow()) + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + bubble_widget, kShellWindowId_SettingBubbleContainer, params); +} + +void WebNotificationTray::HideBubble(const views::TrayBubbleView* bubble_view) { + HideBubbleWithView(bubble_view); +} + +bool WebNotificationTray::ShowNotifierSettings() { + if (message_center_bubble()) { + static_cast<message_center::MessageCenterBubble*>( + message_center_bubble()->bubble()) + ->SetSettingsVisible(); + return true; + } + return ShowMessageCenterInternal(true /* show_settings */); +} + +bool WebNotificationTray::IsContextMenuEnabled() const { + return IsLoggedIn(); +} + +message_center::MessageCenterTray* WebNotificationTray::GetMessageCenterTray() { + return message_center_tray_.get(); +} + +bool WebNotificationTray::IsCommandIdChecked(int command_id) const { + if (command_id != kToggleQuietMode) + return false; + return message_center()->IsQuietMode(); +} + +bool WebNotificationTray::IsCommandIdEnabled(int command_id) const { + return true; +} + +void WebNotificationTray::ExecuteCommand(int command_id, int event_flags) { + if (command_id == kToggleQuietMode) { + bool in_quiet_mode = message_center()->IsQuietMode(); + message_center()->SetQuietMode(!in_quiet_mode); + return; + } + base::TimeDelta expires_in = command_id == kEnableQuietModeDay + ? base::TimeDelta::FromDays(1) + : base::TimeDelta::FromHours(1); + message_center()->EnterQuietModeWithExpire(expires_in); +} + +void WebNotificationTray::OnMessageCenterTrayChanged() { + // Do not update the tray contents directly. Multiple change events can happen + // consecutively, and calling Update in the middle of those events will show + // intermediate unread counts for a moment. + should_update_tray_content_ = true; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&WebNotificationTray::UpdateTrayContent, AsWeakPtr())); +} + +void WebNotificationTray::UpdateTrayContent() { + if (!should_update_tray_content_) + return; + should_update_tray_content_ = false; + + std::unordered_set<std::string> notification_ids; + for (auto pair : visible_small_icons_) + notification_ids.insert(pair.first); + + // Add small icons (up to kMaximumSmallIconCount = 3). + message_center::MessageCenter* message_center = + message_center_tray_->message_center(); + size_t visible_small_icon_count = 0; + for (const auto* notification : message_center->GetVisibleNotifications()) { + gfx::Image image = notification->small_image(); + if (image.IsEmpty()) + continue; + + if (visible_small_icon_count >= kMaximumSmallIconCount) + break; + visible_small_icon_count++; + + notification_ids.erase(notification->id()); + if (visible_small_icons_.count(notification->id()) != 0) + continue; + + auto* item = + new WebNotificationImage(image.AsImageSkia(), kTrayItemInnerIconSize, + animation_container_.get(), this); + visible_small_icons_.insert(std::make_pair(notification->id(), item)); + + tray_container()->AddChildViewAt(item, 0); + item->SetVisible(true); + } + + // Remove unnecessary icons. + for (const std::string& id : notification_ids) { + WebNotificationImage* item = visible_small_icons_[id]; + visible_small_icons_.erase(id); + item->HideAndDelete(); + } + + // Show or hide the bell icon. + size_t visible_notification_count = message_center->NotificationCount(); + bell_icon_->SetVisible(visible_notification_count == 0); + + // Show or hide the counter. + size_t hidden_icon_count = + visible_notification_count - visible_small_icon_count; + if (hidden_icon_count != 0) { + counter_->SetVisible(true); + counter_->SetNotificationCount( + (visible_small_icon_count != 0), // small_icons_exist + hidden_icon_count); + } else { + counter_->SetVisible(false); + } + + SetVisible(IsLoggedIn() && ShouldShowMessageCenter()); + PreferredSizeChanged(); + Layout(); + SchedulePaint(); + if (IsLoggedIn()) + system_tray_->SetNextFocusableView(this); +} + +void WebNotificationTray::ClickedOutsideBubble() { + // Only hide the message center + if (!message_center_bubble()) + return; + + message_center_tray_->HideMessageCenterBubble(); +} + +message_center::MessageCenter* WebNotificationTray::message_center() const { + return message_center_tray_->message_center(); +} + +bool WebNotificationTray::IsLoggedIn() const { + WmShell* shell = WmShell::Get(); + return shell->system_tray_delegate()->GetUserLoginStatus() != + LoginStatus::NOT_LOGGED_IN && + !shell->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); +} + +// Methods for testing + +bool WebNotificationTray::IsPopupVisible() const { + return message_center_tray_->popups_visible(); +} + +message_center::MessageCenterBubble* +WebNotificationTray::GetMessageCenterBubbleForTest() { + if (!message_center_bubble()) + return nullptr; + return static_cast<message_center::MessageCenterBubble*>( + message_center_bubble()->bubble()); +} + +} // namespace ash
diff --git a/ash/common/system/web_notification/web_notification_tray.h b/ash/common/system/web_notification/web_notification_tray.h new file mode 100644 index 0000000..ce64dd8a --- /dev/null +++ b/ash/common/system/web_notification/web_notification_tray.h
@@ -0,0 +1,190 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_ +#define ASH_COMMON_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/login_status.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "ui/base/models/simple_menu_model.h" +#include "ui/gfx/animation/animation_container.h" +#include "ui/message_center/message_center_tray.h" +#include "ui/message_center/message_center_tray_delegate.h" +#include "ui/views/bubble/tray_bubble_view.h" + +// Status area tray for showing browser and app notifications. This hosts +// a MessageCenter class which manages the notification list. This class +// contains the Ash specific tray implementation. +// +// Note: These are not related to system notifications (i.e NotificationView +// generated by SystemTrayItem). Visibility of one notification type or other +// is controlled by StatusAreaWidget. + +namespace message_center { +class MessageCenter; +class MessageCenterBubble; +class MessagePopupCollection; +} + +namespace ash { +class AshPopupAlignmentDelegate; +class SystemTray; +class WebNotificationBubbleWrapper; +class WebNotificationImage; +class WebNotificationLabel; +class WmWindow; + +class ASH_EXPORT WebNotificationTray + : public TrayBackgroundView, + public views::TrayBubbleView::Delegate, + public message_center::MessageCenterTrayDelegate, + public base::SupportsWeakPtr<WebNotificationTray>, + public ui::SimpleMenuModel::Delegate { + public: + WebNotificationTray(WmShelf* shelf, + WmWindow* status_area_window, + SystemTray* system_tray); + ~WebNotificationTray() override; + + static void DisableAnimationsForTest(bool disable); + + // Sets the height of the system tray bubble (or legacy notification bubble) + // from the edge of the work area so that the web notification popups don't + // overlap with the tray. Pass 0 if no bubble is shown. + void SetTrayBubbleHeight(int height); + + // Returns the current tray bubble height or 0 if there is no bubble. + int tray_bubble_height_for_test() const; + + // Returns true if it should block the auto hide behavior of the shelf. + bool ShouldBlockShelfAutoHide() const; + + // Returns true if the message center bubble is visible. + bool IsMessageCenterBubbleVisible() const; + + // Shows the message center bubble. + void ShowMessageCenterBubble(); + + // Called when the login status is changed. + void UpdateAfterLoginStatusChange(LoginStatus login_status); + + // Overridden from TrayBackgroundView. + void SetShelfAlignment(ShelfAlignment alignment) override; + void AnchorUpdated() override; + base::string16 GetAccessibleNameForTray() override; + void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; + void ClickedOutsideBubble() override; + + // Overridden from ActionableView. + bool PerformAction(const ui::Event& event) override; + + // Overridden from views::TrayBubbleView::Delegate. + void BubbleViewDestroyed() override; + void OnMouseEnteredView() override; + void OnMouseExitedView() override; + base::string16 GetAccessibleNameForBubble() override; + void OnBeforeBubbleWidgetInit( + views::Widget* anchor_widget, + views::Widget* bubble_widget, + views::Widget::InitParams* params) const override; + void HideBubble(const views::TrayBubbleView* bubble_view) override; + + // Overridden from MessageCenterTrayDelegate. + void OnMessageCenterTrayChanged() override; + bool ShowMessageCenter() override; + void HideMessageCenter() override; + bool ShowPopups() override; + void HidePopups() override; + bool ShowNotifierSettings() override; + bool IsContextMenuEnabled() const override; + message_center::MessageCenterTray* GetMessageCenterTray() override; + + // Overridden from ui::SimpleMenuModel::Delegate. + bool IsCommandIdChecked(int command_id) const override; + bool IsCommandIdEnabled(int command_id) const override; + void ExecuteCommand(int command_id, int event_flags) override; + + message_center::MessageCenter* message_center() const; + + private: + friend class WebNotificationTrayTest; + + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotifications); + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotificationPopupBubble); + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, + ManyMessageCenterNotifications); + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, ManyPopupNotifications); + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupShownOnBothDisplays); + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupAndSystemTray); + FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupAndAutoHideShelf); + + void UpdateTrayContent(); + + // The actual process to show the message center. Set |show_settings| to true + // if the message center should be initialized with the settings visible. + // Returns true if the center is successfully created. + bool ShowMessageCenterInternal(bool show_settings); + + // Queries login status and the status area widget to determine visibility of + // the message center. + bool ShouldShowMessageCenter(); + + // Returns true if it should show the quiet mode menu. + bool ShouldShowQuietModeMenu(const ui::Event& event); + + // Shows the quiet mode menu. + void ShowQuietModeMenu(const ui::Event& event); + + // Creates the menu model for quiet mode and returns it. + ui::MenuModel* CreateQuietModeMenu(); + + WebNotificationBubbleWrapper* message_center_bubble() const { + return message_center_bubble_.get(); + } + + // Returns true if any user is logged in and the system is not at the screen + // for adding a secondary user. + bool IsLoggedIn() const; + + // Testing accessors. + bool IsPopupVisible() const; + message_center::MessageCenterBubble* GetMessageCenterBubbleForTest(); + + WmWindow* status_area_window_; + SystemTray* system_tray_; + std::unique_ptr<message_center::MessageCenterTray> message_center_tray_; + std::unique_ptr<WebNotificationBubbleWrapper> message_center_bubble_; + std::unique_ptr<message_center::MessagePopupCollection> popup_collection_; + std::unique_ptr<WebNotificationImage> bell_icon_; + std::unique_ptr<WebNotificationLabel> counter_; + + scoped_refptr<gfx::AnimationContainer> animation_container_ = + new gfx::AnimationContainer(); + + std::unordered_map<std::string, WebNotificationImage*> visible_small_icons_; + + bool show_message_center_on_unlock_; + + bool should_update_tray_content_; + + // True when the shelf auto hide behavior has to be blocked. Previously + // this was done by checking |message_center_bubble_| but actually + // the check can be called when creating this object, so it would cause + // flickers of the shelf from hidden to shown. See: crbug.com/181213 + bool should_block_shelf_auto_hide_; + + std::unique_ptr<AshPopupAlignmentDelegate> popup_alignment_delegate_; + + DISALLOW_COPY_AND_ASSIGN(WebNotificationTray); +}; + +} // namespace ash + +#endif // ASH_COMMON_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
diff --git a/ash/common/test/ash_test.cc b/ash/common/test/ash_test.cc new file mode 100644 index 0000000..ba087ec2 --- /dev/null +++ b/ash/common/test/ash_test.cc
@@ -0,0 +1,143 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/ash_test.h" + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/test/ash_test_impl.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "ui/compositor/layer_type.h" +#include "ui/display/display.h" + +namespace ash { + +WindowOwner::WindowOwner(WmWindow* window) : window_(window) {} + +WindowOwner::~WindowOwner() { + window_->Destroy(); +} + +AshTest::AshTest() : test_impl_(AshTestImpl::Create()) {} + +AshTest::~AshTest() {} + +// static +WmShelf* AshTest::GetPrimaryShelf() { + return WmShell::Get() + ->GetPrimaryRootWindow() + ->GetRootWindowController() + ->GetShelf(); +} + +// static +SystemTray* AshTest::GetPrimarySystemTray() { + return GetPrimaryShelf()->GetStatusAreaWidget()->system_tray(); +} + +// static +test::TestSystemTrayDelegate* AshTest::GetSystemTrayDelegate() { + return static_cast<test::TestSystemTrayDelegate*>( + WmShell::Get()->system_tray_delegate()); +} + +void AshTest::UpdateDisplay(const std::string& display_spec) { + return test_impl_->UpdateDisplay(display_spec); +} + +std::unique_ptr<WindowOwner> AshTest::CreateTestWindow(const gfx::Rect& bounds, + ui::wm::WindowType type, + int shell_window_id) { + return test_impl_->CreateTestWindow(bounds, type, shell_window_id); +} + +std::unique_ptr<WindowOwner> AshTest::CreateToplevelTestWindow( + const gfx::Rect& bounds_in_screen, + int shell_window_id) { + return test_impl_->CreateToplevelTestWindow(bounds_in_screen, + shell_window_id); +} + +std::unique_ptr<WindowOwner> AshTest::CreateChildWindow(WmWindow* parent, + const gfx::Rect& bounds, + int shell_window_id) { + std::unique_ptr<WindowOwner> window_owner = + base::MakeUnique<WindowOwner>(WmShell::Get()->NewWindow( + ui::wm::WINDOW_TYPE_NORMAL, ui::LAYER_NOT_DRAWN)); + window_owner->window()->SetBounds(bounds); + window_owner->window()->SetShellWindowId(shell_window_id); + parent->AddChild(window_owner->window()); + window_owner->window()->Show(); + return window_owner; +} + +// static +std::unique_ptr<views::Widget> AshTest::CreateTestWidget( + const gfx::Rect& bounds, + views::WidgetDelegate* delegate, + int container_id) { + std::unique_ptr<views::Widget> widget(new views::Widget); + views::Widget::InitParams params; + params.delegate = delegate; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = bounds; + WmShell::Get() + ->GetPrimaryRootWindow() + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer(widget.get(), container_id, + ¶ms); + widget->Init(params); + widget->Show(); + return widget; +} + +display::Display AshTest::GetSecondaryDisplay() { + return test_impl_->GetSecondaryDisplay(); +} + +bool AshTest::SetSecondaryDisplayPlacement( + display::DisplayPlacement::Position position, + int offset) { + if (WmShell::Get()->IsRunningInMash()) { + NOTIMPLEMENTED(); + return false; + } + return test_impl_->SetSecondaryDisplayPlacement(position, offset); +} + +void AshTest::ConfigureWidgetInitParamsForDisplay( + WmWindow* window, + views::Widget::InitParams* init_params) { + test_impl_->ConfigureWidgetInitParamsForDisplay(window, init_params); +} + +void AshTest::ParentWindowInPrimaryRootWindow(WmWindow* window) { + window->SetParentUsingContext(WmShell::Get()->GetPrimaryRootWindow(), + gfx::Rect()); +} + +void AshTest::AddTransientChild(WmWindow* parent, WmWindow* window) { + test_impl_->AddTransientChild(parent, window); +} + +void AshTest::RunAllPendingInMessageLoop() { + base::RunLoop run_loop; + run_loop.RunUntilIdle(); +} + +void AshTest::SetUp() { + test_impl_->SetUp(); +} + +void AshTest::TearDown() { + test_impl_->TearDown(); +} + +} // namespace ash
diff --git a/ash/common/test/ash_test.h b/ash/common/test/ash_test.h new file mode 100644 index 0000000..d91c4d6 --- /dev/null +++ b/ash/common/test/ash_test.h
@@ -0,0 +1,149 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_ASH_TEST_H_ +#define ASH_COMMON_TEST_ASH_TEST_H_ + +#include <memory> +#include <string> + +#include "ash/public/cpp/shell_window_ids.h" +#include "base/macros.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/display/display_layout.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/widget/widget.h" +#include "ui/wm/public/window_types.h" + +namespace display { +class Display; +} + +namespace views { +class WidgetDelegate; +} + +namespace ash { + +class AshTestImpl; +class SystemTray; +class WmShelf; +class WmWindow; + +namespace test { +class TestSystemTrayDelegate; +} + +// Wraps a WmWindow calling WmWindow::Destroy() from the destructor. WmWindow is +// owned by the corresponding window implementation. The only way to delete +// WmWindow is to call WmWindow::Destroy(), which deletes the corresponding +// window, then the WmWindow. This class calls WmWindow::Destroy() from its +// destructor. +class WindowOwner { + public: + explicit WindowOwner(WmWindow* window); + ~WindowOwner(); + + WmWindow* window() { return window_; } + + private: + WmWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(WindowOwner); +}; + +// Base class for ash tests. This class calls through to AshTestImpl for the +// real implementation. This class exists so that tests can be written to +// ash/common and run in both mus and aura. +// +// The implementation of AshTestImpl that is used depends upon gn targets. To +// use the aura backend depend on "//ash/test:ash_with_aura_test_support." The +// mus backend is not provided as a separate link target. +class AshTest : public testing::Test { + public: + AshTest(); + ~AshTest() override; + + // Returns the WmShelf for the primary display. + static WmShelf* GetPrimaryShelf(); + + // Returns the system tray on the primary display. + static SystemTray* GetPrimarySystemTray(); + + static test::TestSystemTrayDelegate* GetSystemTrayDelegate(); + + // Update the display configuration as given in |display_spec|. + // See test::DisplayManagerTestApi::UpdateDisplay for more details. + void UpdateDisplay(const std::string& display_spec); + + // Creates a visible window in the appropriate container. If + // |bounds_in_screen| is empty the window is added to the primary root + // window, otherwise the window is added to the display matching + // |bounds_in_screen|. |shell_window_id| is the shell window id to give to + // the new window. + std::unique_ptr<WindowOwner> CreateTestWindow( + const gfx::Rect& bounds_in_screen = gfx::Rect(), + ui::wm::WindowType type = ui::wm::WINDOW_TYPE_NORMAL, + int shell_window_id = kShellWindowId_Invalid); + + // Creates a visible top-level window. For aura a top-level window is a Window + // that has a delegate, see aura::Window::GetToplevelWindow() for more + // details. + std::unique_ptr<WindowOwner> CreateToplevelTestWindow( + const gfx::Rect& bounds_in_screen = gfx::Rect(), + int shell_window_id = kShellWindowId_Invalid); + + // Creates a visible window parented to |parent| with the specified bounds and + // id. + std::unique_ptr<WindowOwner> CreateChildWindow( + WmWindow* parent, + const gfx::Rect& bounds = gfx::Rect(), + int shell_window_id = kShellWindowId_Invalid); + + // Creates and shows a widget. See ash/public/cpp/shell_window_ids.h for + // values for |container_id|. + static std::unique_ptr<views::Widget> CreateTestWidget( + const gfx::Rect& bounds, + views::WidgetDelegate* delegate = nullptr, + int container_id = kShellWindowId_DefaultContainer); + + // Returns the Display for the secondary display. It's assumed there are two + // displays. + display::Display GetSecondaryDisplay(); + + // Sets the placement of the secondary display. Returns true if the secondary + // display can be moved, false otherwise. The false return value is temporary + // until mus fully supports this. + bool SetSecondaryDisplayPlacement( + display::DisplayPlacement::Position position, + int offset); + + // Configures |init_params| so that the widget will be created on the same + // display as |window|. + void ConfigureWidgetInitParamsForDisplay( + WmWindow* window, + views::Widget::InitParams* init_params); + + // Adds |window| to the appropriate container in the primary root window. + void ParentWindowInPrimaryRootWindow(WmWindow* window); + + // Adds |window| as as a transient child of |parent|. + void AddTransientChild(WmWindow* parent, WmWindow* window); + + void RunAllPendingInMessageLoop(); + + protected: + // testing::Test: + void SetUp() override; + void TearDown() override; + + private: + std::unique_ptr<AshTestImpl> test_impl_; + + DISALLOW_COPY_AND_ASSIGN(AshTest); +}; + +} // namespace ash + +#endif // ASH_COMMON_TEST_ASH_TEST_H_
diff --git a/ash/common/test/ash_test_impl.h b/ash/common/test/ash_test_impl.h new file mode 100644 index 0000000..8984dfbf --- /dev/null +++ b/ash/common/test/ash_test_impl.h
@@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_ASH_TEST_IMPL_H_ +#define ASH_COMMON_TEST_ASH_TEST_IMPL_H_ + +#include <memory> +#include <string> + +#include "ui/display/display_layout.h" +#include "ui/views/widget/widget.h" +#include "ui/wm/public/window_types.h" + +namespace display { +class Display; +} + +namespace gfx { +class Rect; +} + +namespace ash { + +class WindowOwner; +class WmWindow; + +// Provides the real implementation of AshTest, see it for details. +class AshTestImpl { + public: + virtual ~AshTestImpl() {} + + // Factory function for creating AshTestImpl. Implemention that is used + // depends upon build dependencies. + static std::unique_ptr<AshTestImpl> Create(); + + // These functions mirror that of AshTest, see it for details. + virtual void SetUp() = 0; + virtual void TearDown() = 0; + virtual void UpdateDisplay(const std::string& display_spec) = 0; + virtual std::unique_ptr<WindowOwner> CreateTestWindow( + const gfx::Rect& bounds_in_screen, + ui::wm::WindowType type, + int shell_window_id) = 0; + virtual std::unique_ptr<WindowOwner> CreateToplevelTestWindow( + const gfx::Rect& bounds_in_screen, + int shell_window_id) = 0; + virtual display::Display GetSecondaryDisplay() = 0; + virtual bool SetSecondaryDisplayPlacement( + display::DisplayPlacement::Position position, + int offset) = 0; + virtual void ConfigureWidgetInitParamsForDisplay( + WmWindow* window, + views::Widget::InitParams* init_params) = 0; + virtual void AddTransientChild(WmWindow* parent, WmWindow* window) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_TEST_ASH_TEST_IMPL_H_
diff --git a/ash/common/test/test_palette_delegate.cc b/ash/common/test/test_palette_delegate.cc new file mode 100644 index 0000000..ab5692f --- /dev/null +++ b/ash/common/test/test_palette_delegate.cc
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/test_palette_delegate.h" + +namespace ash { + +TestPaletteDelegate::TestPaletteDelegate() {} + +TestPaletteDelegate::~TestPaletteDelegate() {} + +std::unique_ptr<PaletteDelegate::EnableListenerSubscription> +TestPaletteDelegate::AddPaletteEnableListener( + const EnableListener& on_state_changed) { + return nullptr; +} + +void TestPaletteDelegate::CreateNote() { + ++create_note_count_; +} + +bool TestPaletteDelegate::HasNoteApp() { + ++has_note_app_count_; + return has_note_app_; +} + +bool TestPaletteDelegate::ShouldAutoOpenPalette() { + return should_auto_open_palette_; +} + +bool TestPaletteDelegate::ShouldShowPalette() { + return should_show_palette_; +} + +void TestPaletteDelegate::TakeScreenshot() { + ++take_screenshot_count_; +} + +void TestPaletteDelegate::TakePartialScreenshot(const base::Closure& done) { + ++take_partial_screenshot_count_; + partial_screenshot_done_ = done; +} + +void TestPaletteDelegate::CancelPartialScreenshot() {} + +} // namespace ash
diff --git a/ash/common/test/test_palette_delegate.h b/ash/common/test/test_palette_delegate.h new file mode 100644 index 0000000..f0fc5e55 --- /dev/null +++ b/ash/common/test/test_palette_delegate.h
@@ -0,0 +1,69 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_TEST_PALETTE_DELEGATE_H_ +#define ASH_COMMON_TEST_TEST_PALETTE_DELEGATE_H_ + +#include "ash/common/palette_delegate.h" +#include "base/macros.h" + +namespace ash { + +// A simple test double for a PaletteDelegate. +class TestPaletteDelegate : public PaletteDelegate { + public: + TestPaletteDelegate(); + ~TestPaletteDelegate() override; + + int create_note_count() const { return create_note_count_; } + + int has_note_app_count() const { return has_note_app_count_; } + + int take_screenshot_count() const { return take_screenshot_count_; } + + int take_partial_screenshot_count() const { + return take_partial_screenshot_count_; + } + + base::Closure partial_screenshot_done() const { + return partial_screenshot_done_; + } + + void set_has_note_app(bool has_note_app) { has_note_app_ = has_note_app; } + + void set_should_auto_open_palette(bool should_auto_open_palette) { + should_auto_open_palette_ = should_auto_open_palette; + } + + void set_should_show_palette(bool should_show_palette) { + should_show_palette_ = should_show_palette; + } + + private: + // PaletteDelegate: + std::unique_ptr<EnableListenerSubscription> AddPaletteEnableListener( + const EnableListener& on_state_changed) override; + void CreateNote() override; + bool HasNoteApp() override; + bool ShouldAutoOpenPalette() override; + bool ShouldShowPalette() override; + void TakeScreenshot() override; + void TakePartialScreenshot(const base::Closure& done) override; + void CancelPartialScreenshot() override; + + int create_note_count_ = 0; + int has_note_app_count_ = 0; + int take_screenshot_count_ = 0; + int take_partial_screenshot_count_ = 0; + base::Closure partial_screenshot_done_; + bool has_note_app_ = false; + bool should_auto_open_palette_ = false; + bool should_show_palette_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestPaletteDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_TEST_TEST_PALETTE_DELEGATE_H_
diff --git a/ash/common/test/test_session_state_delegate.cc b/ash/common/test/test_session_state_delegate.cc new file mode 100644 index 0000000..265c048 --- /dev/null +++ b/ash/common/test/test_session_state_delegate.cc
@@ -0,0 +1,253 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/test_session_state_delegate.h" + +#include <algorithm> +#include <string> + +#include "ash/common/login_status.h" +#include "ash/common/wm_shell.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" +#include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/user_info.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ash { +namespace test { + +namespace { + +// Returns the "canonicalized" email from a given |email| address. +std::string GetUserIdFromEmail(const std::string& email) { + std::string user_id = email; + std::transform(user_id.begin(), user_id.end(), user_id.begin(), ::tolower); + return user_id; +} + +// Returns Account ID from a given |email| address. +AccountId GetAccountIdFromEmail(const std::string& email) { + return AccountId::FromUserEmail(GetUserIdFromEmail(email)); +} + +} // namespace + +class MockUserInfo : public user_manager::UserInfo { + public: + explicit MockUserInfo(const std::string& display_email) + : display_email_(display_email), + account_id_(GetAccountIdFromEmail(display_email)) {} + ~MockUserInfo() override {} + + void SetUserImage(const gfx::ImageSkia& user_image) { + user_image_ = user_image; + } + + base::string16 GetDisplayName() const override { + return base::UTF8ToUTF16("Über tray Über tray Über tray Über tray"); + } + + base::string16 GetGivenName() const override { + return base::UTF8ToUTF16("Über Über Über Über"); + } + + std::string GetDisplayEmail() const override { return display_email_; } + + const AccountId& GetAccountId() const override { return account_id_; } + + const gfx::ImageSkia& GetImage() const override { return user_image_; } + + // A test user image. + gfx::ImageSkia user_image_; + + std::string display_email_; + const AccountId account_id_; + + DISALLOW_COPY_AND_ASSIGN(MockUserInfo); +}; + +// A test version of user_manager::UserManager which can be used for testing on +// non-ChromeOS builds. +class TestSessionStateDelegate::TestUserManager { + public: + TestUserManager() : session_started_(false) {} + + void SessionStarted() { session_started_ = true; } + + bool IsSessionStarted() const { return session_started_; } + + private: + // True if SessionStarted() has been called. + bool session_started_; + DISALLOW_COPY_AND_ASSIGN(TestUserManager); +}; + +TestSessionStateDelegate::TestSessionStateDelegate() + : can_lock_screen_(true), + should_lock_screen_automatically_(false), + screen_locked_(false), + user_adding_screen_running_(false), + logged_in_users_(1), + active_user_index_(0), + user_manager_(new TestUserManager()), + session_state_(session_manager::SessionState::LOGIN_PRIMARY) { + // This is intended to be capitalized. + user_list_.push_back(base::MakeUnique<MockUserInfo>("First@tray")); + // This is intended to be capitalized. + user_list_.push_back(base::MakeUnique<MockUserInfo>("Second@tray")); + user_list_.push_back(base::MakeUnique<MockUserInfo>("third@tray")); + user_list_.push_back(base::MakeUnique<MockUserInfo>("someone@tray")); +} + +TestSessionStateDelegate::~TestSessionStateDelegate() {} + +void TestSessionStateDelegate::AddUser(const AccountId& account_id) { + user_list_.push_back( + base::MakeUnique<MockUserInfo>(account_id.GetUserEmail())); +} + +const user_manager::UserInfo* TestSessionStateDelegate::GetActiveUserInfo() + const { + return user_list_[active_user_index_].get(); +} + +int TestSessionStateDelegate::GetMaximumNumberOfLoggedInUsers() const { + return 3; +} + +int TestSessionStateDelegate::NumberOfLoggedInUsers() const { + // TODO(skuhne): Add better test framework to test multiple profiles. + return IsActiveUserSessionStarted() ? logged_in_users_ : 0; +} + +bool TestSessionStateDelegate::IsActiveUserSessionStarted() const { + return user_manager_->IsSessionStarted() && + session_state_ == session_manager::SessionState::ACTIVE; +} + +bool TestSessionStateDelegate::CanLockScreen() const { + return IsActiveUserSessionStarted() && can_lock_screen_; +} + +bool TestSessionStateDelegate::IsScreenLocked() const { + return screen_locked_; +} + +bool TestSessionStateDelegate::ShouldLockScreenAutomatically() const { + return should_lock_screen_automatically_; +} + +void TestSessionStateDelegate::LockScreen() { + if (CanLockScreen()) + screen_locked_ = true; +} + +void TestSessionStateDelegate::UnlockScreen() { + screen_locked_ = false; +} + +bool TestSessionStateDelegate::IsUserSessionBlocked() const { + return !IsActiveUserSessionStarted() || IsScreenLocked() || + user_adding_screen_running_ || + session_state_ != session_manager::SessionState::ACTIVE; +} + +session_manager::SessionState TestSessionStateDelegate::GetSessionState() + const { + return session_state_; +} + +void TestSessionStateDelegate::SetHasActiveUser(bool has_active_user) { + session_state_ = has_active_user + ? session_manager::SessionState::ACTIVE + : session_manager::SessionState::LOGIN_PRIMARY; +} + +void TestSessionStateDelegate::SetActiveUserSessionStarted( + bool active_user_session_started) { + if (active_user_session_started) { + user_manager_->SessionStarted(); + session_state_ = session_manager::SessionState::ACTIVE; + WmShell::Get()->CreateShelfView(); + WmShell::Get()->UpdateAfterLoginStatusChange(LoginStatus::USER); + } else { + session_state_ = session_manager::SessionState::LOGIN_PRIMARY; + user_manager_.reset(new TestUserManager()); + } +} + +// static +void TestSessionStateDelegate::SetCanLockScreen(bool can_lock_screen) { + CHECK(WmShell::HasInstance()); + static_cast<ash::test::TestSessionStateDelegate*>( + WmShell::Get()->GetSessionStateDelegate()) + ->can_lock_screen_ = can_lock_screen; +} + +void TestSessionStateDelegate::SetShouldLockScreenAutomatically( + bool should_lock) { + should_lock_screen_automatically_ = should_lock; +} + +void TestSessionStateDelegate::SetUserAddingScreenRunning( + bool user_adding_screen_running) { + user_adding_screen_running_ = user_adding_screen_running; + if (user_adding_screen_running_) + session_state_ = session_manager::SessionState::LOGIN_SECONDARY; + else + session_state_ = session_manager::SessionState::ACTIVE; +} + +void TestSessionStateDelegate::SetUserImage(const gfx::ImageSkia& user_image) { + user_list_[active_user_index_]->SetUserImage(user_image); +} + +const user_manager::UserInfo* TestSessionStateDelegate::GetUserInfo( + UserIndex index) const { + int max = static_cast<int>(user_list_.size()); + return user_list_[index < max ? index : max - 1].get(); +} + +bool TestSessionStateDelegate::ShouldShowAvatar(WmWindow* window) const { + return !GetActiveUserInfo()->GetImage().isNull(); +} + +gfx::ImageSkia TestSessionStateDelegate::GetAvatarImageForWindow( + WmWindow* window) const { + return gfx::ImageSkia(); +} + +void TestSessionStateDelegate::SwitchActiveUser(const AccountId& account_id) { + // Make sure this is a user id and not an email address. + EXPECT_EQ(account_id.GetUserEmail(), + GetUserIdFromEmail(account_id.GetUserEmail())); + active_user_index_ = 0; + for (auto iter = user_list_.begin(); iter != user_list_.end(); ++iter) { + if ((*iter)->GetAccountId() == account_id) { + active_user_index_ = iter - user_list_.begin(); + return; + } + } + NOTREACHED() << "Unknown user:" << account_id.GetUserEmail(); +} + +void TestSessionStateDelegate::CycleActiveUser(CycleUserDirection direction) { + SwitchActiveUser(AccountId::FromUserEmail("someone@tray")); +} + +bool TestSessionStateDelegate::IsMultiProfileAllowedByPrimaryUserPolicy() + const { + return true; +} + +void TestSessionStateDelegate::AddSessionStateObserver( + SessionStateObserver* observer) {} + +void TestSessionStateDelegate::RemoveSessionStateObserver( + SessionStateObserver* observer) {} + +} // namespace test +} // namespace ash
diff --git a/ash/common/test/test_session_state_delegate.h b/ash/common/test/test_session_state_delegate.h new file mode 100644 index 0000000..eb71d540 --- /dev/null +++ b/ash/common/test/test_session_state_delegate.h
@@ -0,0 +1,122 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_TEST_SESSION_STATE_DELEGATE_H_ +#define ASH_COMMON_TEST_TEST_SESSION_STATE_DELEGATE_H_ + +#include <memory> +#include <vector> + +#include "ash/common/session/session_state_delegate.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "ui/gfx/image/image_skia.h" + +class AccountId; + +namespace ash { +namespace test { + +class MockUserInfo; + +class TestSessionStateDelegate : public SessionStateDelegate { + public: + TestSessionStateDelegate(); + ~TestSessionStateDelegate() override; + + void set_logged_in_users(int users) { logged_in_users_ = users; } + void set_session_state(session_manager::SessionState session_state) { + session_state_ = session_state; + } + void AddUser(const AccountId& account_id); + const user_manager::UserInfo* GetActiveUserInfo() const; + + // SessionStateDelegate: + int GetMaximumNumberOfLoggedInUsers() const override; + int NumberOfLoggedInUsers() const override; + bool IsActiveUserSessionStarted() const override; + bool CanLockScreen() const override; + bool IsScreenLocked() const override; + bool ShouldLockScreenAutomatically() const override; + void LockScreen() override; + void UnlockScreen() override; + bool IsUserSessionBlocked() const override; + session_manager::SessionState GetSessionState() const override; + const user_manager::UserInfo* GetUserInfo( + ash::UserIndex index) const override; + bool ShouldShowAvatar(WmWindow* window) const override; + gfx::ImageSkia GetAvatarImageForWindow(WmWindow* window) const override; + void SwitchActiveUser(const AccountId& account_id) override; + void CycleActiveUser(CycleUserDirection direction) override; + bool IsMultiProfileAllowedByPrimaryUserPolicy() const override; + void AddSessionStateObserver(ash::SessionStateObserver* observer) override; + void RemoveSessionStateObserver(ash::SessionStateObserver* observer) override; + + // TODO(oshima): Use state machine instead of using boolean variables. + + // Updates the internal state that indicates whether a session is in progress + // and there is an active user. If |has_active_user| is |false|, + // |active_user_session_started_| is reset to |false| as well (see below for + // the difference between these two flags). + void SetHasActiveUser(bool has_active_user); + + // Updates the internal state that indicates whether the session has been + // fully started for the active user. If |active_user_session_started| is + // |true|, |has_active_user_| is set to |true| as well (see below for the + // difference between these two flags). + void SetActiveUserSessionStarted(bool active_user_session_started); + + // Updates the internal state that indicates whether the screen can be locked. + // Locking will only actually be allowed when this value is |true| and there + // is an active user. + static void SetCanLockScreen(bool can_lock_screen); + + // Updates |should_lock_screen_automatically_|. + void SetShouldLockScreenAutomatically(bool should_lock); + + // Updates the internal state that indicates whether user adding screen is + // running now. + void SetUserAddingScreenRunning(bool user_adding_screen_running); + + // Setting non NULL image enables avatar icon. + void SetUserImage(const gfx::ImageSkia& user_image); + + private: + class TestUserManager; + + // Whether the screen can be locked. Locking will only actually be allowed + // when this is |true| and there is an active user. + bool can_lock_screen_; + + // Return value for ShouldLockScreenAutomatically(). + bool should_lock_screen_automatically_; + + // Whether the screen is currently locked. + bool screen_locked_; + + // Whether user addding screen is running now. + bool user_adding_screen_running_; + + // The number of users logged in. + int logged_in_users_; + + // The index for the activated user. + int active_user_index_; + + std::vector<std::unique_ptr<MockUserInfo>> user_list_; + + // The user manager to be used instead of the system instance. + std::unique_ptr<TestUserManager> user_manager_; + + // The current state of the login screen. |session_state_| becomes active + // before the profile and browser UI are available. + session_manager::SessionState session_state_; + + DISALLOW_COPY_AND_ASSIGN(TestSessionStateDelegate); +}; + +} // namespace test +} // namespace ash + +#endif // ASH_COMMON_TEST_TEST_SESSION_STATE_DELEGATE_H_
diff --git a/ash/common/test/test_shelf_delegate.cc b/ash/common/test/test_shelf_delegate.cc new file mode 100644 index 0000000..ee762fd --- /dev/null +++ b/ash/common/test/test_shelf_delegate.cc
@@ -0,0 +1,162 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/test_shelf_delegate.h" + +#include <utility> + +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shell_observer.h" +#include "ash/common/test/test_shelf_item_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_properties.h" +#include "base/memory/ptr_util.h" +#include "ui/aura/window.h" + +namespace ash { +namespace test { + +TestShelfDelegate* TestShelfDelegate::instance_ = nullptr; + +// A ShellObserver that sets the shelf alignment and auto hide behavior when the +// shelf is created, to simulate ChromeLauncherController's behavior. +class ShelfInitializer : public ShellObserver { + public: + ShelfInitializer() { WmShell::Get()->AddShellObserver(this); } + ~ShelfInitializer() override { WmShell::Get()->RemoveShellObserver(this); } + + // ShellObserver: + void OnShelfCreatedForRootWindow(WmWindow* root_window) override { + WmShelf* shelf = root_window->GetRootWindowController()->GetShelf(); + // Do not override the custom initialization performed by some unit tests. + if (shelf->alignment() == SHELF_ALIGNMENT_BOTTOM_LOCKED && + shelf->auto_hide_behavior() == SHELF_AUTO_HIDE_ALWAYS_HIDDEN) { + shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); + shelf->UpdateVisibilityState(); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShelfInitializer); +}; + +TestShelfDelegate::TestShelfDelegate() + : shelf_initializer_(base::MakeUnique<ShelfInitializer>()) { + CHECK(!instance_); + instance_ = this; +} + +TestShelfDelegate::~TestShelfDelegate() { + instance_ = nullptr; +} + +void TestShelfDelegate::AddShelfItem(WmWindow* window) { + AddShelfItem(window, STATUS_CLOSED); +} + +void TestShelfDelegate::AddShelfItem(WmWindow* window, + const std::string& app_id) { + AddShelfItem(window, STATUS_CLOSED); + ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey); + AddShelfIDToAppIDMapping(shelf_id, app_id); +} + +void TestShelfDelegate::AddShelfItem(WmWindow* window, ShelfItemStatus status) { + ShelfItem item; + if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL) + item.type = TYPE_APP_PANEL; + else + item.type = TYPE_APP; + ShelfModel* model = WmShell::Get()->shelf_model(); + ShelfID id = model->next_id(); + item.status = status; + model->Add(item); + window->aura_window()->AddObserver(this); + + model->SetShelfItemDelegate(id, + base::MakeUnique<TestShelfItemDelegate>(window)); + window->aura_window()->SetProperty(kShelfIDKey, id); +} + +void TestShelfDelegate::RemoveShelfItemForWindow(WmWindow* window) { + ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey); + if (shelf_id == 0) + return; + ShelfModel* model = WmShell::Get()->shelf_model(); + int index = model->ItemIndexByID(shelf_id); + DCHECK_NE(-1, index); + model->RemoveItemAt(index); + window->aura_window()->RemoveObserver(this); + if (HasShelfIDToAppIDMapping(shelf_id)) { + const std::string& app_id = GetAppIDForShelfID(shelf_id); + if (IsAppPinned(app_id)) + UnpinAppWithID(app_id); + if (HasShelfIDToAppIDMapping(shelf_id)) + RemoveShelfIDToAppIDMapping(shelf_id); + } +} + +void TestShelfDelegate::OnWindowDestroying(aura::Window* window) { + RemoveShelfItemForWindow(WmWindow::Get(window)); +} + +void TestShelfDelegate::OnWindowHierarchyChanging( + const HierarchyChangeParams& params) { + // The window may be legitimately reparented while staying open if it moves + // to another display or container. If the window does not have a new parent + // then remove the shelf item. + if (!params.new_parent) + RemoveShelfItemForWindow(WmWindow::Get(params.target)); +} + +ShelfID TestShelfDelegate::GetShelfIDForAppID(const std::string& app_id) { + for (auto const& iter : shelf_id_to_app_id_map_) { + if (iter.second == app_id) + return iter.first; + } + return 0; +} + +ShelfID TestShelfDelegate::GetShelfIDForAppIDAndLaunchID( + const std::string& app_id, + const std::string& launch_id) { + return GetShelfIDForAppID(app_id); +} + +bool TestShelfDelegate::HasShelfIDToAppIDMapping(ShelfID id) const { + return shelf_id_to_app_id_map_.find(id) != shelf_id_to_app_id_map_.end(); +} + +const std::string& TestShelfDelegate::GetAppIDForShelfID(ShelfID id) { + DCHECK_GT(shelf_id_to_app_id_map_.count(id), 0u); + return shelf_id_to_app_id_map_[id]; +} + +void TestShelfDelegate::PinAppWithID(const std::string& app_id) { + pinned_apps_.insert(app_id); +} + +bool TestShelfDelegate::IsAppPinned(const std::string& app_id) { + return pinned_apps_.find(app_id) != pinned_apps_.end(); +} + +void TestShelfDelegate::UnpinAppWithID(const std::string& app_id) { + pinned_apps_.erase(app_id); +} + +void TestShelfDelegate::AddShelfIDToAppIDMapping(ShelfID shelf_id, + const std::string& app_id) { + shelf_id_to_app_id_map_[shelf_id] = app_id; +} + +void TestShelfDelegate::RemoveShelfIDToAppIDMapping(ShelfID shelf_id) { + shelf_id_to_app_id_map_.erase(shelf_id); +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/test/test_shelf_delegate.h b/ash/common/test/test_shelf_delegate.h new file mode 100644 index 0000000..a334848 --- /dev/null +++ b/ash/common/test/test_shelf_delegate.h
@@ -0,0 +1,86 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_TEST_SHELF_DELEGATE_H_ +#define ASH_COMMON_TEST_TEST_SHELF_DELEGATE_H_ + +#include <map> +#include <set> +#include <string> + +#include "ash/common/shelf/shelf_delegate.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" + +namespace ash { + +class WmWindow; + +namespace test { + +class ShelfInitializer; + +// Test implementation of ShelfDelegate. +// Tests may create icons for windows by calling AddShelfItem(). +class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver { + public: + TestShelfDelegate(); + ~TestShelfDelegate() override; + + // Adds a ShelfItem for the given |window|. The ShelfItem's status will be + // STATUS_CLOSED. + void AddShelfItem(WmWindow* window); + + // Adds a ShelfItem for the given |window| and adds a mapping from the added + // ShelfItem's ShelfID to the given |app_id|. The ShelfItem's status will be + // STATUS_CLOSED. + void AddShelfItem(WmWindow* window, const std::string& app_id); + + // Adds a ShelfItem for the given |window| with the specified |status|. + void AddShelfItem(WmWindow* window, ShelfItemStatus status); + + // Removes the ShelfItem for the specified |window| and unpins it if it was + // pinned. The |window|'s ShelfID to app id mapping will be removed if it + // exists. + void RemoveShelfItemForWindow(WmWindow* window); + + static TestShelfDelegate* instance() { return instance_; } + + // WindowObserver implementation + void OnWindowDestroying(aura::Window* window) override; + void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override; + + // ShelfDelegate implementation. + ShelfID GetShelfIDForAppID(const std::string& app_id) override; + ShelfID GetShelfIDForAppIDAndLaunchID(const std::string& app_id, + const std::string& launch_id) override; + bool HasShelfIDToAppIDMapping(ShelfID id) const override; + const std::string& GetAppIDForShelfID(ShelfID id) override; + void PinAppWithID(const std::string& app_id) override; + bool IsAppPinned(const std::string& app_id) override; + void UnpinAppWithID(const std::string& app_id) override; + + private: + // Adds a mapping from a ShelfID to an app id. + void AddShelfIDToAppIDMapping(ShelfID shelf_id, const std::string& app_id); + + // Removes the mapping from a ShelfID to an app id. + void RemoveShelfIDToAppIDMapping(ShelfID shelf_id); + + static TestShelfDelegate* instance_; + + std::unique_ptr<ShelfInitializer> shelf_initializer_; + + std::set<std::string> pinned_apps_; + + // Tracks the ShelfID to app id mappings. + std::map<ShelfID, std::string> shelf_id_to_app_id_map_; + + DISALLOW_COPY_AND_ASSIGN(TestShelfDelegate); +}; + +} // namespace test +} // namespace ash + +#endif // ASH_COMMON_TEST_TEST_SHELF_DELEGATE_H_
diff --git a/ash/common/test/test_shelf_item_delegate.cc b/ash/common/test/test_shelf_item_delegate.cc new file mode 100644 index 0000000..31e22c8 --- /dev/null +++ b/ash/common/test/test_shelf_item_delegate.cc
@@ -0,0 +1,46 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/test_shelf_item_delegate.h" + +#include "ash/common/wm_window.h" +#include "ash/wm/window_util.h" + +namespace ash { +namespace test { + +TestShelfItemDelegate::TestShelfItemDelegate(WmWindow* window) + : window_(window) {} + +TestShelfItemDelegate::~TestShelfItemDelegate() {} + +ShelfAction TestShelfItemDelegate::ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) { + if (window_) { + if (window_->GetType() == ui::wm::WINDOW_TYPE_PANEL) + wm::MoveWindowToDisplay(window_->aura_window(), display_id); + window_->Show(); + window_->Activate(); + return SHELF_ACTION_WINDOW_ACTIVATED; + } + return SHELF_ACTION_NONE; +} + +ShelfAppMenuItemList TestShelfItemDelegate::GetAppMenuItems(int event_flags) { + // Return an empty item list to avoid showing an application menu. + return ShelfAppMenuItemList(); +} + +void TestShelfItemDelegate::ExecuteCommand(uint32_t command_id, + int event_flags) { + // This delegate does not support showing an application menu. + NOTIMPLEMENTED(); +} + +void TestShelfItemDelegate::Close() {} + +} // namespace test +} // namespace ash
diff --git a/ash/common/test/test_shelf_item_delegate.h b/ash/common/test/test_shelf_item_delegate.h new file mode 100644 index 0000000..6e2f8b5 --- /dev/null +++ b/ash/common/test/test_shelf_item_delegate.h
@@ -0,0 +1,41 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_ +#define ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_ + +#include "ash/common/shelf/shelf_item_delegate.h" +#include "base/macros.h" + +namespace ash { + +class WmWindow; + +namespace test { + +// Test implementation of ShelfItemDelegate. +class TestShelfItemDelegate : public ShelfItemDelegate { + public: + explicit TestShelfItemDelegate(WmWindow* window); + ~TestShelfItemDelegate() override; + + // ShelfItemDelegate: + ShelfAction ItemSelected(ui::EventType event_type, + int event_flags, + int64_t display_id, + ShelfLaunchSource source) override; + ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; + void ExecuteCommand(uint32_t command_id, int event_flags) override; + void Close() override; + + private: + WmWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(TestShelfItemDelegate); +}; + +} // namespace test +} // namespace ash + +#endif // ASH_COMMON_TEST_TEST_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/common/test/test_system_tray_delegate.cc b/ash/common/test/test_system_tray_delegate.cc new file mode 100644 index 0000000..84b240c33 --- /dev/null +++ b/ash/common/test/test_system_tray_delegate.cc
@@ -0,0 +1,109 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/test_system_tray_delegate.h" + +#include <string> + +#include "ash/common/login_status.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm_shell.h" +#include "base/time/time.h" + +namespace ash { +namespace test { + +namespace { + +LoginStatus g_initial_status = LoginStatus::USER; + +} // namespace + +TestSystemTrayDelegate::TestSystemTrayDelegate() + : login_status_(g_initial_status), session_length_limit_set_(false) {} + +TestSystemTrayDelegate::~TestSystemTrayDelegate() {} + +void TestSystemTrayDelegate::SetLoginStatus(LoginStatus login_status) { + login_status_ = login_status; + WmShell::Get()->UpdateAfterLoginStatusChange(login_status); +} + +void TestSystemTrayDelegate::SetSessionLengthLimitForTest( + const base::TimeDelta& new_limit) { + session_length_limit_ = new_limit; + session_length_limit_set_ = true; +} + +void TestSystemTrayDelegate::ClearSessionLengthLimit() { + session_length_limit_set_ = false; +} + +void TestSystemTrayDelegate::SetCurrentIME(const IMEInfo& info) { + current_ime_ = info; +} + +void TestSystemTrayDelegate::SetAvailableIMEList(const IMEInfoList& list) { + ime_list_ = list; +} + +LoginStatus TestSystemTrayDelegate::GetUserLoginStatus() const { + // Initial login status has been changed for testing. + if (g_initial_status != LoginStatus::USER && + g_initial_status == login_status_) { + return login_status_; + } + + // At new user image screen manager->IsUserLoggedIn() would return true + // but there's no browser session available yet so use SessionStarted(). + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + + if (!delegate->IsActiveUserSessionStarted()) + return LoginStatus::NOT_LOGGED_IN; + if (delegate->IsScreenLocked()) + return LoginStatus::LOCKED; + return login_status_; +} + +bool TestSystemTrayDelegate::IsUserSupervised() const { + return login_status_ == LoginStatus::SUPERVISED; +} + +bool TestSystemTrayDelegate::GetSessionStartTime( + base::TimeTicks* session_start_time) { + // Just returns TimeTicks::Now(), so the remaining time is always the + // specified limit. This is useful for testing. + if (session_length_limit_set_) + *session_start_time = base::TimeTicks::Now(); + return session_length_limit_set_; +} + +bool TestSystemTrayDelegate::GetSessionLengthLimit( + base::TimeDelta* session_length_limit) { + if (session_length_limit_set_) + *session_length_limit = session_length_limit_; + return session_length_limit_set_; +} + +void TestSystemTrayDelegate::GetCurrentIME(IMEInfo* info) { + *info = current_ime_; +} + +void TestSystemTrayDelegate::GetAvailableIMEList(IMEInfoList* list) { + *list = ime_list_; +} + +//////////////////////////////////////////////////////////////////////////////// + +ScopedInitialLoginStatus::ScopedInitialLoginStatus(LoginStatus new_status) + : old_status_(g_initial_status) { + g_initial_status = new_status; +} + +ScopedInitialLoginStatus::~ScopedInitialLoginStatus() { + g_initial_status = old_status_; +} + +} // namespace test +} // namespace ash
diff --git a/ash/common/test/test_system_tray_delegate.h b/ash/common/test/test_system_tray_delegate.h new file mode 100644 index 0000000..4c3cae3 --- /dev/null +++ b/ash/common/test/test_system_tray_delegate.h
@@ -0,0 +1,76 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_ +#define ASH_COMMON_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_ + +#include "ash/common/system/tray/default_system_tray_delegate.h" +#include "ash/common/system/tray/ime_info.h" +#include "base/macros.h" +#include "base/time/time.h" + +namespace ash { +namespace test { + +class TestSystemTrayDelegate : public DefaultSystemTrayDelegate { + public: + TestSystemTrayDelegate(); + ~TestSystemTrayDelegate() override; + + // Changes the current login status in the test. This also invokes + // UpdateAfterLoginStatusChange(). Usually this is called in the test code to + // set up a login status. This will fit to most of the test cases, but this + // cannot be set during the initialization. To test the initialization, + // consider using SetInitialLoginStatus() instead. + void SetLoginStatus(LoginStatus login_status); + + // Updates the session length limit so that the limit will come from now in + // |new_limit|. + void SetSessionLengthLimitForTest(const base::TimeDelta& new_limit); + + // Clears the session length limit. + void ClearSessionLengthLimit(); + + // Sets the IME info. + void SetCurrentIME(const IMEInfo& info); + + // Sets the list of available IMEs. + void SetAvailableIMEList(const IMEInfoList& list); + + // Overridden from SystemTrayDelegate: + LoginStatus GetUserLoginStatus() const override; + bool IsUserSupervised() const override; + bool GetSessionStartTime(base::TimeTicks* session_start_time) override; + bool GetSessionLengthLimit(base::TimeDelta* session_length_limit) override; + void GetCurrentIME(IMEInfo* info) override; + void GetAvailableIMEList(IMEInfoList* list) override; + + private: + LoginStatus login_status_; + base::TimeDelta session_length_limit_; + bool session_length_limit_set_; + IMEInfo current_ime_; + IMEInfoList ime_list_; + + DISALLOW_COPY_AND_ASSIGN(TestSystemTrayDelegate); +}; + +// Changes the initial login status before TestSystemTrayDelegate is created. +// Allows testing the case when chrome is restarted right after login (such as +// when a flag is set). +class ScopedInitialLoginStatus { + public: + explicit ScopedInitialLoginStatus(LoginStatus status); + ~ScopedInitialLoginStatus(); + + private: + LoginStatus old_status_; + + DISALLOW_COPY_AND_ASSIGN(ScopedInitialLoginStatus); +}; + +} // namespace test +} // namespace ash + +#endif // ASH_COMMON_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_
diff --git a/ash/common/test/wm_shell_test_api.cc b/ash/common/test/wm_shell_test_api.cc new file mode 100644 index 0000000..6be4bab0 --- /dev/null +++ b/ash/common/test/wm_shell_test_api.cc
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/wm_shell_test_api.h" + +#include <utility> + +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/public/interfaces/new_window.mojom.h" + +namespace ash { + +WmShellTestApi::WmShellTestApi() {} + +WmShellTestApi::~WmShellTestApi() {} + +void WmShellTestApi::SetSystemTrayDelegate( + std::unique_ptr<SystemTrayDelegate> delegate) { + WmShell::Get()->SetSystemTrayDelegate(std::move(delegate)); +} + +} // namespace ash
diff --git a/ash/common/test/wm_shell_test_api.h b/ash/common/test/wm_shell_test_api.h new file mode 100644 index 0000000..07ab6fff --- /dev/null +++ b/ash/common/test/wm_shell_test_api.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_WM_SHELL_TEST_API_H_ +#define ASH_COMMON_TEST_WM_SHELL_TEST_API_H_ + +#include <memory> + +#include "base/macros.h" + +namespace ash { + +class SystemTrayDelegate; + +// Test API to access the internal state of the singleton WmShell. +class WmShellTestApi { + public: + WmShellTestApi(); + ~WmShellTestApi(); + + void SetSystemTrayDelegate(std::unique_ptr<SystemTrayDelegate> delegate); + + private: + DISALLOW_COPY_AND_ASSIGN(WmShellTestApi); +}; + +} // namespace ash + +#endif // ASH_COMMON_TEST_WM_SHELL_TEST_API_H_
diff --git a/ash/common/test/workspace_event_handler_test_helper.cc b/ash/common/test/workspace_event_handler_test_helper.cc new file mode 100644 index 0000000..865ffbf --- /dev/null +++ b/ash/common/test/workspace_event_handler_test_helper.cc
@@ -0,0 +1,15 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/test/workspace_event_handler_test_helper.h" + +namespace ash { + +WorkspaceEventHandlerTestHelper::WorkspaceEventHandlerTestHelper( + WorkspaceEventHandler* handler) + : handler_(handler) {} + +WorkspaceEventHandlerTestHelper::~WorkspaceEventHandlerTestHelper() {} + +} // namespace ash
diff --git a/ash/common/test/workspace_event_handler_test_helper.h b/ash/common/test/workspace_event_handler_test_helper.h new file mode 100644 index 0000000..a090eee7 --- /dev/null +++ b/ash/common/test/workspace_event_handler_test_helper.h
@@ -0,0 +1,31 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_ +#define ASH_COMMON_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_ + +#include "ash/common/wm/workspace/workspace_event_handler.h" + +#include "base/macros.h" + +namespace ash { + +class WorkspaceEventHandlerTestHelper { + public: + explicit WorkspaceEventHandlerTestHelper(WorkspaceEventHandler* handler); + ~WorkspaceEventHandlerTestHelper(); + + MultiWindowResizeController* resize_controller() { + return &(handler_->multi_window_resize_controller_); + } + + private: + WorkspaceEventHandler* handler_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceEventHandlerTestHelper); +}; + +} // namespace ash + +#endif // ASH_COMMON_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
diff --git a/ash/common/wallpaper/wallpaper_view.cc b/ash/common/wallpaper/wallpaper_view.cc index f3ad6ae3..2aed6b6 100644 --- a/ash/common/wallpaper/wallpaper_view.cc +++ b/ash/common/wallpaper/wallpaper_view.cc
@@ -8,10 +8,10 @@ #include "ash/common/wallpaper/wallpaper_controller.h" #include "ash/common/wallpaper/wallpaper_delegate.h" #include "ash/common/wallpaper/wallpaper_widget_controller.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ui/display/display.h" #include "ui/display/manager/managed_display_info.h" #include "ui/display/screen.h"
diff --git a/ash/common/wm/OWNERS b/ash/common/wm/OWNERS new file mode 100644 index 0000000..6310ae0 --- /dev/null +++ b/ash/common/wm/OWNERS
@@ -0,0 +1,3 @@ +pkotwicz@chromium.org +varkha@chromium.org +flackr@chromium.org
diff --git a/ash/common/wm/always_on_top_controller.cc b/ash/common/wm/always_on_top_controller.cc new file mode 100644 index 0000000..d115f01 --- /dev/null +++ b/ash/common/wm/always_on_top_controller.cc
@@ -0,0 +1,78 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/always_on_top_controller.h" + +#include "ash/common/wm/workspace/workspace_layout_manager.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "base/memory/ptr_util.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" + +namespace ash { + +AlwaysOnTopController::AlwaysOnTopController(WmWindow* viewport) + : always_on_top_container_(viewport) { + DCHECK_NE(kShellWindowId_DefaultContainer, viewport->GetShellWindowId()); + always_on_top_container_->SetLayoutManager( + base::MakeUnique<WorkspaceLayoutManager>(viewport)); + // Container should be empty. + DCHECK(always_on_top_container_->GetChildren().empty()); + always_on_top_container_->aura_window()->AddObserver(this); +} + +AlwaysOnTopController::~AlwaysOnTopController() { + if (always_on_top_container_) + always_on_top_container_->aura_window()->RemoveObserver(this); +} + +WmWindow* AlwaysOnTopController::GetContainer(WmWindow* window) const { + DCHECK(always_on_top_container_); + if (window->aura_window()->GetProperty(aura::client::kAlwaysOnTopKey)) + return always_on_top_container_; + return always_on_top_container_->GetRootWindow()->GetChildByShellWindowId( + kShellWindowId_DefaultContainer); +} + +// TODO(rsadam@): Refactor so that this cast is unneeded. +WorkspaceLayoutManager* AlwaysOnTopController::GetLayoutManager() const { + return static_cast<WorkspaceLayoutManager*>( + always_on_top_container_->GetLayoutManager()); +} + +void AlwaysOnTopController::SetLayoutManagerForTest( + std::unique_ptr<WorkspaceLayoutManager> layout_manager) { + always_on_top_container_->SetLayoutManager(std::move(layout_manager)); +} + +void AlwaysOnTopController::OnWindowHierarchyChanged( + const HierarchyChangeParams& params) { + if (WmWindow::Get(params.old_parent) == always_on_top_container_) + params.target->RemoveObserver(this); + else if (WmWindow::Get(params.new_parent) == always_on_top_container_) + params.target->AddObserver(this); +} + +void AlwaysOnTopController::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + if (WmWindow::Get(window) != always_on_top_container_ && + key == aura::client::kAlwaysOnTopKey) { + DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL || + window->type() == ui::wm::WINDOW_TYPE_POPUP); + WmWindow* container = GetContainer(WmWindow::Get(window)); + if (WmWindow::Get(window->parent()) != container) + container->AddChild(WmWindow::Get(window)); + } +} + +void AlwaysOnTopController::OnWindowDestroying(aura::Window* window) { + if (WmWindow::Get(window) == always_on_top_container_) { + always_on_top_container_->aura_window()->RemoveObserver(this); + always_on_top_container_ = nullptr; + } +} + +} // namespace ash
diff --git a/ash/common/wm/always_on_top_controller.h b/ash/common/wm/always_on_top_controller.h new file mode 100644 index 0000000..bdf1446 --- /dev/null +++ b/ash/common/wm/always_on_top_controller.h
@@ -0,0 +1,51 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_ALWAYS_ON_TOP_CONTROLLER_H_ +#define ASH_COMMON_WM_ALWAYS_ON_TOP_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" + +namespace ash { + +class WmWindow; +class WorkspaceLayoutManager; + +// AlwaysOnTopController puts window into proper containers based on its +// 'AlwaysOnTop' property. That is, putting a window into the worskpace +// container if its "AlwaysOnTop" property is false. Otherwise, put it in +// |always_on_top_container_|. +class ASH_EXPORT AlwaysOnTopController : public aura::WindowObserver { + public: + explicit AlwaysOnTopController(WmWindow* viewport); + ~AlwaysOnTopController() override; + + // Gets container for given |window| based on its "AlwaysOnTop" property. + WmWindow* GetContainer(WmWindow* window) const; + + WorkspaceLayoutManager* GetLayoutManager() const; + + void SetLayoutManagerForTest( + std::unique_ptr<WorkspaceLayoutManager> layout_manager); + + private: + // Overridden from aura::WindowObserver: + void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + void OnWindowDestroying(aura::Window* window) override; + + WmWindow* always_on_top_container_; + + DISALLOW_COPY_AND_ASSIGN(AlwaysOnTopController); +}; + +} // namepsace ash + +#endif // ASH_COMMON_WM_ALWAYS_ON_TOP_CONTROLLER_H_
diff --git a/ash/common/wm/container_finder.cc b/ash/common/wm/container_finder.cc new file mode 100644 index 0000000..ece5ca95 --- /dev/null +++ b/ash/common/wm/container_finder.cc
@@ -0,0 +1,130 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/container_finder.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm/always_on_top_controller.h" +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/root_window_controller.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { +namespace wm { +namespace { + +WmWindow* FindContainerRoot(WmShell* shell, const gfx::Rect& bounds) { + if (bounds == gfx::Rect()) + return shell->GetRootWindowForNewWindows(); + return GetRootWindowMatching(bounds); +} + +bool HasTransientParentWindow(const WmWindow* window) { + return window->GetTransientParent() && + window->GetTransientParent()->GetType() != ui::wm::WINDOW_TYPE_UNKNOWN; +} + +WmWindow* GetSystemModalContainer(WmWindow* root, WmWindow* window) { + DCHECK(window->IsSystemModal()); + + // If screen lock is not active and user session is active, + // all modal windows are placed into the normal modal container. + // In case of missing transient parent (it could happen for alerts from + // background pages) assume that the window belongs to user session. + if (!window->GetShell()->GetSessionStateDelegate()->IsUserSessionBlocked() || + !window->GetTransientParent()) { + return root->GetChildByShellWindowId(kShellWindowId_SystemModalContainer); + } + + // Otherwise those that originate from LockScreen container and above are + // placed in the screen lock modal container. + int window_container_id = + window->GetTransientParent()->GetParent()->GetShellWindowId(); + if (window_container_id < kShellWindowId_LockScreenContainer) + return root->GetChildByShellWindowId(kShellWindowId_SystemModalContainer); + return root->GetChildByShellWindowId(kShellWindowId_LockSystemModalContainer); +} + +WmWindow* GetContainerFromAlwaysOnTopController(WmWindow* root, + WmWindow* window) { + return root->GetRootWindowController() + ->always_on_top_controller() + ->GetContainer(window); +} + +} // namespace + +WmWindow* GetContainerForWindow(WmWindow* window) { + WmWindow* parent = window->GetParent(); + // The first parent with an explicit shell window ID is the container. + while (parent && parent->GetShellWindowId() == kShellWindowId_Invalid) + parent = parent->GetParent(); + return parent; +} + +WmWindow* GetDefaultParent(WmWindow* context, + WmWindow* window, + const gfx::Rect& bounds) { + WmWindow* target_root = nullptr; + WmWindow* transient_parent = window->GetTransientParent(); + if (transient_parent) { + // Transient window should use the same root as its transient parent. + target_root = transient_parent->GetRootWindow(); + } else { + target_root = FindContainerRoot(context->GetShell(), bounds); + } + + switch (window->GetType()) { + case ui::wm::WINDOW_TYPE_NORMAL: + case ui::wm::WINDOW_TYPE_POPUP: + if (window->IsSystemModal()) + return GetSystemModalContainer(target_root, window); + if (HasTransientParentWindow(window)) + return GetContainerForWindow(window->GetTransientParent()); + return GetContainerFromAlwaysOnTopController(target_root, window); + case ui::wm::WINDOW_TYPE_CONTROL: + return target_root->GetChildByShellWindowId( + kShellWindowId_UnparentedControlContainer); + case ui::wm::WINDOW_TYPE_PANEL: + if (window->aura_window()->GetProperty(kPanelAttachedKey)) + return target_root->GetChildByShellWindowId( + kShellWindowId_PanelContainer); + return GetContainerFromAlwaysOnTopController(target_root, window); + case ui::wm::WINDOW_TYPE_MENU: + return target_root->GetChildByShellWindowId(kShellWindowId_MenuContainer); + case ui::wm::WINDOW_TYPE_TOOLTIP: + return target_root->GetChildByShellWindowId( + kShellWindowId_DragImageAndTooltipContainer); + default: + NOTREACHED() << "Window " << window->GetShellWindowId() + << " has unhandled type " << window->GetType(); + break; + } + return nullptr; +} + +std::vector<WmWindow*> GetContainersFromAllRootWindows( + int container_id, + WmWindow* priority_root) { + std::vector<WmWindow*> containers; + for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { + WmWindow* container = root->GetChildByShellWindowId(container_id); + if (!container) + continue; + + if (priority_root && priority_root->Contains(container)) + containers.insert(containers.begin(), container); + else + containers.push_back(container); + } + return containers; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/container_finder.h b/ash/common/wm/container_finder.h new file mode 100644 index 0000000..a54e57a --- /dev/null +++ b/ash/common/wm/container_finder.h
@@ -0,0 +1,42 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_CONTAINER_FINDER_H_ +#define ASH_COMMON_WM_CONTAINER_FINDER_H_ + +#include <vector> + +#include "ash/ash_export.h" + +namespace gfx { +class Rect; +} + +namespace ash { + +class WmWindow; + +namespace wm { + +// Returns the first ancestor of |window| that has a known container ID. +ASH_EXPORT WmWindow* GetContainerForWindow(WmWindow* window); + +// Returns the parent to add |window| to in |context|. This is generally +// used when a window is moved from one root to another. In this case |context| +// is the new root to add |window| to. +ASH_EXPORT WmWindow* GetDefaultParent(WmWindow* context, + WmWindow* window, + const gfx::Rect& bounds); + +// Returns the list of containers that match |container_id| in all root windows. +// If |priority_root| is non-null, the container in |priority_root| is placed at +// the front of the list. +ASH_EXPORT std::vector<WmWindow*> GetContainersFromAllRootWindows( + int container_id, + WmWindow* priority_root = nullptr); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_CONTAINER_FINDER_H_
diff --git a/ash/common/wm/container_finder_unittest.cc b/ash/common/wm/container_finder_unittest.cc new file mode 100644 index 0000000..cf9f96d --- /dev/null +++ b/ash/common/wm/container_finder_unittest.cc
@@ -0,0 +1,34 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/container_finder.h" + +#include <memory> + +#include "ash/common/test/ash_test.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +using ContainerFinderTest = AshTest; + +TEST_F(ContainerFinderTest, GetContainerForWindow) { + // Create a normal widget in the default container. + std::unique_ptr<views::Widget> widget = + CreateTestWidget(gfx::Rect(1, 2, 3, 4)); + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + + // The window itself is not a container. + EXPECT_EQ(kShellWindowId_Invalid, window->GetShellWindowId()); + + // Container lookup finds the default container. + WmWindow* container = wm::GetContainerForWindow(window); + ASSERT_TRUE(container); + EXPECT_EQ(kShellWindowId_DefaultContainer, container->GetShellWindowId()); +} + +} // namespace ash
diff --git a/ash/common/wm/default_state.cc b/ash/common/wm/default_state.cc new file mode 100644 index 0000000..8149d7f --- /dev/null +++ b/ash/common/wm/default_state.cc
@@ -0,0 +1,823 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/default_state.h" + +#include "ash/common/ash_switches.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/window_parenting_utils.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_delegate.h" +#include "ash/common/wm/window_state_util.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" + +namespace ash { +namespace wm { +namespace { + +// This specifies how much percent (30%) of a window rect +// must be visible when the window is added to the workspace. +const float kMinimumPercentOnScreenArea = 0.3f; + +// When a window that has restore bounds at least as large as a work area is +// unmaximized, inset the bounds slightly so that they are not exactly the same. +// This makes it easier to resize the window. +const int kMaximizedWindowInset = 10; // DIPs. + +bool IsMinimizedWindowState(const WindowStateType state_type) { + return state_type == WINDOW_STATE_TYPE_MINIMIZED || + state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; +} + +void MoveToDisplayForRestore(WindowState* window_state) { + if (!window_state->HasRestoreBounds()) + return; + const gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); + + // Move only if the restore bounds is outside of + // the display. There is no information about in which + // display it should be restored, so this is best guess. + // TODO(oshima): Restore information should contain the + // work area information like WindowResizer does for the + // last window location. + gfx::Rect display_area = + window_state->window()->GetDisplayNearestWindow().bounds(); + + if (!display_area.Intersects(restore_bounds)) { + const display::Display& display = + display::Screen::GetScreen()->GetDisplayMatching(restore_bounds); + WmShell* shell = window_state->window()->GetShell(); + WmWindow* new_root = shell->GetRootWindowForDisplayId(display.id()); + if (new_root != window_state->window()->GetRootWindow()) { + WmWindow* new_container = new_root->GetChildByShellWindowId( + window_state->window()->GetParent()->GetShellWindowId()); + new_container->AddChild(window_state->window()); + } + } +} + +DockedWindowLayoutManager* GetDockedWindowLayoutManager(WmShell* shell) { + return DockedWindowLayoutManager::Get(shell->GetActiveWindow()); +} + +class ScopedPreferredAlignmentResetter { + public: + ScopedPreferredAlignmentResetter(DockedAlignment dock_alignment, + DockedWindowLayoutManager* dock_layout) + : docked_window_layout_manager_(dock_layout) { + docked_window_layout_manager_->set_preferred_alignment(dock_alignment); + } + ~ScopedPreferredAlignmentResetter() { + docked_window_layout_manager_->set_preferred_alignment( + DOCKED_ALIGNMENT_NONE); + } + + private: + DockedWindowLayoutManager* docked_window_layout_manager_; + + DISALLOW_COPY_AND_ASSIGN(ScopedPreferredAlignmentResetter); +}; + +class ScopedDockedLayoutEventSourceResetter { + public: + ScopedDockedLayoutEventSourceResetter(DockedWindowLayoutManager* dock_layout) + : docked_window_layout_manager_(dock_layout) { + docked_window_layout_manager_->set_event_source( + DOCKED_ACTION_SOURCE_KEYBOARD); + } + ~ScopedDockedLayoutEventSourceResetter() { + docked_window_layout_manager_->set_event_source( + DOCKED_ACTION_SOURCE_UNKNOWN); + } + + private: + DockedWindowLayoutManager* docked_window_layout_manager_; + + DISALLOW_COPY_AND_ASSIGN(ScopedDockedLayoutEventSourceResetter); +}; + +void CycleSnap(WindowState* window_state, WMEventType event) { + DCHECK(!ash::switches::DockedWindowsEnabled()); + + wm::WindowStateType desired_snap_state = + event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT + ? wm::WINDOW_STATE_TYPE_LEFT_SNAPPED + : wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED; + + if (window_state->CanSnap() && + window_state->GetStateType() != desired_snap_state && + window_state->window()->GetType() != ui::wm::WINDOW_TYPE_PANEL) { + const wm::WMEvent event(desired_snap_state == + wm::WINDOW_STATE_TYPE_LEFT_SNAPPED + ? wm::WM_EVENT_SNAP_LEFT + : wm::WM_EVENT_SNAP_RIGHT); + window_state->OnWMEvent(&event); + return; + } + + if (window_state->IsSnapped()) { + window_state->Restore(); + return; + } + window_state->window()->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); +} + +void CycleSnapDock(WindowState* window_state, WMEventType event) { + DCHECK(ash::switches::DockedWindowsEnabled()); + + DockedWindowLayoutManager* dock_layout = + GetDockedWindowLayoutManager(window_state->window()->GetShell()); + wm::WindowStateType desired_snap_state = + event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT + ? wm::WINDOW_STATE_TYPE_LEFT_SNAPPED + : wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED; + DockedAlignment desired_dock_alignment = + event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT ? DOCKED_ALIGNMENT_LEFT + : DOCKED_ALIGNMENT_RIGHT; + DockedAlignment current_dock_alignment = + dock_layout ? dock_layout->CalculateAlignment() : DOCKED_ALIGNMENT_NONE; + + if (!window_state->IsDocked() || + (current_dock_alignment != DOCKED_ALIGNMENT_NONE && + current_dock_alignment != desired_dock_alignment)) { + if (window_state->CanSnap() && + window_state->GetStateType() != desired_snap_state && + window_state->window()->GetType() != ui::wm::WINDOW_TYPE_PANEL) { + const wm::WMEvent event(desired_snap_state == + wm::WINDOW_STATE_TYPE_LEFT_SNAPPED + ? wm::WM_EVENT_SNAP_LEFT + : wm::WM_EVENT_SNAP_RIGHT); + window_state->OnWMEvent(&event); + return; + } + + if (dock_layout && + dock_layout->CanDockWindow(window_state->window(), + desired_dock_alignment)) { + if (window_state->IsDocked()) { + dock_layout->MaybeSetDesiredDockedAlignment(desired_dock_alignment); + return; + } + + ScopedDockedLayoutEventSourceResetter event_source_resetter(dock_layout); + ScopedPreferredAlignmentResetter alignmentResetter(desired_dock_alignment, + dock_layout); + const wm::WMEvent event(wm::WM_EVENT_DOCK); + window_state->OnWMEvent(&event); + return; + } + } + + if (window_state->IsDocked() || window_state->IsSnapped()) { + ScopedDockedLayoutEventSourceResetter event_source_resetter(dock_layout); + window_state->Restore(); + return; + } + window_state->window()->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); +} + +} // namespace + +DefaultState::DefaultState(WindowStateType initial_state_type) + : state_type_(initial_state_type), stored_window_state_(nullptr) {} +DefaultState::~DefaultState() {} + +void DefaultState::OnWMEvent(WindowState* window_state, const WMEvent* event) { + if (ProcessWorkspaceEvents(window_state, event)) + return; + + // Do not change the PINNED window state if this is not unpin event. + if (window_state->IsTrustedPinned() && event->type() != WM_EVENT_NORMAL) + return; + + if (ProcessCompoundEvents(window_state, event)) + return; + + WindowStateType current_state_type = window_state->GetStateType(); + WindowStateType next_state_type = WINDOW_STATE_TYPE_NORMAL; + switch (event->type()) { + case WM_EVENT_NORMAL: + next_state_type = current_state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED + ? WINDOW_STATE_TYPE_DOCKED + : WINDOW_STATE_TYPE_NORMAL; + break; + case WM_EVENT_MAXIMIZE: + next_state_type = WINDOW_STATE_TYPE_MAXIMIZED; + break; + case WM_EVENT_MINIMIZE: + next_state_type = current_state_type == WINDOW_STATE_TYPE_DOCKED + ? WINDOW_STATE_TYPE_DOCKED_MINIMIZED + : WINDOW_STATE_TYPE_MINIMIZED; + break; + case WM_EVENT_FULLSCREEN: + next_state_type = WINDOW_STATE_TYPE_FULLSCREEN; + break; + case WM_EVENT_SNAP_LEFT: + next_state_type = WINDOW_STATE_TYPE_LEFT_SNAPPED; + break; + case WM_EVENT_SNAP_RIGHT: + next_state_type = WINDOW_STATE_TYPE_RIGHT_SNAPPED; + break; + case WM_EVENT_DOCK: + next_state_type = WINDOW_STATE_TYPE_DOCKED; + break; + case WM_EVENT_SET_BOUNDS: + SetBounds(window_state, static_cast<const SetBoundsEvent*>(event)); + return; + case WM_EVENT_SHOW_INACTIVE: + next_state_type = WINDOW_STATE_TYPE_INACTIVE; + break; + case WM_EVENT_PIN: + case WM_EVENT_TRUSTED_PIN: + // If there already is a pinned window, it is not allowed to set it + // to this window. + // TODO(hidehiko): If a system modal window is openening, the pinning + // probably should fail. + if (WmShell::Get()->IsPinned()) { + LOG(ERROR) << "An PIN event will be failed since another window is " + << "already in pinned mode."; + next_state_type = current_state_type; + } else { + next_state_type = event->type() == WM_EVENT_PIN + ? WINDOW_STATE_TYPE_PINNED + : WINDOW_STATE_TYPE_TRUSTED_PINNED; + } + break; + case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: + case WM_EVENT_TOGGLE_MAXIMIZE: + case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: + case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: + case WM_EVENT_TOGGLE_FULLSCREEN: + case WM_EVENT_CYCLE_SNAP_DOCK_LEFT: + case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: + case WM_EVENT_CENTER: + NOTREACHED() << "Compound event should not reach here:" << event; + return; + case WM_EVENT_ADDED_TO_WORKSPACE: + case WM_EVENT_WORKAREA_BOUNDS_CHANGED: + case WM_EVENT_DISPLAY_BOUNDS_CHANGED: + NOTREACHED() << "Workspace event should not reach here:" << event; + return; + } + + if (next_state_type == current_state_type && window_state->IsSnapped()) { + gfx::Rect snapped_bounds = + event->type() == WM_EVENT_SNAP_LEFT + ? GetDefaultLeftSnappedWindowBoundsInParent(window_state->window()) + : GetDefaultRightSnappedWindowBoundsInParent( + window_state->window()); + window_state->SetBoundsDirectAnimated(snapped_bounds); + return; + } + + if (event->type() == WM_EVENT_SNAP_LEFT || + event->type() == WM_EVENT_SNAP_RIGHT) { + window_state->set_bounds_changed_by_user(true); + } + + EnterToNextState(window_state, next_state_type); +} + +WindowStateType DefaultState::GetType() const { + return state_type_; +} + +void DefaultState::AttachState(WindowState* window_state, + WindowState::State* state_in_previous_mode) { + DCHECK_EQ(stored_window_state_, window_state); + + ReenterToCurrentState(window_state, state_in_previous_mode); + + // If the display has changed while in the another mode, + // we need to let windows know the change. + display::Display current_display = + window_state->window()->GetDisplayNearestWindow(); + if (stored_display_state_.bounds() != current_display.bounds()) { + const WMEvent event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); + window_state->OnWMEvent(&event); + } else if (stored_display_state_.work_area() != current_display.work_area()) { + const WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); + window_state->OnWMEvent(&event); + } +} + +void DefaultState::DetachState(WindowState* window_state) { + stored_window_state_ = window_state; + stored_bounds_ = window_state->window()->GetBounds(); + stored_restore_bounds_ = window_state->HasRestoreBounds() + ? window_state->GetRestoreBoundsInParent() + : gfx::Rect(); + // Remember the display state so that in case of the display change + // while in the other mode, we can perform necessary action to + // restore the window state to the proper state for the current + // display. + stored_display_state_ = window_state->window()->GetDisplayNearestWindow(); +} + +// static +bool DefaultState::ProcessCompoundEvents(WindowState* window_state, + const WMEvent* event) { + WmWindow* window = window_state->window(); + + switch (event->type()) { + case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: + if (window_state->IsFullscreen()) { + const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); + window_state->OnWMEvent(&event); + } else if (window_state->IsMaximized()) { + window_state->Restore(); + } else if (window_state->IsNormalOrSnapped()) { + if (window_state->CanMaximize()) + window_state->Maximize(); + } + return true; + case WM_EVENT_TOGGLE_MAXIMIZE: + if (window_state->IsFullscreen()) { + const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); + window_state->OnWMEvent(&event); + } else if (window_state->IsMaximized()) { + window_state->Restore(); + } else if (window_state->CanMaximize()) { + window_state->Maximize(); + } + return true; + case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: { + gfx::Rect work_area = GetDisplayWorkAreaBoundsInParent(window); + + // Maximize vertically if: + // - The window does not have a max height defined. + // - The window has the normal state type. Snapped windows are excluded + // because they are already maximized vertically and reverting to the + // restored bounds looks weird. + if (window->GetMaximumSize().height() != 0 || + !window_state->IsNormalStateType()) { + return true; + } + if (window_state->HasRestoreBounds() && + (window->GetBounds().height() == work_area.height() && + window->GetBounds().y() == work_area.y())) { + window_state->SetAndClearRestoreBounds(); + } else { + window_state->SaveCurrentBoundsForRestore(); + window->SetBounds(gfx::Rect(window->GetBounds().x(), work_area.y(), + window->GetBounds().width(), + work_area.height())); + } + return true; + } + case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: { + // Maximize horizontally if: + // - The window does not have a max width defined. + // - The window is snapped or has the normal state type. + if (window->GetMaximumSize().width() != 0) + return true; + if (!window_state->IsNormalOrSnapped()) + return true; + gfx::Rect work_area = GetDisplayWorkAreaBoundsInParent(window); + if (window_state->IsNormalStateType() && + window_state->HasRestoreBounds() && + (window->GetBounds().width() == work_area.width() && + window->GetBounds().x() == work_area.x())) { + window_state->SetAndClearRestoreBounds(); + } else { + gfx::Rect new_bounds(work_area.x(), window->GetBounds().y(), + work_area.width(), window->GetBounds().height()); + + gfx::Rect restore_bounds = window->GetBounds(); + if (window_state->IsSnapped()) { + window_state->SetRestoreBoundsInParent(new_bounds); + window_state->Restore(); + + // The restore logic prevents a window from being restored to bounds + // which match the workspace bounds exactly so it is necessary to set + // the bounds again below. + } + + window_state->SetRestoreBoundsInParent(restore_bounds); + window->SetBounds(new_bounds); + } + return true; + } + case WM_EVENT_TOGGLE_FULLSCREEN: + ToggleFullScreen(window_state, window_state->delegate()); + return true; + case WM_EVENT_CYCLE_SNAP_DOCK_LEFT: + case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: + if (ash::switches::DockedWindowsEnabled()) + CycleSnapDock(window_state, event->type()); + else + CycleSnap(window_state, event->type()); + return true; + case WM_EVENT_CENTER: + CenterWindow(window_state); + return true; + case WM_EVENT_NORMAL: + case WM_EVENT_MAXIMIZE: + case WM_EVENT_MINIMIZE: + case WM_EVENT_FULLSCREEN: + case WM_EVENT_PIN: + case WM_EVENT_TRUSTED_PIN: + case WM_EVENT_SNAP_LEFT: + case WM_EVENT_SNAP_RIGHT: + case WM_EVENT_SET_BOUNDS: + case WM_EVENT_SHOW_INACTIVE: + case WM_EVENT_DOCK: + break; + case WM_EVENT_ADDED_TO_WORKSPACE: + case WM_EVENT_WORKAREA_BOUNDS_CHANGED: + case WM_EVENT_DISPLAY_BOUNDS_CHANGED: + NOTREACHED() << "Workspace event should not reach here:" << event; + break; + } + return false; +} + +bool DefaultState::ProcessWorkspaceEvents(WindowState* window_state, + const WMEvent* event) { + switch (event->type()) { + case WM_EVENT_ADDED_TO_WORKSPACE: { + // When a window is dragged and dropped onto a different + // root window, the bounds will be updated after they are added + // to the root window. + // If a window is opened as maximized or fullscreen, its bounds may be + // empty, so update the bounds now before checking empty. + if (window_state->is_dragged() || + SetMaximizedOrFullscreenBounds(window_state)) { + return true; + } + + WmWindow* window = window_state->window(); + gfx::Rect bounds = window->GetBounds(); + + // Don't adjust window bounds if the bounds are empty as this + // happens when a new views::Widget is created. + if (bounds.IsEmpty()) + return true; + + // Only windows of type WINDOW_TYPE_NORMAL or WINDOW_TYPE_PANEL need to be + // adjusted to have minimum visibility, because they are positioned by the + // user and user should always be able to interact with them. Other + // windows are positioned programmatically. + if (!window_state->IsUserPositionable()) + return true; + + // Use entire display instead of workarea because the workarea can + // be further shrunk by the docked area. The logic ensures 30% + // visibility which should be enough to see where the window gets + // moved. + gfx::Rect display_area = GetDisplayBoundsInParent(window); + int min_width = bounds.width() * wm::kMinimumPercentOnScreenArea; + int min_height = bounds.height() * wm::kMinimumPercentOnScreenArea; + wm::AdjustBoundsToEnsureWindowVisibility(display_area, min_width, + min_height, &bounds); + window_state->AdjustSnappedBounds(&bounds); + if (window->GetBounds() != bounds) + window_state->SetBoundsConstrained(bounds); + return true; + } + case WM_EVENT_DISPLAY_BOUNDS_CHANGED: { + if (window_state->is_dragged() || + SetMaximizedOrFullscreenBounds(window_state)) { + return true; + } + gfx::Rect work_area_in_parent = + GetDisplayWorkAreaBoundsInParent(window_state->window()); + gfx::Rect bounds = window_state->window()->GetTargetBounds(); + // When display bounds has changed, make sure the entire window is fully + // visible. + bounds.AdjustToFit(work_area_in_parent); + window_state->AdjustSnappedBounds(&bounds); + if (window_state->window()->GetTargetBounds() != bounds) + window_state->SetBoundsDirectAnimated(bounds); + return true; + } + case WM_EVENT_WORKAREA_BOUNDS_CHANGED: { + // Don't resize the maximized window when the desktop is covered + // by fullscreen window. crbug.com/504299. + bool in_fullscreen = + window_state->window() + ->GetRootWindowController() + ->GetWorkspaceWindowState() == WORKSPACE_WINDOW_STATE_FULL_SCREEN; + if (in_fullscreen && window_state->IsMaximized()) + return true; + + if (window_state->is_dragged() || + SetMaximizedOrFullscreenBounds(window_state)) { + return true; + } + gfx::Rect work_area_in_parent = + GetDisplayWorkAreaBoundsInParent(window_state->window()); + gfx::Rect bounds = window_state->window()->GetTargetBounds(); + if (!window_state->window()->GetTransientParent()) { + wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, + &bounds); + } + window_state->AdjustSnappedBounds(&bounds); + if (window_state->window()->GetTargetBounds() != bounds) + window_state->SetBoundsDirectAnimated(bounds); + return true; + } + case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: + case WM_EVENT_TOGGLE_MAXIMIZE: + case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: + case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: + case WM_EVENT_TOGGLE_FULLSCREEN: + case WM_EVENT_CYCLE_SNAP_DOCK_LEFT: + case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: + case WM_EVENT_CENTER: + case WM_EVENT_NORMAL: + case WM_EVENT_MAXIMIZE: + case WM_EVENT_MINIMIZE: + case WM_EVENT_FULLSCREEN: + case WM_EVENT_PIN: + case WM_EVENT_TRUSTED_PIN: + case WM_EVENT_SNAP_LEFT: + case WM_EVENT_SNAP_RIGHT: + case WM_EVENT_SET_BOUNDS: + case WM_EVENT_SHOW_INACTIVE: + case WM_EVENT_DOCK: + break; + } + return false; +} + +// static +bool DefaultState::SetMaximizedOrFullscreenBounds(WindowState* window_state) { + DCHECK(!window_state->is_dragged()); + if (window_state->IsMaximized()) { + window_state->SetBoundsDirect( + GetMaximizedWindowBoundsInParent(window_state->window())); + return true; + } + if (window_state->IsFullscreen()) { + window_state->SetBoundsDirect( + GetDisplayBoundsInParent(window_state->window())); + return true; + } + return false; +} + +// static +void DefaultState::SetBounds(WindowState* window_state, + const SetBoundsEvent* event) { + if (window_state->is_dragged()) { + // TODO(oshima|varkha): This may be no longer needed, as the dragging + // happens in docked window container. crbug.com/485612. + window_state->SetBoundsDirect(event->requested_bounds()); + } else if (window_state->IsSnapped()) { + gfx::Rect work_area_in_parent = + GetDisplayWorkAreaBoundsInParent(window_state->window()); + gfx::Rect child_bounds(event->requested_bounds()); + wm::AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds); + window_state->AdjustSnappedBounds(&child_bounds); + window_state->SetBoundsDirect(child_bounds); + } else if (!SetMaximizedOrFullscreenBounds(window_state) || + window_state->allow_set_bounds_in_maximized()) { + window_state->SetBoundsConstrained(event->requested_bounds()); + } +} + +void DefaultState::EnterToNextState(WindowState* window_state, + WindowStateType next_state_type) { + // Do nothing if we're already in the same state. + if (state_type_ == next_state_type) + return; + + WindowStateType previous_state_type = state_type_; + state_type_ = next_state_type; + + window_state->UpdateWindowShowStateFromStateType(); + window_state->NotifyPreStateTypeChange(previous_state_type); + + if (window_state->window()->GetParent()) { + if (!window_state->HasRestoreBounds() && + (previous_state_type == WINDOW_STATE_TYPE_DEFAULT || + previous_state_type == WINDOW_STATE_TYPE_NORMAL) && + !window_state->IsMinimized() && !window_state->IsNormalStateType()) { + window_state->SaveCurrentBoundsForRestore(); + } + + // When restoring from a minimized state, we want to restore to the + // previous bounds. However, we want to maintain the restore bounds. + // (The restore bounds are set if a user maximized the window in one + // axis by double clicking the window border for example). + gfx::Rect restore_bounds_in_screen; + if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED && + window_state->IsNormalStateType() && window_state->HasRestoreBounds() && + !window_state->unminimize_to_restore_bounds()) { + restore_bounds_in_screen = window_state->GetRestoreBoundsInScreen(); + window_state->SaveCurrentBoundsForRestore(); + } + + if (window_state->IsMaximizedOrFullscreenOrPinned()) + MoveToDisplayForRestore(window_state); + + UpdateBoundsFromState(window_state, previous_state_type); + + // Normal state should have no restore bounds unless it's + // unminimized. + if (!restore_bounds_in_screen.IsEmpty()) + window_state->SetRestoreBoundsInScreen(restore_bounds_in_screen); + else if (window_state->IsNormalStateType()) + window_state->ClearRestoreBounds(); + } + window_state->NotifyPostStateTypeChange(previous_state_type); + + if (next_state_type == WINDOW_STATE_TYPE_PINNED || + previous_state_type == WINDOW_STATE_TYPE_PINNED || + next_state_type == WINDOW_STATE_TYPE_TRUSTED_PINNED || + previous_state_type == WINDOW_STATE_TYPE_TRUSTED_PINNED) { + WmShell::Get()->SetPinnedWindow(window_state->window()); + } +} + +void DefaultState::ReenterToCurrentState( + WindowState* window_state, + WindowState::State* state_in_previous_mode) { + WindowStateType previous_state_type = state_in_previous_mode->GetType(); + + // A state change should not move a window into or out of full screen or + // pinned since these are "special mode" the user wanted to be in and + // should be respected as such. + if (previous_state_type == wm::WINDOW_STATE_TYPE_FULLSCREEN || + previous_state_type == wm::WINDOW_STATE_TYPE_PINNED || + previous_state_type == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { + state_type_ = previous_state_type; + } else if (state_type_ == wm::WINDOW_STATE_TYPE_FULLSCREEN || + state_type_ == wm::WINDOW_STATE_TYPE_PINNED || + state_type_ == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { + state_type_ = previous_state_type; + } + + window_state->UpdateWindowShowStateFromStateType(); + window_state->NotifyPreStateTypeChange(previous_state_type); + + if ((state_type_ == wm::WINDOW_STATE_TYPE_NORMAL || + state_type_ == wm::WINDOW_STATE_TYPE_DEFAULT) && + !stored_bounds_.IsEmpty()) { + // Use the restore mechanism to set the bounds for + // the window in normal state. This also covers unminimize case. + window_state->SetRestoreBoundsInParent(stored_bounds_); + } + + UpdateBoundsFromState(window_state, state_in_previous_mode->GetType()); + + // Then restore the restore bounds to their previous value. + if (!stored_restore_bounds_.IsEmpty()) + window_state->SetRestoreBoundsInParent(stored_restore_bounds_); + else + window_state->ClearRestoreBounds(); + + window_state->NotifyPostStateTypeChange(previous_state_type); +} + +void DefaultState::UpdateBoundsFromState(WindowState* window_state, + WindowStateType previous_state_type) { + WmWindow* window = window_state->window(); + gfx::Rect bounds_in_parent; + switch (state_type_) { + case WINDOW_STATE_TYPE_LEFT_SNAPPED: + case WINDOW_STATE_TYPE_RIGHT_SNAPPED: + bounds_in_parent = + state_type_ == WINDOW_STATE_TYPE_LEFT_SNAPPED + ? GetDefaultLeftSnappedWindowBoundsInParent(window) + : GetDefaultRightSnappedWindowBoundsInParent(window); + break; + case WINDOW_STATE_TYPE_DOCKED: { + // TODO(afakhry): Remove in M58. + DCHECK(ash::switches::DockedWindowsEnabled()); + if (window->GetParent()->GetShellWindowId() != + kShellWindowId_DockedContainer) { + WmWindow* docked_container = + window->GetRootWindow()->GetChildByShellWindowId( + kShellWindowId_DockedContainer); + ReparentChildWithTransientChildren(window, window->GetParent(), + docked_container); + } + // Return early because we don't want to update the bounds of the + // window below; as the bounds are managed by the dock layout. + return; + } + case WINDOW_STATE_TYPE_DEFAULT: + case WINDOW_STATE_TYPE_NORMAL: { + gfx::Rect work_area_in_parent = GetDisplayWorkAreaBoundsInParent(window); + if (window_state->HasRestoreBounds()) { + bounds_in_parent = window_state->GetRestoreBoundsInParent(); + // Check if the |window|'s restored size is bigger than the working area + // This may happen if a window was resized to maximized bounds or if the + // display resolution changed while the window was maximized. + if (previous_state_type == WINDOW_STATE_TYPE_MAXIMIZED && + bounds_in_parent.width() >= work_area_in_parent.width() && + bounds_in_parent.height() >= work_area_in_parent.height()) { + bounds_in_parent = work_area_in_parent; + bounds_in_parent.Inset(kMaximizedWindowInset, kMaximizedWindowInset, + kMaximizedWindowInset, kMaximizedWindowInset); + } + } else { + bounds_in_parent = window->GetBounds(); + } + // Make sure that part of the window is always visible. + if (!window_state->is_dragged()) { + // Avoid doing this while the window is being dragged as its root + // window hasn't been updated yet in the case of dragging to another + // display. crbug.com/666836. + wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, + &bounds_in_parent); + } + break; + } + case WINDOW_STATE_TYPE_MAXIMIZED: + bounds_in_parent = GetMaximizedWindowBoundsInParent(window); + break; + + case WINDOW_STATE_TYPE_FULLSCREEN: + case WINDOW_STATE_TYPE_PINNED: + case WINDOW_STATE_TYPE_TRUSTED_PINNED: + bounds_in_parent = GetDisplayBoundsInParent(window); + break; + + case WINDOW_STATE_TYPE_DOCKED_MINIMIZED: + case WINDOW_STATE_TYPE_MINIMIZED: + break; + case WINDOW_STATE_TYPE_INACTIVE: + case WINDOW_STATE_TYPE_END: + case WINDOW_STATE_TYPE_AUTO_POSITIONED: + return; + } + + if (!window_state->IsMinimized()) { + if (IsMinimizedWindowState(previous_state_type) || + window_state->IsFullscreen() || window_state->IsPinned()) { + window_state->SetBoundsDirect(bounds_in_parent); + } else if (window_state->IsMaximized() || + IsMaximizedOrFullscreenOrPinnedWindowStateType( + previous_state_type)) { + window_state->SetBoundsDirectCrossFade(bounds_in_parent); + } else if (window_state->is_dragged()) { + // SetBoundsDirectAnimated does not work when the window gets reparented. + // TODO(oshima): Consider fixing it and reenable the animation. + window_state->SetBoundsDirect(bounds_in_parent); + } else { + window_state->SetBoundsDirectAnimated(bounds_in_parent); + } + } + + if (window_state->IsMinimized()) { + // Save the previous show state so that we can correctly restore it after + // exiting the minimized mode. + window->SetPreMinimizedShowState(ToWindowShowState(previous_state_type)); + window->SetVisibilityAnimationType( + WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); + + // Hide the window. + window->Hide(); + // Activate another window. + if (window_state->IsActive()) + window_state->Deactivate(); + } else if ((window->GetTargetVisibility() || + IsMinimizedWindowState(previous_state_type)) && + !window->GetLayerVisible()) { + // The layer may be hidden if the window was previously minimized. Make + // sure it's visible. + window->Show(); + if (IsMinimizedWindowState(previous_state_type) && + !window_state->IsMaximizedOrFullscreenOrPinned()) { + window_state->set_unminimize_to_restore_bounds(false); + } + } +} + +// static +void DefaultState::CenterWindow(WindowState* window_state) { + if (!window_state->IsNormalOrSnapped()) + return; + WmWindow* window = window_state->window(); + if (window_state->IsSnapped()) { + gfx::Rect center_in_screen = window->GetDisplayNearestWindow().work_area(); + gfx::Size size = window_state->HasRestoreBounds() + ? window_state->GetRestoreBoundsInScreen().size() + : window->GetBounds().size(); + center_in_screen.ClampToCenteredSize(size); + window_state->SetRestoreBoundsInScreen(center_in_screen); + window_state->Restore(); + } else { + gfx::Rect center_in_parent = GetDisplayWorkAreaBoundsInParent(window); + center_in_parent.ClampToCenteredSize(window->GetBounds().size()); + window_state->SetBoundsDirectAnimated(center_in_parent); + } + // Centering window is treated as if a user moved and resized the window. + window_state->set_bounds_changed_by_user(true); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/default_state.h b/ash/common/wm/default_state.h new file mode 100644 index 0000000..b7cee4c0 --- /dev/null +++ b/ash/common/wm/default_state.h
@@ -0,0 +1,82 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DEFAULT_STATE_H_ +#define ASH_COMMON_WM_DEFAULT_STATE_H_ + +#include "ash/common/wm/window_state.h" +#include "base/macros.h" +#include "ui/display/display.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { +namespace wm { +class SetBoundsEvent; + +// DefaultState implements Ash behavior without state machine. +class DefaultState : public WindowState::State { + public: + explicit DefaultState(WindowStateType initial_state_type); + ~DefaultState() override; + + // WindowState::State overrides: + void OnWMEvent(WindowState* window_state, const WMEvent* event) override; + WindowStateType GetType() const override; + void AttachState(WindowState* window_state, + WindowState::State* previous_state) override; + void DetachState(WindowState* window_state) override; + + private: + // Process state dependent events, such as TOGGLE_MAXIMIZED, + // TOGGLE_FULLSCREEN. + static bool ProcessCompoundEvents(WindowState* window_state, + const WMEvent* event); + + // Process workspace related events, such as DISPLAY_BOUNDS_CHANGED. + static bool ProcessWorkspaceEvents(WindowState* window_state, + const WMEvent* event); + + // Set the fullscreen/maximized bounds without animation. + static bool SetMaximizedOrFullscreenBounds(wm::WindowState* window_state); + + static void SetBounds(WindowState* window_state, + const SetBoundsEvent* bounds_event); + + static void CenterWindow(WindowState* window_state); + + // Enters next state. This is used when the state moves from one to another + // within the same desktop mode. + void EnterToNextState(wm::WindowState* window_state, + wm::WindowStateType next_state_type); + + // Reenters the current state. This is called when migrating from + // previous desktop mode, and the window's state needs to re-construct the + // state/bounds for this state. + void ReenterToCurrentState(wm::WindowState* window_state, + wm::WindowState::State* state_in_previous_mode); + + // Animates to new window bounds based on the current and previous state type. + void UpdateBoundsFromState(wm::WindowState* window_state, + wm::WindowStateType old_state_type); + + // The current type of the window. + WindowStateType state_type_; + + // The saved window state for the case that the state gets de-/activated. + gfx::Rect stored_bounds_; + gfx::Rect stored_restore_bounds_; + + // The display state in which the mode got started. + display::Display stored_display_state_; + + // The window state only gets remembered for DCHECK reasons. + WindowState* stored_window_state_; + + DISALLOW_COPY_AND_ASSIGN(DefaultState); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_DEFAULT_STATE_H_
diff --git a/ash/common/wm/default_window_resizer.cc b/ash/common/wm/default_window_resizer.cc new file mode 100644 index 0000000..6a6102a --- /dev/null +++ b/ash/common/wm/default_window_resizer.cc
@@ -0,0 +1,53 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/default_window_resizer.h" + +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" + +namespace ash { + +DefaultWindowResizer::~DefaultWindowResizer() { + shell_->UnlockCursor(); +} + +// static +DefaultWindowResizer* DefaultWindowResizer::Create( + wm::WindowState* window_state) { + return new DefaultWindowResizer(window_state); +} + +void DefaultWindowResizer::Drag(const gfx::Point& location, int event_flags) { + gfx::Rect bounds(CalculateBoundsForDrag(location)); + if (bounds != GetTarget()->GetBounds()) { + if (!did_move_or_resize_ && !details().restore_bounds.IsEmpty()) + window_state_->ClearRestoreBounds(); + did_move_or_resize_ = true; + GetTarget()->SetBounds(bounds); + } +} + +void DefaultWindowResizer::CompleteDrag() {} + +void DefaultWindowResizer::RevertDrag() { + if (!did_move_or_resize_) + return; + + GetTarget()->SetBounds(details().initial_bounds_in_parent); + + if (!details().restore_bounds.IsEmpty()) + window_state_->SetRestoreBoundsInScreen(details().restore_bounds); +} + +DefaultWindowResizer::DefaultWindowResizer(wm::WindowState* window_state) + : WindowResizer(window_state), + did_move_or_resize_(false), + shell_(GetTarget()->GetShell()) { + DCHECK(details().is_resizable); + shell_->LockCursor(); +} + +} // namespace aura
diff --git a/ash/common/wm/default_window_resizer.h b/ash/common/wm/default_window_resizer.h new file mode 100644 index 0000000..34022ca --- /dev/null +++ b/ash/common/wm/default_window_resizer.h
@@ -0,0 +1,51 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DEFAULT_WINDOW_RESIZER_H_ +#define ASH_COMMON_WM_DEFAULT_WINDOW_RESIZER_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm/window_resizer.h" +#include "base/macros.h" + +namespace ash { +class WmShell; + +// WindowResizer is used by ToplevelWindowEventFilter to handle dragging, moving +// or resizing a window. All coordinates passed to this are in the parent +// windows coordiantes. +class ASH_EXPORT DefaultWindowResizer : public WindowResizer { + public: + ~DefaultWindowResizer() override; + + // Creates a new DefaultWindowResizer. The caller takes ownership of the + // returned object. + static DefaultWindowResizer* Create(wm::WindowState* window_state); + + // Returns true if the drag will result in changing the window in anyway. + bool is_resizable() const { return details().is_resizable; } + + bool changed_size() const { + return !(details().bounds_change & kBoundsChange_Repositions); + } + + // WindowResizer: + void Drag(const gfx::Point& location, int event_flags) override; + void CompleteDrag() override; + void RevertDrag() override; + + private: + explicit DefaultWindowResizer(wm::WindowState* window_state); + + // Set to true once Drag() is invoked and the bounds of the window change. + bool did_move_or_resize_; + + WmShell* shell_; + + DISALLOW_COPY_AND_ASSIGN(DefaultWindowResizer); +}; + +} // namespace aura + +#endif // ASH_COMMON_WM_DEFAULT_WINDOW_RESIZER_H_
diff --git a/ash/common/wm/dock/dock_types.h b/ash/common/wm/dock/dock_types.h new file mode 100644 index 0000000..02e8b450 --- /dev/null +++ b/ash/common/wm/dock/dock_types.h
@@ -0,0 +1,53 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DOCK_DOCK_TYPES_H_ +#define ASH_COMMON_WM_DOCK_DOCK_TYPES_H_ + +namespace ash { + +// Possible values of which side of the screen the windows are docked at. +// This is used by DockedwindowLayoutManager and DockedWindowResizer to +// implement docking behavior including magnetism while dragging windows into +// or out of the docked windows area. +enum DockedAlignment { + // No docked windows. + DOCKED_ALIGNMENT_NONE, + + // Some windows are already docked on the left side of the screen. + DOCKED_ALIGNMENT_LEFT, + + // Some windows are already docked on the right side of the screen. + DOCKED_ALIGNMENT_RIGHT, +}; + +// User action recorded for use in UMA histograms. +enum DockedAction { + DOCKED_ACTION_NONE, // Regular drag of undocked window. Not recorded. + DOCKED_ACTION_DOCK, // Dragged and docked a window. + DOCKED_ACTION_UNDOCK, // Dragged and undocked a window. + DOCKED_ACTION_RESIZE, // Resized a docked window. + DOCKED_ACTION_REORDER, // Possibly reordered docked windows. + DOCKED_ACTION_EVICT, // A docked window could not stay docked. + DOCKED_ACTION_MAXIMIZE, // Maximized a docked window. + DOCKED_ACTION_MINIMIZE, // Minimized a docked window. + DOCKED_ACTION_RESTORE, // Restored a docked window that was minimized. + DOCKED_ACTION_CLOSE, // Closed a window while it was docked. + DOCKED_ACTION_COUNT, // Maximum value of this enum for histograms use. +}; + +// Event source for the docking user action (when known). +enum DockedActionSource { + DOCKED_ACTION_SOURCE_UNKNOWN, + DOCKED_ACTION_SOURCE_MOUSE, + DOCKED_ACTION_SOURCE_TOUCH, + DOCKED_ACTION_SOURCE_KEYBOARD, + + // Maximum value of this enum for histograms use. + DOCKED_ACTION_SOURCE_COUNT, +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_DOCK_DOCK_TYPES_H_
diff --git a/ash/common/wm/dock/docked_window_layout_manager.cc b/ash/common/wm/dock/docked_window_layout_manager.cc new file mode 100644 index 0000000..fb373ec --- /dev/null +++ b/ash/common/wm/dock/docked_window_layout_manager.cc
@@ -0,0 +1,1336 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/dock/docked_window_layout_manager.h" + +#include "ash/animation/animation_change_type.h" +#include "ash/common/shelf/shelf_background_animator.h" +#include "ash/common/shelf/shelf_background_animator_observer.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/window_parenting_utils.h" +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_state_aura.h" +#include "base/auto_reset.h" +#include "base/metrics/histogram_macros.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/views/background.h" +#include "ui/wm/core/coordinate_conversion.h" +#include "ui/wm/core/window_animations.h" + +namespace ash { + +// Minimum, maximum width of the dock area and a width of the gap +// static +const int DockedWindowLayoutManager::kMaxDockWidth = 360; +// static +const int DockedWindowLayoutManager::kMinDockWidth = 200; +// static +const int DockedWindowLayoutManager::kMinDockGap = 2; +// static +const int DockedWindowLayoutManager::kIdealWidth = 250; +const int kMinimumHeight = 250; +const int kSlideDurationMs = 120; +const int kFadeDurationMs = 60; +const int kMinimizeDurationMs = 720; + +class DockedBackgroundWidget : public views::Widget, + public WmShelfObserver, + public ShelfBackgroundAnimatorObserver { + public: + explicit DockedBackgroundWidget(DockedWindowLayoutManager* manager) + : manager_(manager), + alignment_(DOCKED_ALIGNMENT_NONE), + background_animator_(SHELF_BACKGROUND_DEFAULT, + nullptr, + WmShell::Get()->wallpaper_controller()), + opaque_background_(ui::LAYER_SOLID_COLOR), + visible_background_type_(manager_->shelf()->GetBackgroundType()), + visible_background_change_type_(AnimationChangeType::IMMEDIATE) { + manager_->shelf()->AddObserver(this); + InitWidget(manager_->dock_container()); + + background_animator_.AddObserver(this); + } + + ~DockedBackgroundWidget() override { + background_animator_.RemoveObserver(this); + manager_->shelf()->RemoveObserver(this); + } + + // Sets widget bounds and sizes opaque background layer to fill the widget. + void SetBackgroundBounds(const gfx::Rect& bounds, DockedAlignment alignment) { + SetBounds(bounds); + opaque_background_.SetBounds(gfx::Rect(bounds.size())); + alignment_ = alignment; + } + + private: + // views::Widget: + void OnNativeWidgetVisibilityChanged(bool visible) override { + views::Widget::OnNativeWidgetVisibilityChanged(visible); + UpdateBackground(); + } + + // ShelfBackgroundAnimatorObserver: + void UpdateShelfBackground(SkColor color) override { + opaque_background_.SetColor(color); + } + + // WmShelfObserver: + void OnBackgroundTypeChanged(ShelfBackgroundType background_type, + AnimationChangeType change_type) override { + // Sets the background type. Starts an animation to transition to + // |background_type| if the widget is visible. If the widget is not visible, + // the animation is postponed till the widget becomes visible. + visible_background_type_ = background_type; + visible_background_change_type_ = change_type; + if (IsVisible()) + UpdateBackground(); + } + + void InitWidget(WmWindow* parent) { + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.keep_on_top = false; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.accept_events = false; + set_focus_on_creation(false); + parent->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + this, parent->GetShellWindowId(), ¶ms); + Init(params); + SetVisibilityChangedAnimationsEnabled(false); + WmWindow* wm_window = WmWindow::Get(this->GetNativeWindow()); + wm_window->SetLockedToRoot(true); + opaque_background_.SetColor(SK_ColorBLACK); + opaque_background_.SetBounds(gfx::Rect(GetWindowBoundsInScreen().size())); + opaque_background_.SetOpacity(0.0f); + wm_window->GetLayer()->Add(&opaque_background_); + + // This background should be explicitly stacked below any windows already in + // the dock, otherwise the z-order is set by the order in which windows were + // added to the container, and UpdateStacking only manages user windows, not + // the background widget. + parent->StackChildAtBottom(wm_window); + } + + // Transitions to |visible_background_type_| if the widget is visible and to + // SHELF_BACKGROUND_DEFAULT if it is not. + void UpdateBackground() { + ShelfBackgroundType background_type = + IsVisible() ? visible_background_type_ : SHELF_BACKGROUND_DEFAULT; + AnimationChangeType change_type = IsVisible() + ? visible_background_change_type_ + : AnimationChangeType::IMMEDIATE; + background_animator_.PaintBackground(background_type, change_type); + SchedulePaintInRect(gfx::Rect(GetWindowBoundsInScreen().size())); + } + + DockedWindowLayoutManager* manager_; + + DockedAlignment alignment_; + + // The animator for the background transitions. + ShelfBackgroundAnimator background_animator_; + + // TODO(bruthig): Remove opaque_background_ (see https://crbug.com/621551). + // Solid black background that can be made fully opaque. + ui::Layer opaque_background_; + + // The background type to use when the widget is visible. When not visible, + // the widget uses SHELF_BACKGROUND_DEFAULT. + ShelfBackgroundType visible_background_type_; + + // Whether the widget should animate to |visible_background_type_|. + AnimationChangeType visible_background_change_type_; + + DISALLOW_COPY_AND_ASSIGN(DockedBackgroundWidget); +}; + +namespace { + +// Returns true if a window is a popup or a transient child. +bool IsPopupOrTransient(const WmWindow* window) { + return (window->GetType() == ui::wm::WINDOW_TYPE_POPUP || + window->GetTransientParent()); +} + +// Certain windows (minimized, hidden or popups) are not docked and are ignored +// by layout logic even when they are children of a docked container. +bool IsWindowDocked(const WmWindow* window) { + return (window->IsVisible() && !window->GetWindowState()->IsMinimized() && + !IsPopupOrTransient(window)); +} + +void UndockWindow(WmWindow* window) { + gfx::Rect previous_bounds = window->GetBounds(); + WmWindow* old_parent = window->GetParent(); + window->SetParentUsingContext(window, gfx::Rect()); + if (window->GetParent() != old_parent) { + wm::ReparentTransientChildrenOfChild(window, old_parent, + window->GetParent()); + } + // Start maximize or fullscreen (affecting packaged apps) animation from + // previous window bounds. + window->GetLayer()->SetBounds(previous_bounds); +} + +// Returns width that is as close as possible to |target_width| while being +// consistent with docked min and max restrictions and respects the |window|'s +// minimum and maximum size. +int GetWindowWidthCloseTo(const WmWindow* window, int target_width) { + if (!window->GetWindowState()->CanResize()) { + DCHECK_LE(window->GetBounds().width(), + DockedWindowLayoutManager::kMaxDockWidth); + return window->GetBounds().width(); + } + int width = std::max( + DockedWindowLayoutManager::kMinDockWidth, + std::min(target_width, DockedWindowLayoutManager::kMaxDockWidth)); + width = std::max(width, window->GetMinimumSize().width()); + if (window->GetMaximumSize().width() != 0) + width = std::min(width, window->GetMaximumSize().width()); + DCHECK_LE(width, DockedWindowLayoutManager::kMaxDockWidth); + return width; +} + +// Returns height that is as close as possible to |target_height| while +// respecting the |window|'s minimum and maximum size. +int GetWindowHeightCloseTo(const WmWindow* window, int target_height) { + if (!window->GetWindowState()->CanResize()) + return window->GetBounds().height(); + int minimum_height = + std::max(kMinimumHeight, window->GetMinimumSize().height()); + int maximum_height = window->GetMaximumSize().height(); + if (minimum_height) + target_height = std::max(target_height, minimum_height); + if (maximum_height) + target_height = std::min(target_height, maximum_height); + return target_height; +} + +} // namespace + +struct DockedWindowLayoutManager::WindowWithHeight { + explicit WindowWithHeight(WmWindow* window) + : window(window), height(window->GetBounds().height()) {} + WmWindow* window; + int height; +}; + +// A functor used to sort the windows in order of their minimum height. +struct DockedWindowLayoutManager::CompareMinimumHeight { + bool operator()(const WindowWithHeight& win1, const WindowWithHeight& win2) { + return GetWindowHeightCloseTo(win1.window, 0) < + GetWindowHeightCloseTo(win2.window, 0); + } +}; + +// A functor used to sort the windows in order of their center Y position. +// |delta| is a pre-calculated distance from the bottom of one window to the top +// of the next. Its value can be positive (gap) or negative (overlap). +// Half of |delta| is used as a transition point at which windows could ideally +// swap positions. +struct DockedWindowLayoutManager::CompareWindowPos { + CompareWindowPos(WmWindow* dragged_window, + WmWindow* docked_container, + float delta) + : dragged_window_(dragged_window), + docked_container_(docked_container), + delta_(delta / 2) {} + + bool operator()(const WindowWithHeight& window_with_height1, + const WindowWithHeight& window_with_height2) { + // Use target coordinates since animations may be active when windows are + // reordered. + WmWindow* win1(window_with_height1.window); + WmWindow* win2(window_with_height2.window); + gfx::Rect win1_bounds = + docked_container_->ConvertRectToScreen(win1->GetTargetBounds()); + gfx::Rect win2_bounds = + docked_container_->ConvertRectToScreen(win2->GetTargetBounds()); + win1_bounds.set_height(window_with_height1.height); + win2_bounds.set_height(window_with_height2.height); + // If one of the windows is the |dragged_window_| attempt to make an + // earlier swap between the windows than just based on their centers. + // This is possible if the dragged window is at least as tall as the other + // window. + if (win1 == dragged_window_) + return compare_two_windows(win1_bounds, win2_bounds); + if (win2 == dragged_window_) + return !compare_two_windows(win2_bounds, win1_bounds); + // Otherwise just compare the centers. + return win1_bounds.CenterPoint().y() < win2_bounds.CenterPoint().y(); + } + + // Based on center point tries to deduce where the drag is coming from. + // When dragging from below up the transition point is lower. + // When dragging from above down the transition point is higher. + bool compare_bounds(const gfx::Rect& dragged, const gfx::Rect& other) { + if (dragged.CenterPoint().y() < other.CenterPoint().y()) + return dragged.CenterPoint().y() < other.y() - delta_; + return dragged.CenterPoint().y() < other.bottom() + delta_; + } + + // Performs comparison both ways and selects stable result. + bool compare_two_windows(const gfx::Rect& bounds1, const gfx::Rect& bounds2) { + // Try comparing windows in both possible orders and see if the comparison + // is stable. + bool result1 = compare_bounds(bounds1, bounds2); + bool result2 = compare_bounds(bounds2, bounds1); + if (result1 != result2) + return result1; + + // Otherwise it is not possible to be sure that the windows will not bounce. + // In this case just compare the centers. + return bounds1.CenterPoint().y() < bounds2.CenterPoint().y(); + } + + private: + WmWindow* dragged_window_; + WmWindow* docked_container_; + float delta_; +}; + +//////////////////////////////////////////////////////////////////////////////// +// A class that observes shelf for bounds changes. +class DockedWindowLayoutManager::ShelfWindowObserver + : public aura::WindowObserver { + public: + explicit ShelfWindowObserver(DockedWindowLayoutManager* docked_layout_manager) + : docked_layout_manager_(docked_layout_manager) { + DCHECK(docked_layout_manager_->shelf()->GetWindow()); + docked_layout_manager_->shelf()->GetWindow()->aura_window()->AddObserver( + this); + } + + ~ShelfWindowObserver() override { + if (docked_layout_manager_->shelf() && + docked_layout_manager_->shelf()->GetWindow()) { + docked_layout_manager_->shelf() + ->GetWindow() + ->aura_window() + ->RemoveObserver(this); + } + } + + // aura::WindowObserver: + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override { + shelf_bounds_in_screen_ = new_bounds; + ::wm::ConvertRectToScreen(window->parent(), &shelf_bounds_in_screen_); + + // When the shelf is auto-hidden, it has an invisible height of 3px used + // as a hit region which is specific to Chrome OS MD (for non-MD, the 3 + // pixels are visible). In computing the work area we should consider a + // hidden shelf as having a height of 0 (for non-MD, shelf height is 3). + if (docked_layout_manager_->shelf()->GetAutoHideState() == + ShelfAutoHideState::SHELF_AUTO_HIDE_HIDDEN) { + shelf_bounds_in_screen_.set_height( + GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE)); + } + docked_layout_manager_->OnShelfBoundsChanged(); + } + + const gfx::Rect& shelf_bounds_in_screen() const { + return shelf_bounds_in_screen_; + } + + private: + DockedWindowLayoutManager* docked_layout_manager_; + gfx::Rect shelf_bounds_in_screen_; + + DISALLOW_COPY_AND_ASSIGN(ShelfWindowObserver); +}; + +//////////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager public implementation: +DockedWindowLayoutManager::DockedWindowLayoutManager(WmWindow* dock_container) + : dock_container_(dock_container), + root_window_controller_(dock_container->GetRootWindowController()), + in_layout_(false), + dragged_window_(nullptr), + is_dragged_window_docked_(false), + is_dragged_from_dock_(false), + shelf_(nullptr), + in_fullscreen_(root_window_controller_->GetWorkspaceWindowState() == + wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN), + docked_width_(0), + in_overview_(false), + alignment_(DOCKED_ALIGNMENT_NONE), + preferred_alignment_(DOCKED_ALIGNMENT_NONE), + event_source_(DOCKED_ACTION_SOURCE_UNKNOWN), + last_active_window_(nullptr), + last_action_time_(base::Time::Now()), + background_widget_(nullptr) { + DCHECK(dock_container); + dock_container_->GetShell()->AddShellObserver(this); + dock_container->GetShell()->AddActivationObserver(this); + display::Screen::GetScreen()->AddObserver(this); +} + +DockedWindowLayoutManager::~DockedWindowLayoutManager() { + Shutdown(); +} + +// static +DockedWindowLayoutManager* DockedWindowLayoutManager::Get(WmWindow* window) { + if (!window) + return nullptr; + + WmWindow* root = window->GetRootWindow(); + return static_cast<DockedWindowLayoutManager*>( + root->GetChildByShellWindowId(kShellWindowId_DockedContainer) + ->GetLayoutManager()); +} + +void DockedWindowLayoutManager::Shutdown() { + background_widget_.reset(); + shelf_observer_.reset(); + shelf_ = nullptr; + for (WmWindow* child : dock_container_->GetChildren()) { + child->aura_window()->RemoveObserver(this); + child->GetWindowState()->RemoveObserver(this); + } + dock_container_->GetShell()->RemoveActivationObserver(this); + dock_container_->GetShell()->RemoveShellObserver(this); + display::Screen::GetScreen()->RemoveObserver(this); +} + +void DockedWindowLayoutManager::AddObserver( + DockedWindowLayoutManagerObserver* observer) { + observer_list_.AddObserver(observer); +} + +void DockedWindowLayoutManager::RemoveObserver( + DockedWindowLayoutManagerObserver* observer) { + observer_list_.RemoveObserver(observer); +} + +void DockedWindowLayoutManager::StartDragging(WmWindow* window) { + DCHECK(!dragged_window_); + dragged_window_ = window; + DCHECK(!IsPopupOrTransient(window)); + // Start observing a window unless it is docked container's child in which + // case it is already observed. + wm::WindowState* dragged_state = dragged_window_->GetWindowState(); + if (dragged_window_->GetParent() != dock_container_) { + dragged_window_->aura_window()->AddObserver(this); + dragged_state->AddObserver(this); + } else if (!IsAnyWindowDocked() && dragged_state->drag_details() && + !(dragged_state->drag_details()->bounds_change & + WindowResizer::kBoundsChange_Resizes)) { + // If there are no other docked windows clear alignment when a docked window + // is moved (but not when it is resized or the window could get undocked + // when resized away from the edge while docked). + alignment_ = DOCKED_ALIGNMENT_NONE; + } + is_dragged_from_dock_ = window->GetParent() == dock_container_; + DCHECK(!is_dragged_window_docked_); + + // Resize all windows that are flush with the dock edge together if one of + // them gets resized. + if (dragged_window_->GetBounds().width() == docked_width_ && + (dragged_state->drag_details()->bounds_change & + WindowResizer::kBoundsChange_Resizes) && + (dragged_state->drag_details()->size_change_direction & + WindowResizer::kBoundsChangeDirection_Horizontal)) { + for (WmWindow* window1 : dock_container_->GetChildren()) { + if (IsWindowDocked(window1) && window1 != dragged_window_ && + window1->GetBounds().width() == docked_width_) { + window1->GetWindowState()->set_bounds_changed_by_user(false); + } + } + } +} + +void DockedWindowLayoutManager::DockDraggedWindow(WmWindow* window) { + DCHECK(!IsPopupOrTransient(window)); + OnDraggedWindowDocked(window); + Relayout(); +} + +void DockedWindowLayoutManager::UndockDraggedWindow() { + DCHECK(!IsPopupOrTransient(dragged_window_)); + OnDraggedWindowUndocked(); + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); + is_dragged_from_dock_ = false; +} + +void DockedWindowLayoutManager::FinishDragging(DockedAction action, + DockedActionSource source) { + DCHECK(dragged_window_); + DCHECK(!IsPopupOrTransient(dragged_window_)); + if (is_dragged_window_docked_) + OnDraggedWindowUndocked(); + DCHECK(!is_dragged_window_docked_); + // Stop observing a window unless it is docked container's child in which + // case it needs to keep being observed after the drag completes. + if (dragged_window_->GetParent() != dock_container_) { + dragged_window_->aura_window()->RemoveObserver(this); + dragged_window_->GetWindowState()->RemoveObserver(this); + if (last_active_window_ == dragged_window_) + last_active_window_ = nullptr; + } else { + // If this is the first window that got docked by a move update alignment. + if (alignment_ == DOCKED_ALIGNMENT_NONE) + alignment_ = GetEdgeNearestWindow(dragged_window_); + // A window is no longer dragged and is a child. + // When a window becomes a child at drag start this is + // the only opportunity we will have to enforce a window + // count limit so do it here. + MaybeMinimizeChildrenExcept(dragged_window_); + } + dragged_window_ = nullptr; + dragged_bounds_ = gfx::Rect(); + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); + RecordUmaAction(action, source); +} + +void DockedWindowLayoutManager::SetShelf(WmShelf* shelf) { + DCHECK(!shelf_); + shelf_ = shelf; + shelf_observer_.reset(new ShelfWindowObserver(this)); +} + +DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow( + const WmWindow* window) const { + const gfx::Rect& bounds(window->GetBoundsInScreen()); + + // Test overlap with an existing docked area first. + if (docked_bounds_.Intersects(bounds) && + alignment_ != DOCKED_ALIGNMENT_NONE) { + // A window is being added to other docked windows (on the same side). + return alignment_; + } + + const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen(); + if (bounds.x() <= container_bounds.x() && + bounds.right() > container_bounds.x()) { + return DOCKED_ALIGNMENT_LEFT; + } else if (bounds.x() < container_bounds.right() && + bounds.right() >= container_bounds.right()) { + return DOCKED_ALIGNMENT_RIGHT; + } + return DOCKED_ALIGNMENT_NONE; +} + +DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const { + return CalculateAlignmentExcept(dragged_window_); +} + +DockedAlignment DockedWindowLayoutManager::CalculateAlignmentExcept( + const WmWindow* window) const { + // Find a child that is not the window being queried and is not a popup. + // If such exists the current alignment is returned - even if some of the + // children are hidden or minimized (so they can be restored without losing + // the docked state). + for (WmWindow* child : dock_container_->GetChildren()) { + if (window != child && !IsPopupOrTransient(child)) + return alignment_; + } + // No docked windows remain other than possibly the window being queried. + // Return |NONE| to indicate that windows may get docked on either side. + return DOCKED_ALIGNMENT_NONE; +} + +bool DockedWindowLayoutManager::CanDockWindow( + WmWindow* window, + DockedAlignment desired_alignment) { + // Don't allow interactive docking of windows with transient parents such as + // modal browser dialogs. Prevent docking of panels attached to shelf during + // the drag. + wm::WindowState* window_state = window->GetWindowState(); + bool should_attach_to_shelf = + window_state->drag_details() && + window_state->drag_details()->should_attach_to_shelf; + if (IsPopupOrTransient(window) || should_attach_to_shelf) + return false; + // If a window is wide and cannot be resized down to maximum width allowed + // then it cannot be docked. + // TODO(varkha). Prevent windows from changing size programmatically while + // they are docked. The size will take effect only once a window is undocked. + // See http://crbug.com/307792. + if (window->GetBounds().width() > kMaxDockWidth && + (!window_state->CanResize() || + (window->GetMinimumSize().width() != 0 && + window->GetMinimumSize().width() > kMaxDockWidth))) { + return false; + } + // If a window is tall and cannot be resized down to maximum height allowed + // then it cannot be docked. + const gfx::Rect work_area = + dock_container_->GetDisplayNearestWindow().work_area(); + if (GetWindowHeightCloseTo(window, work_area.height()) > work_area.height()) + return false; + // Cannot dock on the other size from an existing dock. + const DockedAlignment alignment = CalculateAlignmentExcept(window); + if (desired_alignment != DOCKED_ALIGNMENT_NONE && + alignment != DOCKED_ALIGNMENT_NONE && alignment != desired_alignment) { + return false; + } + // Do not allow docking on the same side as shelf. + return IsDockedAlignmentValid(desired_alignment); +} + +bool DockedWindowLayoutManager::IsDockedAlignmentValid( + DockedAlignment alignment) const { + ShelfAlignment shelf_alignment = + shelf_ ? shelf_->GetAlignment() : SHELF_ALIGNMENT_BOTTOM; + if ((alignment == DOCKED_ALIGNMENT_LEFT && + shelf_alignment == SHELF_ALIGNMENT_LEFT) || + (alignment == DOCKED_ALIGNMENT_RIGHT && + shelf_alignment == SHELF_ALIGNMENT_RIGHT)) { + return false; + } + return true; +} + +void DockedWindowLayoutManager::MaybeSetDesiredDockedAlignment( + DockedAlignment alignment) { + // If the requested alignment is |NONE| or there are no + // docked windows return early as we can't change whether there is a + // dock or not. If the requested alignment is the same as the current + // alignment return early as an optimization. + if (alignment == DOCKED_ALIGNMENT_NONE || + alignment_ == DOCKED_ALIGNMENT_NONE || alignment_ == alignment || + !IsDockedAlignmentValid(alignment)) { + return; + } + alignment_ = alignment; + + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} + +void DockedWindowLayoutManager::OnShelfBoundsChanged() { + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_INSETS_CHANGED); +} + +//////////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager, aura::LayoutManager implementation: +void DockedWindowLayoutManager::OnWindowResized() { + MaybeMinimizeChildrenExcept(dragged_window_); + Relayout(); + // When screen resizes update the insets even when dock width or alignment + // does not change. + UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_RESIZED); +} + +void DockedWindowLayoutManager::OnWindowAddedToLayout(WmWindow* child) { + if (IsPopupOrTransient(child)) + return; + // Dragged windows are already observed by StartDragging and do not change + // docked alignment during the drag. + if (child == dragged_window_) + return; + // If this is the first window getting docked - update alignment. + // A window can be added without proper bounds when window is moved to another + // display via API or due to display configuration change, so the alignment + // is set based on which edge is closer in the new display. + if (alignment_ == DOCKED_ALIGNMENT_NONE) { + alignment_ = preferred_alignment_ != DOCKED_ALIGNMENT_NONE + ? preferred_alignment_ + : GetEdgeNearestWindow(child); + } + MaybeMinimizeChildrenExcept(child); + child->aura_window()->AddObserver(this); + child->GetWindowState()->AddObserver(this); + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); + + // Only keyboard-initiated actions are recorded here. Dragging cases + // are handled in FinishDragging. + if (event_source_ != DOCKED_ACTION_SOURCE_UNKNOWN) + RecordUmaAction(DOCKED_ACTION_DOCK, event_source_); +} + +void DockedWindowLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) { + if (IsPopupOrTransient(child)) + return; + // Dragged windows are stopped being observed by FinishDragging and do not + // change alignment during the drag. They also cannot be set to be the + // |last_active_window_|. + if (child == dragged_window_) + return; + // If this is the last window, set alignment and maximize the workspace. + if (!IsAnyWindowDocked()) { + alignment_ = DOCKED_ALIGNMENT_NONE; + UpdateDockedWidth(0); + } + if (last_active_window_ == child) + last_active_window_ = nullptr; + child->aura_window()->RemoveObserver(this); + child->GetWindowState()->RemoveObserver(this); + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} + +void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) { + if (IsPopupOrTransient(child)) + return; + + wm::WindowState* window_state = child->GetWindowState(); + if (visible && window_state->IsMinimized()) + window_state->Restore(); + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} + +void DockedWindowLayoutManager::SetChildBounds( + WmWindow* child, + const gfx::Rect& requested_bounds) { + // The minimum constraints have to be applied first by the layout manager. + gfx::Rect actual_new_bounds(requested_bounds); + if (child->HasNonClientArea()) { + const gfx::Size min_size = child->GetMinimumSize(); + actual_new_bounds.set_width( + std::max(min_size.width(), actual_new_bounds.width())); + actual_new_bounds.set_height( + std::max(min_size.height(), actual_new_bounds.height())); + } + if (IsWindowDocked(child) && child != dragged_window_) + return; + wm::WmSnapToPixelLayoutManager::SetChildBounds(child, actual_new_bounds); + if (IsPopupOrTransient(child)) + return; + // Whenever one of our windows is moved or resized enforce layout. + if (shelf_) + shelf_->UpdateVisibilityState(); +} + +//////////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager, display::DisplayObserver implementation: + +void DockedWindowLayoutManager::OnDisplayMetricsChanged( + const display::Display& display, + uint32_t changed_metrics) { + if (dock_container_->GetDisplayNearestWindow().id() != display.id()) + return; + + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_INSETS_CHANGED); + MaybeMinimizeChildrenExcept(dragged_window_); +} + +///////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager, WindowStateObserver implementation: + +void DockedWindowLayoutManager::OnPreWindowStateTypeChange( + wm::WindowState* window_state, + wm::WindowStateType old_type) { + WmWindow* window = window_state->window(); + if (IsPopupOrTransient(window)) + return; + // The window property will still be set, but no actual change will occur + // until OnFullscreenStateChange is called when exiting fullscreen. + if (in_fullscreen_) + return; + if (!window_state->IsDocked()) { + if (window != dragged_window_) { + UndockWindow(window); + if (window_state->IsMaximizedOrFullscreenOrPinned()) + RecordUmaAction(DOCKED_ACTION_MAXIMIZE, event_source_); + else + RecordUmaAction(DOCKED_ACTION_UNDOCK, event_source_); + } + } else if (window_state->IsMinimized()) { + MinimizeDockedWindow(window_state); + } else if (old_type == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED) { + RestoreDockedWindow(window_state); + } else if (old_type == wm::WINDOW_STATE_TYPE_MINIMIZED) { + NOTREACHED() << "Minimized window in docked layout manager"; + } +} + +///////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager, WindowObserver implementation: + +void DockedWindowLayoutManager::OnWindowBoundsChanged( + aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + // Only relayout if the dragged window would get docked. + if (WmWindow::Get(window) == dragged_window_ && is_dragged_window_docked_) + Relayout(); +} + +void DockedWindowLayoutManager::OnWindowVisibilityChanging(aura::Window* window, + bool visible) { + if (IsPopupOrTransient(WmWindow::Get(window))) + return; + int animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT; + if (visible) { + animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DROP; + ::wm::SetWindowVisibilityAnimationDuration( + window, base::TimeDelta::FromMilliseconds(kFadeDurationMs)); + } else if (wm::GetWindowState(window)->IsMinimized()) { + animation_type = wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE; + } + ::wm::SetWindowVisibilityAnimationType(window, animation_type); +} + +void DockedWindowLayoutManager::OnWindowDestroying(aura::Window* window) { + if (dragged_window_ == WmWindow::Get(window)) { + FinishDragging(DOCKED_ACTION_NONE, DOCKED_ACTION_SOURCE_UNKNOWN); + DCHECK(!dragged_window_); + DCHECK(!is_dragged_window_docked_); + } + if (WmWindow::Get(window) == last_active_window_) + last_active_window_ = nullptr; + RecordUmaAction(DOCKED_ACTION_CLOSE, event_source_); +} + +//////////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager, WmActivationObserver implementation: + +void DockedWindowLayoutManager::OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) { + if (gained_active && IsPopupOrTransient(gained_active)) + return; + // Ignore if the window that is not managed by this was activated. + WmWindow* ancestor = nullptr; + for (WmWindow* parent = gained_active; parent; parent = parent->GetParent()) { + if (parent->GetParent() == dock_container_) { + ancestor = parent; + break; + } + } + if (ancestor) { + // Window activation from overview mode may unminimize a window and require + // layout update. + MaybeMinimizeChildrenExcept(gained_active); + Relayout(); + UpdateStacking(ancestor); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager, ShellObserver implementation: + +void DockedWindowLayoutManager::OnShelfAlignmentChanged(WmWindow* root_window) { + if (!shelf_ || alignment_ == DOCKED_ALIGNMENT_NONE || + root_window != shelf_->GetWindow()->GetRootWindow()) { + return; + } + + // Do not allow shelf and dock on the same side. Switch side that + // the dock is attached to and move all dock windows to that new side. + ShelfAlignment shelf_alignment = shelf_->GetAlignment(); + if (alignment_ == DOCKED_ALIGNMENT_LEFT && + shelf_alignment == SHELF_ALIGNMENT_LEFT) { + alignment_ = DOCKED_ALIGNMENT_RIGHT; + } else if (alignment_ == DOCKED_ALIGNMENT_RIGHT && + shelf_alignment == SHELF_ALIGNMENT_RIGHT) { + alignment_ = DOCKED_ALIGNMENT_LEFT; + } + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::SHELF_ALIGNMENT_CHANGED); +} + +void DockedWindowLayoutManager::OnFullscreenStateChanged( + bool is_fullscreen, + WmWindow* root_window) { + if (root_window != dock_container_->GetRootWindow()) + return; + + // Entering fullscreen mode (including immersive) hides docked windows. + in_fullscreen_ = root_window_controller_->GetWorkspaceWindowState() == + wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN; + { + // prevent Relayout from getting called multiple times during this + base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); + // Use a copy of children array because a call to MinimizeDockedWindow or + // RestoreDockedWindow can change order. + for (WmWindow* window : dock_container_->GetChildren()) { + if (IsPopupOrTransient(window)) + continue; + wm::WindowState* window_state = window->GetWindowState(); + if (in_fullscreen_) { + if (window->IsVisible()) + MinimizeDockedWindow(window_state); + } else { + if (!window_state->IsMinimized()) + RestoreDockedWindow(window_state); + } + } + } + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} + +void DockedWindowLayoutManager::OnOverviewModeStarting() { + in_overview_ = true; + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} + +void DockedWindowLayoutManager::OnOverviewModeEnded() { + in_overview_ = false; + UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); +} + +//////////////////////////////////////////////////////////////////////////////// +// DockedWindowLayoutManager private implementation: + +void DockedWindowLayoutManager::MaybeMinimizeChildrenExcept(WmWindow* child) { + WindowSelectorController* window_selector_controller = + WmShell::Get()->window_selector_controller(); + if (window_selector_controller->IsRestoringMinimizedWindows()) + return; + // Minimize any windows that don't fit without overlap. + const gfx::Rect work_area = + dock_container_->GetDisplayNearestWindow().work_area(); + int available_room = work_area.height(); + bool gap_needed = !!child; + if (child) + available_room -= GetWindowHeightCloseTo(child, 0); + // Use a copy of children array because a call to Minimize can change order. + std::vector<WmWindow*> children(dock_container_->GetChildren()); + for (auto iter = children.rbegin(); iter != children.rend(); ++iter) { + WmWindow* window(*iter); + if (window == child || !IsWindowDocked(window)) + continue; + int room_needed = + GetWindowHeightCloseTo(window, 0) + (gap_needed ? kMinDockGap : 0); + gap_needed = true; + if (available_room > room_needed) { + available_room -= room_needed; + } else { + // Slow down minimizing animations. Lock duration so that it is not + // overridden by other ScopedLayerAnimationSettings down the stack. + ui::ScopedLayerAnimationSettings settings( + window->GetLayer()->GetAnimator()); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kMinimizeDurationMs)); + settings.LockTransitionDuration(); + window->GetWindowState()->Minimize(); + } + } +} + +void DockedWindowLayoutManager::MinimizeDockedWindow( + wm::WindowState* window_state) { + DCHECK(!IsPopupOrTransient(window_state->window())); + window_state->window()->Hide(); + if (window_state->IsActive()) + window_state->Deactivate(); + RecordUmaAction(DOCKED_ACTION_MINIMIZE, event_source_); +} + +void DockedWindowLayoutManager::RestoreDockedWindow( + wm::WindowState* window_state) { + WmWindow* window = window_state->window(); + DCHECK(!IsPopupOrTransient(window)); + + // Evict the window if it can no longer be docked because of its height. + if (!CanDockWindow(window, DOCKED_ALIGNMENT_NONE)) { + window_state->Restore(); + RecordUmaAction(DOCKED_ACTION_EVICT, event_source_); + return; + } + + // Always place restored window at the bottom shuffling the other windows up. + // TODO(varkha): add a separate container for docked windows to keep track + // of ordering. + const gfx::Rect work_area = + dock_container_->GetDisplayNearestWindow().work_area(); + gfx::Rect bounds(window->GetBounds()); + bounds.set_y(work_area.bottom()); + window->SetBounds(bounds); + window->Show(); + MaybeMinimizeChildrenExcept(window); + RecordUmaAction(DOCKED_ACTION_RESTORE, event_source_); +} + +void DockedWindowLayoutManager::RecordUmaAction(DockedAction action, + DockedActionSource source) { + if (action == DOCKED_ACTION_NONE) + return; + UMA_HISTOGRAM_ENUMERATION("Ash.Dock.Action", action, DOCKED_ACTION_COUNT); + UMA_HISTOGRAM_ENUMERATION("Ash.Dock.ActionSource", source, + DOCKED_ACTION_SOURCE_COUNT); + base::Time time_now = base::Time::Now(); + base::TimeDelta time_between_use = time_now - last_action_time_; + UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.Dock.TimeBetweenUse", + time_between_use.InSeconds(), 1, + base::TimeDelta::FromHours(10).InSeconds(), 100); + last_action_time_ = time_now; + int docked_all_count = 0; + int docked_visible_count = 0; + int docked_panels_count = 0; + int large_windows_count = 0; + for (WmWindow* window : dock_container_->GetChildren()) { + if (IsPopupOrTransient(window)) + continue; + docked_all_count++; + if (!IsWindowDocked(window)) + continue; + docked_visible_count++; + if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL) + docked_panels_count++; + const wm::WindowState* window_state = window->GetWindowState(); + if (window_state->HasRestoreBounds()) { + const gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); + if (restore_bounds.width() > kMaxDockWidth) + large_windows_count++; + } + } + UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsAll", docked_all_count); + UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsLarge", large_windows_count); + UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsPanels", docked_panels_count); + UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsVisible", docked_visible_count); +} + +void DockedWindowLayoutManager::UpdateDockedWidth(int width) { + if (docked_width_ == width) + return; + docked_width_ = width; + UMA_HISTOGRAM_COUNTS_10000("Ash.Dock.Width", docked_width_); +} + +void DockedWindowLayoutManager::OnDraggedWindowDocked(WmWindow* window) { + DCHECK(!is_dragged_window_docked_); + is_dragged_window_docked_ = true; +} + +void DockedWindowLayoutManager::OnDraggedWindowUndocked() { + DCHECK(is_dragged_window_docked_); + is_dragged_window_docked_ = false; +} + +bool DockedWindowLayoutManager::IsAnyWindowDocked() { + return CalculateAlignment() != DOCKED_ALIGNMENT_NONE; +} + +DockedAlignment DockedWindowLayoutManager::GetEdgeNearestWindow( + const WmWindow* window) const { + const gfx::Rect bounds(window->GetBoundsInScreen()); + const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen(); + // Give one pixel preference for docking on the right side to a window that + // has odd width and is centered in a screen that has even width (or vice + // versa). This only matters to the tests but could be a source of flakiness. + return (abs(bounds.x() - container_bounds.x()) + 1 < + abs(bounds.right() - container_bounds.right())) + ? DOCKED_ALIGNMENT_LEFT + : DOCKED_ALIGNMENT_RIGHT; +} + +void DockedWindowLayoutManager::Relayout() { + // Suppress layouts during overview mode while restoring minimized windows so + // that docked animations are not interfering with the overview mode. + WindowSelectorController* window_selector_controller = + WmShell::Get()->window_selector_controller(); + if (in_layout_ || (window_selector_controller->IsRestoringMinimizedWindows())) + return; + if (alignment_ == DOCKED_ALIGNMENT_NONE && !is_dragged_window_docked_) + return; + base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); + + WmWindow* active_window = nullptr; + std::vector<WindowWithHeight> visible_windows; + for (WmWindow* window : dock_container_->GetChildren()) { + if (!IsWindowDocked(window) || window == dragged_window_) + continue; + + // If the shelf is currently hidden (full-screen mode), hide window until + // full-screen mode is exited. + if (in_fullscreen_) { + // The call to Hide does not set the minimize property, so the window will + // be restored when the shelf becomes visible again. + window->Hide(); + continue; + } + if (window->IsFocused() || + window->Contains(window->GetShell()->GetFocusedWindow())) { + DCHECK(!active_window); + active_window = window; + } + visible_windows.push_back(WindowWithHeight(window)); + } + // Consider docked dragged_window_ when fanning out other child windows. + if (is_dragged_window_docked_) { + visible_windows.push_back(WindowWithHeight(dragged_window_)); + DCHECK(!active_window); + active_window = dragged_window_; + } + + // Position docked windows as well as the window being dragged. + gfx::Rect work_area = dock_container_->GetDisplayNearestWindow().work_area(); + if (shelf_observer_) + work_area.Subtract(shelf_observer_->shelf_bounds_in_screen()); + int available_room = + CalculateWindowHeightsAndRemainingRoom(work_area, &visible_windows); + FanOutChildren(work_area, CalculateIdealWidth(visible_windows), + available_room, &visible_windows); + + // After the first Relayout allow the windows to change their order easier + // since we know they are docked. + is_dragged_from_dock_ = true; + UpdateStacking(active_window); +} + +int DockedWindowLayoutManager::CalculateWindowHeightsAndRemainingRoom( + const gfx::Rect& work_area, + std::vector<WindowWithHeight>* visible_windows) { + int available_room = work_area.height(); + int remaining_windows = visible_windows->size(); + int gap_height = remaining_windows > 1 ? kMinDockGap : 0; + + // Sort windows by their minimum heights and calculate target heights. + std::sort(visible_windows->begin(), visible_windows->end(), + CompareMinimumHeight()); + // Distribute the free space among the docked windows. Since the windows are + // sorted (tall windows first) we can now assume that any window which + // required more space than the current window will have already been + // accounted for previously in this loop, so we can safely give that window + // its proportional share of the remaining space. + for (std::vector<WindowWithHeight>::reverse_iterator iter = + visible_windows->rbegin(); + iter != visible_windows->rend(); ++iter) { + iter->height = GetWindowHeightCloseTo( + iter->window, + (available_room + gap_height) / remaining_windows - gap_height); + available_room -= (iter->height + gap_height); + remaining_windows--; + } + return available_room + gap_height; +} + +int DockedWindowLayoutManager::CalculateIdealWidth( + const std::vector<WindowWithHeight>& visible_windows) { + int smallest_max_width = kMaxDockWidth; + int largest_min_width = kMinDockWidth; + // Ideal width of the docked area is as close to kIdealWidth as possible + // while still respecting the minimum and maximum width restrictions on the + // individual docked windows as well as the width that was possibly set by a + // user (which needs to be preserved when dragging and rearranging windows). + for (std::vector<WindowWithHeight>::const_iterator iter = + visible_windows.begin(); + iter != visible_windows.end(); ++iter) { + const WmWindow* window = iter->window; + int min_window_width = window->GetBounds().width(); + int max_window_width = min_window_width; + if (!window->GetWindowState()->bounds_changed_by_user()) { + min_window_width = GetWindowWidthCloseTo(window, kMinDockWidth); + max_window_width = GetWindowWidthCloseTo(window, kMaxDockWidth); + } + largest_min_width = std::max(largest_min_width, min_window_width); + smallest_max_width = std::min(smallest_max_width, max_window_width); + } + int ideal_width = + std::max(largest_min_width, std::min(smallest_max_width, kIdealWidth)); + // Restrict docked area width regardless of window restrictions. + ideal_width = std::max(std::min(ideal_width, kMaxDockWidth), kMinDockWidth); + return ideal_width; +} + +void DockedWindowLayoutManager::FanOutChildren( + const gfx::Rect& work_area, + int ideal_docked_width, + int available_room, + std::vector<WindowWithHeight>* visible_windows) { + gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen(); + + // Calculate initial vertical offset and the gap or overlap between windows. + const int num_windows = visible_windows->size(); + const float delta = + static_cast<float>(available_room) / + ((available_room > 0 || num_windows <= 1) ? num_windows + 1 + : num_windows - 1); + float y_pos = work_area.y() + ((delta > 0) ? delta : 0); + + // Docked area is shown only if there is at least one non-dragged visible + // docked window. + int new_width = ideal_docked_width; + if (visible_windows->empty() || + (visible_windows->size() == 1 && + (*visible_windows)[0].window == dragged_window_)) { + new_width = 0; + } + UpdateDockedWidth(new_width); + // Sort windows by their center positions and fan out overlapping + // windows. + std::sort(visible_windows->begin(), visible_windows->end(), + CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : nullptr, + dock_container_, delta)); + for (std::vector<WindowWithHeight>::iterator iter = visible_windows->begin(); + iter != visible_windows->end(); ++iter) { + WmWindow* window = iter->window; + gfx::Rect bounds = + dock_container_->ConvertRectToScreen(window->GetTargetBounds()); + // A window is extended or shrunk to be as close as possible to the ideal + // docked area width. Windows that were resized by a user are kept at their + // existing size. + // This also enforces the min / max restrictions on the docked area width. + bounds.set_width(GetWindowWidthCloseTo( + window, window->GetWindowState()->bounds_changed_by_user() + ? bounds.width() + : ideal_docked_width)); + DCHECK_LE(bounds.width(), ideal_docked_width); + + DockedAlignment alignment = alignment_; + if (alignment == DOCKED_ALIGNMENT_NONE && window == dragged_window_) + alignment = GetEdgeNearestWindow(window); + + // Fan out windows evenly distributing the overlap or remaining free space. + bounds.set_height(iter->height); + bounds.set_y( + std::max(work_area.y(), std::min(work_area.bottom() - bounds.height(), + static_cast<int>(y_pos + 0.5)))); + y_pos += bounds.height() + delta + kMinDockGap; + + // All docked windows other than the one currently dragged remain stuck + // to the screen edge (flush with the edge or centered in the dock area). + switch (alignment) { + case DOCKED_ALIGNMENT_LEFT: + bounds.set_x(dock_bounds.x() + + (ideal_docked_width - bounds.width()) / 2); + break; + case DOCKED_ALIGNMENT_RIGHT: + bounds.set_x(dock_bounds.right() - + (ideal_docked_width + bounds.width()) / 2); + break; + case DOCKED_ALIGNMENT_NONE: + break; + } + if (window == dragged_window_) { + dragged_bounds_ = bounds; + continue; + } + // If the following asserts it is probably because not all the children + // have been removed when dock was closed. + DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE); + bounds = dock_container_->ConvertRectFromScreen(bounds); + if (bounds != window->GetTargetBounds()) { + ui::Layer* layer = window->GetLayer(); + ui::ScopedLayerAnimationSettings slide_settings(layer->GetAnimator()); + slide_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + slide_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kSlideDurationMs)); + window->SetBoundsDirect(bounds); + } + } +} + +void DockedWindowLayoutManager::UpdateDockBounds( + DockedWindowLayoutManagerObserver::Reason reason) { + int docked_width = in_overview_ ? 0 : docked_width_; + int dock_inset = docked_width + (docked_width > 0 ? kMinDockGap : 0); + const gfx::Rect work_area = + dock_container_->GetDisplayNearestWindow().work_area(); + gfx::Rect bounds = gfx::Rect( + alignment_ == DOCKED_ALIGNMENT_RIGHT && dock_inset > 0 + ? dock_container_->GetBounds().right() - dock_inset + : dock_container_->GetBounds().x(), + dock_container_->GetBounds().y(), dock_inset, work_area.height()); + docked_bounds_ = + bounds + dock_container_->GetBoundsInScreen().OffsetFromOrigin(); + for (auto& observer : observer_list_) + observer.OnDockBoundsChanging(bounds, reason); + // Show or hide background for docked area. + gfx::Rect background_bounds(docked_bounds_); + if (shelf_observer_) + background_bounds.Subtract(shelf_observer_->shelf_bounds_in_screen()); + if (docked_width > 0) { + // TODO: |shelf_| should not be null by the time we get here, but it may + // be in mash as startup sequence doesn't yet match that of ash. Once + // |shelf_| is created at same time as ash we can remove conditional. + // http://crbug.com/632099 + if (shelf_) { + if (!background_widget_) + background_widget_.reset(new DockedBackgroundWidget(this)); + background_widget_->SetBackgroundBounds(background_bounds, alignment_); + background_widget_->Show(); + } + } else if (background_widget_) { + background_widget_->Hide(); + } +} + +void DockedWindowLayoutManager::UpdateStacking(WmWindow* active_window) { + if (!active_window) { + if (!last_active_window_) + return; + active_window = last_active_window_; + } + + // Windows are stacked like a deck of cards: + // ,------. + // |,------.| + // |,------.| + // | active | + // | window | + // |`------'| + // |`------'| + // `------' + // Use the middle of each window to figure out how to stack the window. + // This allows us to update the stacking when a window is being dragged around + // by the titlebar. + std::map<int, WmWindow*> window_ordering; + for (WmWindow* child : dock_container_->GetChildren()) { + if (!IsWindowDocked(child) || + (child == dragged_window_ && !is_dragged_window_docked_)) { + continue; + } + gfx::Rect bounds = child->GetBounds(); + window_ordering.insert( + std::make_pair(bounds.y() + bounds.height() / 2, child)); + } + int active_center_y = active_window->GetBounds().CenterPoint().y(); + + WmWindow* previous_window = nullptr; + for (std::map<int, WmWindow*>::const_iterator it = window_ordering.begin(); + it != window_ordering.end() && it->first < active_center_y; ++it) { + if (previous_window) + dock_container_->StackChildAbove(it->second, previous_window); + previous_window = it->second; + } + for (std::map<int, WmWindow*>::const_reverse_iterator it = + window_ordering.rbegin(); + it != window_ordering.rend() && it->first > active_center_y; ++it) { + if (previous_window) + dock_container_->StackChildAbove(it->second, previous_window); + previous_window = it->second; + } + + if (previous_window && active_window->GetParent() == dock_container_) + dock_container_->StackChildAbove(active_window, previous_window); + if (active_window != dragged_window_) + last_active_window_ = active_window; +} + +//////////////////////////////////////////////////////////////////////////////// +// keyboard::KeyboardControllerObserver implementation: + +void DockedWindowLayoutManager::OnKeyboardBoundsChanging( + const gfx::Rect& keyboard_bounds) { + // This bounds change will have caused a change to the Shelf which does not + // propagate automatically to this class, so manually recalculate bounds. + Relayout(); + UpdateDockBounds(DockedWindowLayoutManagerObserver::KEYBOARD_BOUNDS_CHANGING); +} + +void DockedWindowLayoutManager::OnKeyboardClosed() {} + +} // namespace ash
diff --git a/ash/common/wm/dock/docked_window_layout_manager.h b/ash/common/wm/dock/docked_window_layout_manager.h new file mode 100644 index 0000000..a3f5784d --- /dev/null +++ b/ash/common/wm/dock/docked_window_layout_manager.h
@@ -0,0 +1,322 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/dock/dock_types.h" +#include "ash/common/wm/dock/docked_window_layout_manager_observer.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h" +#include "ash/common/wm_activation_observer.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/time/time.h" +#include "ui/aura/window_observer.h" +#include "ui/display/display_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace ash { +class DockedBackgroundWidget; +class DockedWindowLayoutManagerObserver; +class DockedWindowResizerTest; +class RootWindowController; +class WmShelf; + +// DockedWindowLayoutManager is responsible for organizing windows when they are +// docked to the side of a screen. It is associated with a specific container +// window (i.e. kShellWindowId_DockedContainer) and controls the layout of any +// windows added to that container. +// +// The constructor takes a |dock_container| argument which is expected to set +// its layout manager to this instance, e.g.: +// dock_container->SetLayoutManager( +// new DockedWindowLayoutManager(dock_container)); +// +// TODO(varkha): extend BaseLayoutManager instead of LayoutManager to inherit +// common functionality. +class ASH_EXPORT DockedWindowLayoutManager + : public wm::WmSnapToPixelLayoutManager, + public display::DisplayObserver, + public aura::WindowObserver, + public WmActivationObserver, + public ShellObserver, + public keyboard::KeyboardControllerObserver, + public wm::WindowStateObserver { + public: + // Maximum width of the docked windows area. + static const int kMaxDockWidth; + + // Minimum width of the docked windows area. + static const int kMinDockWidth; + + explicit DockedWindowLayoutManager(WmWindow* dock_container); + ~DockedWindowLayoutManager() override; + + // Returns the DockedWindowLayoutManager in the specified hierarchy. This + // searches from the root of |window|. + static DockedWindowLayoutManager* Get(WmWindow* window); + + // Disconnects observers before container windows get destroyed. + void Shutdown(); + + // Management of the observer list. + virtual void AddObserver(DockedWindowLayoutManagerObserver* observer); + virtual void RemoveObserver(DockedWindowLayoutManagerObserver* observer); + + // Called by a DockedWindowResizer to update which window is being dragged. + // Starts observing the window unless it is a child. + void StartDragging(WmWindow* window); + + // Called by a DockedWindowResizer when a dragged window is docked. + void DockDraggedWindow(WmWindow* window); + + // Called by a DockedWindowResizer when a dragged window is no longer docked. + void UndockDraggedWindow(); + + // Called by a DockedWindowResizer when a window is no longer being dragged. + // Stops observing the window unless it is a child. + // Records |action| by |source| in UMA. + void FinishDragging(DockedAction action, DockedActionSource source); + + // Checks the rules and possibly updates the docked layout to match + // the |alignment|. May not apply the |alignment| when + // the current shelf alignment conflicts. Never clears the |alignment_|. + void MaybeSetDesiredDockedAlignment(DockedAlignment alignment); + + WmShelf* shelf() { return shelf_; } + void SetShelf(WmShelf* shelf); + + // Calculates if a window is touching the screen edges and returns edge. + DockedAlignment GetAlignmentOfWindow(const WmWindow* window) const; + + // Used to snap docked windows to the side of screen during drag. + DockedAlignment CalculateAlignment() const; + + void set_preferred_alignment(DockedAlignment preferred_alignment) { + preferred_alignment_ = preferred_alignment; + } + + void set_event_source(DockedActionSource event_source) { + event_source_ = event_source; + } + + // Returns true when a window can be docked. Windows cannot be docked at the + // edge used by the shelf or the edge opposite from existing dock. + bool CanDockWindow(WmWindow* window, DockedAlignment desired_alignment); + + WmWindow* dock_container() const { return dock_container_; } + + // Returns current bounding rectangle of docked windows area. + const gfx::Rect& docked_bounds() const { return docked_bounds_; } + + // Returns last known coordinates of |dragged_window_| after Relayout. + const gfx::Rect dragged_bounds() const { return dragged_bounds_; } + + // Returns true if currently dragged window is docked at the screen edge. + bool is_dragged_window_docked() const { return is_dragged_window_docked_; } + + // Updates docked layout when shelf bounds change. + void OnShelfBoundsChanged(); + + // SnapLayoutManager: + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override {} + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + // display::DisplayObserver: + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) override; + + // wm::WindowStateObserver: + void OnPreWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) override; + + // aura::WindowObserver: + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override; + void OnWindowVisibilityChanging(aura::Window* window, bool visible) override; + void OnWindowDestroying(aura::Window* window) override; + + // WmActivationObserver: + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override; + + // ShellObserver: + void OnShelfAlignmentChanged(WmWindow* root_window) override; + void OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) override; + void OnOverviewModeStarting() override; + void OnOverviewModeEnded() override; + + private: + struct CompareMinimumHeight; + struct CompareWindowPos; + class ShelfWindowObserver; + struct WindowWithHeight; + + friend class DockedWindowLayoutManagerTest; + friend class DockedWindowResizerTest; + + // Width of the gap between the docked windows and a workspace. + static const int kMinDockGap; + + // Ideal (starting) width of the dock. + static const int kIdealWidth; + + // Returns the alignment of the docked windows other than the |child|. + DockedAlignment CalculateAlignmentExcept(const WmWindow* child) const; + + // Determines if the |alignment| is applicable taking into account + // the shelf alignment. + bool IsDockedAlignmentValid(DockedAlignment alignment) const; + + // Keep at most kMaxVisibleWindows visible in the dock and minimize the rest + // (except for |child|). + void MaybeMinimizeChildrenExcept(WmWindow* child); + + // Minimize / restore window and relayout. + void MinimizeDockedWindow(wm::WindowState* window_state); + void RestoreDockedWindow(wm::WindowState* window_state); + + // Record user-initiated |action| by |source| in UMA metrics. + void RecordUmaAction(DockedAction action, DockedActionSource source); + + // Updates |docked_width_| and UMA histograms. + void UpdateDockedWidth(int width); + + // Updates docked layout state when a window gets inside the dock. + void OnDraggedWindowDocked(WmWindow* window); + + // Updates docked layout state when a window gets outside the dock. + void OnDraggedWindowUndocked(); + + // Returns true if there are any windows currently docked. + bool IsAnyWindowDocked(); + + // Returns DOCKED_ALIGNMENT_LEFT if the |window|'s left edge is closer to + // the |dock_container_|'s left edge than the |window|'s right edge to + // the |dock_container_|'s right edge. Returns DOCKED_ALIGNMENT_RIGHT + // otherwise. + DockedAlignment GetEdgeNearestWindow(const WmWindow* window) const; + + // Called whenever the window layout might change. + void Relayout(); + + // Calculates target heights (and fills it in |visible_windows| array) such + // that the vertical space is fairly distributed among the windows taking + // into account their minimum and maximum size. Returns free vertical space + // (positive value) that remains after resizing all windows or deficit + // (negative value) if not all the windows fit. + int CalculateWindowHeightsAndRemainingRoom( + const gfx::Rect& work_area, + std::vector<WindowWithHeight>* visible_windows); + + // Calculate ideal width for the docked area. It will get used to adjust the + // dragged window or other windows as necessary. + int CalculateIdealWidth(const std::vector<WindowWithHeight>& visible_windows); + + // Fan out windows evenly distributing the overlap or remaining free space. + // Adjust the widths of the windows trying to make them all same. If this + // is not possible, center the windows in the docked area. + void FanOutChildren(const gfx::Rect& work_area, + int ideal_docked_width, + int available_room, + std::vector<WindowWithHeight>* visible_windows); + + // Updates |docked_bounds_| and workspace insets when bounds of docked windows + // area change. Passing |reason| to observers allows selectively skipping + // notifications. + void UpdateDockBounds(DockedWindowLayoutManagerObserver::Reason reason); + + // Called whenever the window stacking order needs to be updated (e.g. focus + // changes or a window is moved). + void UpdateStacking(WmWindow* active_window); + + // keyboard::KeyboardControllerObserver: + void OnKeyboardBoundsChanging(const gfx::Rect& keyboard_bounds) override; + void OnKeyboardClosed() override; + + // Parent window associated with this layout manager. + WmWindow* dock_container_; + + RootWindowController* root_window_controller_; + + // Protect against recursive calls to Relayout(). + bool in_layout_; + + // A window that is being dragged (whether docked or not). + // Windows are tracked by docked layout manager only if they are docked; + // however we need to know if a window is being dragged in order to avoid + // positioning it or even considering it for layout. + WmWindow* dragged_window_; + + // True if the window being dragged is currently docked. + bool is_dragged_window_docked_; + + // Previously docked windows use a more relaxed dragging sorting algorithm + // that uses assumption that a window starts being dragged out of position + // that was previously established in Relayout. This allows easier reordering. + bool is_dragged_from_dock_; + + // The shelf to respond to alignment changes. + WmShelf* shelf_; + + // Tracks if any window in the same root window is in fullscreen mode. + bool in_fullscreen_; + // Current width of the dock. + int docked_width_; + + // Last bounds that were sent to observers. + gfx::Rect docked_bounds_; + + // Target bounds of a docked window being dragged. + gfx::Rect dragged_bounds_; + + // True while in overview mode. + bool in_overview_; + + // Side of the screen that the dock is positioned at. + DockedAlignment alignment_; + + // The preferred alignment of the next window to be added to docked layout. + DockedAlignment preferred_alignment_; + + // The current event source + DockedActionSource event_source_; + + // The last active window. Used to maintain stacking order even if no windows + // are currently focused. + WmWindow* last_active_window_; + + // Timestamp of the last user-initiated action that changed docked state. + // Used in UMA metrics. + base::Time last_action_time_; + + // Observes shelf for bounds changes. + std::unique_ptr<ShelfWindowObserver> shelf_observer_; + + // Widget used to paint a background for the docked area. + std::unique_ptr<DockedBackgroundWidget> background_widget_; + + // Observers of dock bounds changes. + base::ObserverList<DockedWindowLayoutManagerObserver> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(DockedWindowLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/dock/docked_window_layout_manager_observer.h b/ash/common/wm/dock/docked_window_layout_manager_observer.h new file mode 100644 index 0000000..5a3484f --- /dev/null +++ b/ash/common/wm/dock/docked_window_layout_manager_observer.h
@@ -0,0 +1,39 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_OBSERVER_H_ +#define ASH_COMMON_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace gfx { +class Rect; +} + +namespace ash { + +// Observers to the DockedWindowLayoutManager are notified of significant +// events that occur with the docked windows, such as the bounds change. +class ASH_EXPORT DockedWindowLayoutManagerObserver { + public: + // Reason for notification. Allows selectively ignoring notifications to + // prevent a notification loop. + enum Reason { + CHILD_CHANGED, + DISPLAY_RESIZED, + DISPLAY_INSETS_CHANGED, + SHELF_ALIGNMENT_CHANGED, + KEYBOARD_BOUNDS_CHANGING + }; + // Called after the dock bounds are changed. + virtual void OnDockBoundsChanging(const gfx::Rect& new_bounds, + Reason reason) = 0; + + protected: + virtual ~DockedWindowLayoutManagerObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_OBSERVER_H_
diff --git a/ash/common/wm/dock/docked_window_resizer.cc b/ash/common/wm/dock/docked_window_resizer.cc new file mode 100644 index 0000000..f2ea238 --- /dev/null +++ b/ash/common/wm/dock/docked_window_resizer.cc
@@ -0,0 +1,324 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/dock/docked_window_resizer.h" + +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/window_parenting_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace/magnetism_matcher.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ui/base/hit_test.h" +#include "ui/base/ui_base_types.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" + +namespace ash { +namespace { + +DockedWindowLayoutManager* GetDockedLayoutManagerAtPoint( + const gfx::Point& point) { + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestPoint(point); + if (!display.bounds().Contains(point)) + return nullptr; + + return DockedWindowLayoutManager::Get( + Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow()); +} + +} // namespace + +DockedWindowResizer::~DockedWindowResizer() {} + +// static +DockedWindowResizer* DockedWindowResizer::Create( + WindowResizer* next_window_resizer, + wm::WindowState* window_state) { + return new DockedWindowResizer(next_window_resizer, window_state); +} + +void DockedWindowResizer::Drag(const gfx::Point& location, int event_flags) { + last_location_ = GetTarget()->GetParent()->ConvertPointToScreen(location); + base::WeakPtr<DockedWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr()); + + if (!did_move_or_resize_) { + did_move_or_resize_ = true; + StartedDragging(resizer); + } + if (!resizer) + return; + + gfx::Point offset; + gfx::Rect bounds(CalculateBoundsForDrag(location)); + MaybeSnapToEdge(bounds, &offset); + gfx::Point modified_location(location); + modified_location += offset.OffsetFromOrigin(); + + next_window_resizer_->Drag(modified_location, event_flags); + if (!resizer) + return; + + DockedWindowLayoutManager* new_dock_layout = + GetDockedLayoutManagerAtPoint(last_location_); + if (new_dock_layout && new_dock_layout != dock_layout_) { + // The window is being dragged to a new display. If the previous + // container is the current parent of the window it will be informed of + // the end of drag when the window is reparented, otherwise let the + // previous container know the drag is complete. If we told the + // window's parent that the drag was complete it would begin + // positioning the window. + if (is_docked_ && dock_layout_->is_dragged_window_docked()) + dock_layout_->UndockDraggedWindow(); + if (dock_layout_ != initial_dock_layout_) + dock_layout_->FinishDragging( + DOCKED_ACTION_NONE, + details().source == aura::client::WINDOW_MOVE_SOURCE_MOUSE + ? DOCKED_ACTION_SOURCE_MOUSE + : DOCKED_ACTION_SOURCE_TOUCH); + is_docked_ = false; + dock_layout_ = new_dock_layout; + // The window's initial layout manager already knows that the drag is + // in progress for this window. + if (new_dock_layout != initial_dock_layout_) + new_dock_layout->StartDragging(GetTarget()); + } + // Window could get docked by the WorkspaceWindowResizer, update the state. + is_docked_ = dock_layout_->is_dragged_window_docked(); + // Whenever a window is dragged out of the dock it will be auto-sized + // in the dock if it gets docked again. + if (!is_docked_) + was_bounds_changed_by_user_ = false; +} + +void DockedWindowResizer::CompleteDrag() { + // The root window can change when dragging into a different screen. + next_window_resizer_->CompleteDrag(); + FinishedDragging(aura::client::MOVE_SUCCESSFUL); +} + +void DockedWindowResizer::RevertDrag() { + next_window_resizer_->RevertDrag(); + // Restore docked state to what it was before the drag if necessary. + if (is_docked_ != was_docked_) { + is_docked_ = was_docked_; + if (is_docked_) + dock_layout_->DockDraggedWindow(GetTarget()); + else + dock_layout_->UndockDraggedWindow(); + } + FinishedDragging(aura::client::MOVE_CANCELED); +} + +DockedWindowResizer::DockedWindowResizer(WindowResizer* next_window_resizer, + wm::WindowState* window_state) + : WindowResizer(window_state), + next_window_resizer_(next_window_resizer), + dock_layout_(NULL), + initial_dock_layout_(NULL), + did_move_or_resize_(false), + was_docked_(false), + is_docked_(false), + was_bounds_changed_by_user_(window_state->bounds_changed_by_user()), + weak_ptr_factory_(this) { + DCHECK(details().is_resizable); + dock_layout_ = DockedWindowLayoutManager::Get(GetTarget()->GetRootWindow()); + initial_dock_layout_ = dock_layout_; + was_docked_ = GetTarget()->GetParent() == dock_layout_->dock_container(); + is_docked_ = was_docked_; +} + +void DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, + gfx::Point* offset) { + // Windows only snap magnetically when they were previously docked. + if (!was_docked_) + return; + DockedAlignment dock_alignment = dock_layout_->CalculateAlignment(); + gfx::Rect dock_bounds = GetTarget()->GetParent()->ConvertRectFromScreen( + dock_layout_->dock_container()->GetBoundsInScreen()); + + // Short-range magnetism when retaining docked state. Same constant as in + // MagnetismMatcher is used for consistency. + const int kSnapToDockDistance = MagnetismMatcher::kMagneticDistance; + + if (dock_alignment == DOCKED_ALIGNMENT_LEFT || + dock_alignment == DOCKED_ALIGNMENT_NONE) { + const int distance = bounds.x() - dock_bounds.x(); + if (distance < kSnapToDockDistance && distance > 0) { + offset->set_x(-distance); + return; + } + } + if (dock_alignment == DOCKED_ALIGNMENT_RIGHT || + dock_alignment == DOCKED_ALIGNMENT_NONE) { + const int distance = dock_bounds.right() - bounds.right(); + if (distance < kSnapToDockDistance && distance > 0) + offset->set_x(distance); + } +} + +void DockedWindowResizer::StartedDragging( + base::WeakPtr<DockedWindowResizer>& resizer) { + // During resizing the window width is preserved by DockedwindowLayoutManager. + if (is_docked_ && + (details().bounds_change & WindowResizer::kBoundsChange_Resizes)) { + window_state_->set_bounds_changed_by_user(true); + } + + // Tell the dock layout manager that we are dragging this window. + // At this point we are not yet animating the window as it may not be + // inside the docked area. + dock_layout_->StartDragging(GetTarget()); + if (!resizer) + return; + // Reparent workspace windows during the drag to elevate them above workspace. + // Other windows for which the DockedWindowResizer is instantiated include + // panels and windows that are already docked. Those do not need reparenting. + if (GetTarget()->GetType() != ui::wm::WINDOW_TYPE_PANEL && + GetTarget()->GetParent()->GetShellWindowId() == + kShellWindowId_DefaultContainer) { + // Reparent the window into the docked windows container in order to get it + // on top of other docked windows. + WmWindow* docked_container = + GetTarget()->GetRootWindow()->GetChildByShellWindowId( + kShellWindowId_DockedContainer); + wm::ReparentChildWithTransientChildren( + GetTarget(), GetTarget()->GetParent(), docked_container); + if (!resizer) + return; + } + if (is_docked_) + dock_layout_->DockDraggedWindow(GetTarget()); +} + +void DockedWindowResizer::FinishedDragging( + aura::client::WindowMoveResult move_result) { + if (!did_move_or_resize_) + return; + did_move_or_resize_ = false; + WmWindow* window = GetTarget(); + const bool is_attached_panel = + window->GetType() == ui::wm::WINDOW_TYPE_PANEL && + window->aura_window()->GetProperty(kPanelAttachedKey); + const bool is_resized = + (details().bounds_change & WindowResizer::kBoundsChange_Resizes) != 0; + + // Undock the window if it is not in the normal, docked or minimized state + // type. This happens if a user snaps or maximizes a window using a + // keyboard shortcut while it is being dragged. + if (!window_state_->IsMinimized() && !window_state_->IsDocked() && + !window_state_->IsNormalStateType()) + is_docked_ = false; + + // When drag is completed the dragged docked window is resized to the bounds + // calculated by the layout manager that conform to other docked windows. + if (!is_attached_panel && is_docked_ && !is_resized) { + gfx::Rect bounds = window->GetParent()->ConvertRectFromScreen( + dock_layout_->dragged_bounds()); + if (!bounds.IsEmpty() && bounds.width() != window->GetBounds().width()) { + window->SetBounds(bounds); + } + } + // If a window has restore bounds, update the restore origin but not the size. + // The size gets restored when a window is undocked. + if (is_resized && is_docked_ && window_state_->HasRestoreBounds()) { + gfx::Rect restore_bounds = window->GetBoundsInScreen(); + restore_bounds.set_size(window_state_->GetRestoreBoundsInScreen().size()); + window_state_->SetRestoreBoundsInScreen(restore_bounds); + } + + // Check if the window needs to be docked or returned to workspace. + DockedAction action = + MaybeReparentWindowOnDragCompletion(is_resized, is_attached_panel); + dock_layout_->FinishDragging( + move_result == aura::client::MOVE_CANCELED ? DOCKED_ACTION_NONE : action, + details().source == aura::client::WINDOW_MOVE_SOURCE_MOUSE + ? DOCKED_ACTION_SOURCE_MOUSE + : DOCKED_ACTION_SOURCE_TOUCH); + + // If we started the drag in one root window and moved into another root + // but then canceled the drag we may need to inform the original layout + // manager that the drag is finished. + if (initial_dock_layout_ != dock_layout_) + initial_dock_layout_->FinishDragging( + DOCKED_ACTION_NONE, + details().source == aura::client::WINDOW_MOVE_SOURCE_MOUSE + ? DOCKED_ACTION_SOURCE_MOUSE + : DOCKED_ACTION_SOURCE_TOUCH); + is_docked_ = false; +} + +DockedAction DockedWindowResizer::MaybeReparentWindowOnDragCompletion( + bool is_resized, + bool is_attached_panel) { + WmWindow* window = GetTarget(); + + // Check if the window needs to be docked or returned to workspace. + DockedAction action = DOCKED_ACTION_NONE; + WmWindow* dock_container = window->GetRootWindow()->GetChildByShellWindowId( + kShellWindowId_DockedContainer); + if ((is_resized || !is_attached_panel) && + is_docked_ != (window->GetParent() == dock_container)) { + if (is_docked_) { + wm::ReparentChildWithTransientChildren(window, window->GetParent(), + dock_container); + action = DOCKED_ACTION_DOCK; + } else if (window->GetParent()->GetShellWindowId() == + kShellWindowId_DockedContainer) { + // Reparent the window back to workspace. + // We need to be careful to give ParentWindowWithContext a location in + // the right root window (matching the logic in DragWindowResizer) based + // on which root window a mouse pointer is in. We want to undock into the + // right screen near the edge of a multiscreen setup (based on where the + // mouse is). + gfx::Rect near_last_location(last_location_, gfx::Size()); + // Reparenting will cause Relayout and possible dock shrinking. + WmWindow* previous_parent = window->GetParent(); + window->SetParentUsingContext(window, near_last_location); + if (window->GetParent() != previous_parent) { + wm::ReparentTransientChildrenOfChild(window, previous_parent, + window->GetParent()); + } + action = was_docked_ ? DOCKED_ACTION_UNDOCK : DOCKED_ACTION_NONE; + } + } else { + // |action| is recorded in UMA and used to maintain |window_state_|. + if (is_resized && is_docked_ && was_docked_) + action = DOCKED_ACTION_RESIZE; + else if (is_docked_ && was_docked_) + action = DOCKED_ACTION_REORDER; + else if (is_docked_ && !was_docked_) + action = DOCKED_ACTION_DOCK; + else if (!is_docked_ && was_docked_) + action = DOCKED_ACTION_UNDOCK; + else + action = DOCKED_ACTION_NONE; + } + // When a window is newly docked it is auto-sized by docked layout adjusting + // to other windows. If it is just dragged (but not resized) while being + // docked it is auto-sized unless it has been resized while being docked + // before. + if (is_docked_) { + window->GetWindowState()->set_bounds_changed_by_user( + was_docked_ && (is_resized || was_bounds_changed_by_user_)); + } + + if (action == DOCKED_ACTION_DOCK) { + const wm::WMEvent event(wm::WM_EVENT_DOCK); + window_state_->OnWMEvent(&event); + } else if (window->GetWindowState()->IsDocked() && + action == DOCKED_ACTION_UNDOCK) { + const wm::WMEvent event(wm::WM_EVENT_NORMAL); + window_state_->OnWMEvent(&event); + } + + return action; +} + +} // namespace ash
diff --git a/ash/common/wm/dock/docked_window_resizer.h b/ash/common/wm/dock/docked_window_resizer.h new file mode 100644 index 0000000..277bde8 --- /dev/null +++ b/ash/common/wm/dock/docked_window_resizer.h
@@ -0,0 +1,101 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DOCK_DOCKED_WINDOW_RESIZER_H_ +#define ASH_COMMON_WM_DOCK_DOCKED_WINDOW_RESIZER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/dock/dock_types.h" +#include "ash/common/wm/window_resizer.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" + +namespace gfx { +class Point; +class Rect; +} + +namespace ash { +class DockedWindowLayoutManager; + +// DockWindowResizer is used by ToplevelWindowEventFilter to handle dragging, +// moving or resizing of a window while it is docked to the side of a screen. +class ASH_EXPORT DockedWindowResizer : public WindowResizer { + public: + ~DockedWindowResizer() override; + + // Creates a new DockWindowResizer. The caller takes ownership of the + // returned object. The ownership of |next_window_resizer| is taken by the + // returned object. Returns NULL if not resizable. + static DockedWindowResizer* Create(WindowResizer* next_window_resizer, + wm::WindowState* window_state); + + // WindowResizer: + void Drag(const gfx::Point& location, int event_flags) override; + void CompleteDrag() override; + void RevertDrag() override; + + private: + // Creates DockWindowResizer that adds the ability to attach / detach + // windows to / from the dock. This object takes ownership of + // |next_window_resizer|. + DockedWindowResizer(WindowResizer* next_window_resizer, + wm::WindowState* window_state); + + // If the provided window bounds should snap to the side of a screen, + // returns the offset that gives the necessary adjustment to snap. + void MaybeSnapToEdge(const gfx::Rect& bounds, gfx::Point* offset); + + // Tracks the window's initial position and attachment at the start of a drag + // and informs the DockLayoutManager that a drag has started if necessary. + // |resizer| can be used to check if the resizer has been deleted during + // StartedDragging. + void StartedDragging(base::WeakPtr<DockedWindowResizer>& resizer); + + // Informs the DockLayoutManager that the drag is complete if it was informed + // of the drag start. |move_result| specifies if the drag was completed or + // reverted. + void FinishedDragging(aura::client::WindowMoveResult move_result); + + // Reparents dragged window as necessary to the docked container or back to + // workspace at the end of the drag. Calculates and returns action taken that + // can be reported in UMA stats. |is_resized| reports if the window is merely + // being resized rather than repositioned. |attached_panel| is necessary to + // avoid docking panels that have been attached to the launcher shelf at the + // end of the drag. + DockedAction MaybeReparentWindowOnDragCompletion(bool is_resized, + bool is_attached_panel); + + gfx::Point last_location_; + + // Wraps a window resizer and adds detaching / reattaching during drags. + std::unique_ptr<WindowResizer> next_window_resizer_; + + // Dock container window. + DockedWindowLayoutManager* dock_layout_; + DockedWindowLayoutManager* initial_dock_layout_; + + // Set to true once Drag() is invoked and the bounds of the window change. + bool did_move_or_resize_; + + // Set to true if the window that is being dragged was docked before drag. + bool was_docked_; + + // True if the dragged window is docked during the drag. + bool is_docked_; + + // True if the dragged window had |bounds_changed_by_user| before the drag. + // Cleared whenever the target window gets dragged outside of the docked area. + bool was_bounds_changed_by_user_; + + base::WeakPtrFactory<DockedWindowResizer> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(DockedWindowResizer); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_DOCK_DOCKED_WINDOW_RESIZER_H_
diff --git a/ash/common/wm/drag_details.cc b/ash/common/wm/drag_details.cc new file mode 100644 index 0000000..4a91826 --- /dev/null +++ b/ash/common/wm/drag_details.cc
@@ -0,0 +1,80 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/drag_details.h" + +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/window_properties.h" +#include "ui/aura/window.h" +#include "ui/base/hit_test.h" +#include "ui/compositor/layer.h" + +namespace ash { + +namespace { + +int GetSizeChangeDirectionForWindowComponent(int window_component) { + int size_change_direction = WindowResizer::kBoundsChangeDirection_None; + switch (window_component) { + case HTTOPLEFT: + case HTTOPRIGHT: + case HTBOTTOMLEFT: + case HTBOTTOMRIGHT: + case HTGROWBOX: + case HTCAPTION: + size_change_direction |= + WindowResizer::kBoundsChangeDirection_Horizontal | + WindowResizer::kBoundsChangeDirection_Vertical; + break; + case HTTOP: + case HTBOTTOM: + size_change_direction |= WindowResizer::kBoundsChangeDirection_Vertical; + break; + case HTRIGHT: + case HTLEFT: + size_change_direction |= WindowResizer::kBoundsChangeDirection_Horizontal; + break; + default: + break; + } + return size_change_direction; +} + +} // namespace + +DragDetails::DragDetails(WmWindow* window, + const gfx::Point& location, + int window_component, + aura::client::WindowMoveSource source) + : initial_state_type(window->GetWindowState()->GetStateType()), + initial_bounds_in_parent(window->GetBounds()), + initial_location_in_parent(location), + // When drag starts, we might be in the middle of a window opacity + // animation, on drag completion we must set the opacity to the target + // opacity rather than the current opacity (crbug.com/687003). + initial_opacity(window->GetLayer()->GetTargetOpacity()), + window_component(window_component), + bounds_change( + WindowResizer::GetBoundsChangeForWindowComponent(window_component)), + position_change_direction( + WindowResizer::GetPositionChangeDirectionForWindowComponent( + window_component)), + size_change_direction( + GetSizeChangeDirectionForWindowComponent(window_component)), + is_resizable(bounds_change != WindowResizer::kBoundsChangeDirection_None), + source(source), + should_attach_to_shelf( + window->GetType() == ui::wm::WINDOW_TYPE_PANEL && + window->aura_window()->GetProperty(kPanelAttachedKey)) { + wm::WindowState* window_state = window->GetWindowState(); + if ((window_state->IsNormalOrSnapped() || window_state->IsDocked()) && + window_state->HasRestoreBounds() && window_component == HTCAPTION) { + restore_bounds = window_state->GetRestoreBoundsInScreen(); + } +} + +DragDetails::~DragDetails() {} + +} // namespace ash
diff --git a/ash/common/wm/drag_details.h b/ash/common/wm/drag_details.h new file mode 100644 index 0000000..0ea810d --- /dev/null +++ b/ash/common/wm/drag_details.h
@@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_DRAG_DETAILS_H_ +#define ASH_COMMON_WM_DRAG_DETAILS_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm/wm_types.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/wm/public/window_move_client.h" + +namespace ash { + +class WmWindow; + +struct ASH_EXPORT DragDetails { + DragDetails(WmWindow* window, + const gfx::Point& location, + int window_component, + // TODO(sky): make wm type. + aura::client::WindowMoveSource source); + ~DragDetails(); + + ash::wm::WindowStateType initial_state_type; + + // Initial bounds of the window in parent coordinates. + const gfx::Rect initial_bounds_in_parent; + + // Restore bounds (in screen coordinates) of the window before the drag + // started. Only set if the window is normal and is being dragged. + gfx::Rect restore_bounds; + + // Location passed to the constructor, in |window->parent()|'s coordinates. + const gfx::Point initial_location_in_parent; + + // Initial opacity of the window. + const float initial_opacity; + + // The component the user pressed on. + const int window_component; + + // Bitmask of the |kBoundsChange_| constants. + const int bounds_change; + + // Bitmask of the |kBoundsChangeDirection_| constants. + const int position_change_direction; + + // Bitmask of the |kBoundsChangeDirection_| constants. + const int size_change_direction; + + // Will the drag actually modify the window? + const bool is_resizable; + + // Source of the event initiating the drag. + const aura::client::WindowMoveSource source; + + // True if the window should attach to the shelf after releasing. + bool should_attach_to_shelf; +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_DRAG_DETAILS_H_
diff --git a/ash/common/wm/focus_rules.cc b/ash/common/wm/focus_rules.cc new file mode 100644 index 0000000..e0634e62 --- /dev/null +++ b/ash/common/wm/focus_rules.cc
@@ -0,0 +1,59 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/focus_rules.h" + +#include "ash/common/shell_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" + +namespace ash { + +bool IsToplevelWindow(WmWindow* window) { + DCHECK(window); + // The window must in a valid hierarchy. + if (!window->GetRootWindow()) + return false; + + // The window must exist within a container that supports activation. + // The window cannot be blocked by a modal transient. + return IsActivatableShellWindowId(window->GetParent()->GetShellWindowId()); +} + +bool IsWindowConsideredActivatable(WmWindow* window) { + DCHECK(window); + // Only toplevel windows can be activated. + if (!IsToplevelWindow(window)) + return false; + + // The window must be visible. + return IsWindowConsideredVisibleForActivation(window); +} + +bool IsWindowConsideredVisibleForActivation(WmWindow* window) { + DCHECK(window); + // If the |window| doesn't belong to the current active user and also doesn't + // show for the current active user, then it should not be activated. + if (!WmShell::Get()->delegate()->CanShowWindowForUser(window)) + return false; + + if (window->IsVisible()) + return true; + + // Minimized windows are hidden in their minimized state, but they can always + // be activated. + if (window->GetWindowState()->IsMinimized()) + return true; + + if (!window->GetTargetVisibility()) + return false; + + const int parent_shell_window_id = window->GetParent()->GetShellWindowId(); + return parent_shell_window_id == kShellWindowId_DefaultContainer || + parent_shell_window_id == kShellWindowId_LockScreenContainer; +} + +} // namespace ash
diff --git a/ash/common/wm/focus_rules.h b/ash/common/wm/focus_rules.h new file mode 100644 index 0000000..cd54d32 --- /dev/null +++ b/ash/common/wm/focus_rules.h
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_FOCUS_RULES_H_ +#define ASH_COMMON_WM_FOCUS_RULES_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class WmWindow; + +// These functions provide the ash implementation wm::FocusRules. See +// description there for details. +ASH_EXPORT bool IsToplevelWindow(WmWindow* window); +ASH_EXPORT bool IsWindowConsideredActivatable(WmWindow* window); +ASH_EXPORT bool IsWindowConsideredVisibleForActivation(WmWindow* window); + +} // namespace ash + +#endif // ASH_COMMON_WM_FOCUS_RULES_H_
diff --git a/ash/common/wm/fullscreen_window_finder.cc b/ash/common/wm/fullscreen_window_finder.cc new file mode 100644 index 0000000..ee1bef34 --- /dev/null +++ b/ash/common/wm/fullscreen_window_finder.cc
@@ -0,0 +1,53 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/fullscreen_window_finder.h" + +#include "ash/common/wm/switchable_windows.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ui/compositor/layer.h" + +namespace ash { +namespace wm { + +WmWindow* GetWindowForFullscreenMode(WmWindow* context) { + WmWindow* topmost_window = nullptr; + WmWindow* active_window = context->GetShell()->GetActiveWindow(); + if (active_window && + active_window->GetRootWindow() == context->GetRootWindow() && + IsSwitchableContainer(active_window->GetParent())) { + // Use the active window when it is on the current root window to determine + // the fullscreen state to allow temporarily using a panel or docked window + // (which are always above the default container) while a fullscreen + // window is open. We only use the active window when in a switchable + // container as the launcher should not exit fullscreen mode. + topmost_window = active_window; + } else { + // Otherwise, use the topmost window on the root window's default container + // when there is no active window on this root window. + std::vector<WmWindow*> windows = + context->GetRootWindow() + ->GetChildByShellWindowId(kShellWindowId_DefaultContainer) + ->GetChildren(); + for (auto iter = windows.rbegin(); iter != windows.rend(); ++iter) { + if ((*iter)->GetWindowState()->IsUserPositionable() && + (*iter)->GetLayerTargetVisibility()) { + topmost_window = *iter; + break; + } + } + } + while (topmost_window) { + if (topmost_window->GetWindowState()->IsFullscreen()) + return topmost_window; + topmost_window = topmost_window->GetTransientParent(); + } + return nullptr; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/fullscreen_window_finder.h b/ash/common/wm/fullscreen_window_finder.h new file mode 100644 index 0000000..f5c78b9 --- /dev/null +++ b/ash/common/wm/fullscreen_window_finder.h
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_FULLSCREEN_WINDOW_FINDER_H_ +#define ASH_COMMON_WM_FULLSCREEN_WINDOW_FINDER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +class WmWindow; + +namespace wm { + +// Returns the topmost window or one of its transient parents, if any of them +// are in fullscreen mode. This searches for a window in the root of |context|. +ASH_EXPORT WmWindow* GetWindowForFullscreenMode(WmWindow* context); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_FULLSCREEN_WINDOW_FINDER_H_
diff --git a/ash/common/wm/immersive_context_ash.cc b/ash/common/wm/immersive_context_ash.cc new file mode 100644 index 0000000..c1cff55 --- /dev/null +++ b/ash/common/wm/immersive_context_ash.cc
@@ -0,0 +1,66 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/immersive_context_ash.h" + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/shared/immersive_fullscreen_controller.h" +#include "base/logging.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +ImmersiveContextAsh::ImmersiveContextAsh() {} + +ImmersiveContextAsh::~ImmersiveContextAsh() {} + +void ImmersiveContextAsh::InstallResizeHandleWindowTargeter( + ImmersiveFullscreenController* controller) { + WmWindow* window = WmWindow::Get(controller->widget()->GetNativeWindow()); + window->InstallResizeHandleWindowTargeter(controller); +} + +void ImmersiveContextAsh::OnEnteringOrExitingImmersive( + ImmersiveFullscreenController* controller, + bool entering) { + WmWindow* window = WmWindow::Get(controller->widget()->GetNativeWindow()); + wm::WindowState* window_state = window->GetWindowState(); + // Auto hide the shelf in immersive fullscreen instead of hiding it. + window_state->set_hide_shelf_when_fullscreen(!entering); + // Update the window's immersive mode state for the window manager. + window_state->set_in_immersive_fullscreen(entering); + + for (WmWindow* root_window : WmShell::Get()->GetAllRootWindows()) + WmShelf::ForWindow(root_window)->UpdateVisibilityState(); +} + +gfx::Rect ImmersiveContextAsh::GetDisplayBoundsInScreen(views::Widget* widget) { + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + return window->GetDisplayNearestWindow().bounds(); +} + +void ImmersiveContextAsh::AddPointerWatcher( + views::PointerWatcher* watcher, + views::PointerWatcherEventTypes events) { + WmShell::Get()->AddPointerWatcher(watcher, events); +} + +void ImmersiveContextAsh::RemovePointerWatcher(views::PointerWatcher* watcher) { + WmShell::Get()->RemovePointerWatcher(watcher); +} + +bool ImmersiveContextAsh::DoesAnyWindowHaveCapture() { + return WmShell::Get()->GetCaptureWindow() != nullptr; +} + +bool ImmersiveContextAsh::IsMouseEventsEnabled() { + return WmShell::Get()->IsMouseEventsEnabled(); +} + +} // namespace ash
diff --git a/ash/common/wm/immersive_context_ash.h b/ash/common/wm/immersive_context_ash.h new file mode 100644 index 0000000..7beed73 --- /dev/null +++ b/ash/common/wm/immersive_context_ash.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_IMMERSIVE_CONTEXT_ASH_H_ +#define ASH_COMMON_WM_IMMERSIVE_CONTEXT_ASH_H_ + +#include "ash/shared/immersive_context.h" +#include "base/macros.h" + +namespace ash { + +class ASH_EXPORT ImmersiveContextAsh : public ImmersiveContext { + public: + ImmersiveContextAsh(); + ~ImmersiveContextAsh() override; + + // ImmersiveContext: + void InstallResizeHandleWindowTargeter( + ImmersiveFullscreenController* controller) override; + void OnEnteringOrExitingImmersive(ImmersiveFullscreenController* controller, + bool entering) override; + gfx::Rect GetDisplayBoundsInScreen(views::Widget* widget) override; + void AddPointerWatcher(views::PointerWatcher* watcher, + views::PointerWatcherEventTypes events) override; + void RemovePointerWatcher(views::PointerWatcher* watcher) override; + bool DoesAnyWindowHaveCapture() override; + bool IsMouseEventsEnabled() override; + + private: + DISALLOW_COPY_AND_ASSIGN(ImmersiveContextAsh); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_IMMERSIVE_CONTEXT_ASH_H_
diff --git a/ash/common/wm/lock_layout_manager.cc b/ash/common/wm/lock_layout_manager.cc new file mode 100644 index 0000000..d66c5d42 --- /dev/null +++ b/ash/common/wm/lock_layout_manager.cc
@@ -0,0 +1,121 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/lock_layout_manager.h" + +#include "ash/common/wm/lock_window_state.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/events/event.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_util.h" + +namespace ash { + +LockLayoutManager::LockLayoutManager(WmWindow* window) + : wm::WmSnapToPixelLayoutManager(), + window_(window), + root_window_(window->GetRootWindow()), + is_observing_keyboard_(false) { + WmShell::Get()->AddShellObserver(this); + root_window_->aura_window()->AddObserver(this); + if (keyboard::KeyboardController::GetInstance()) { + keyboard::KeyboardController::GetInstance()->AddObserver(this); + is_observing_keyboard_ = true; + } +} + +LockLayoutManager::~LockLayoutManager() { + if (root_window_) + root_window_->aura_window()->RemoveObserver(this); + + for (WmWindow* child : window_->GetChildren()) + child->aura_window()->RemoveObserver(this); + + WmShell::Get()->RemoveShellObserver(this); + + if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) { + keyboard::KeyboardController::GetInstance()->RemoveObserver(this); + is_observing_keyboard_ = false; + } +} + +void LockLayoutManager::OnWindowResized() { + const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); + AdjustWindowsForWorkAreaChange(&event); +} + +void LockLayoutManager::OnWindowAddedToLayout(WmWindow* child) { + child->aura_window()->AddObserver(this); + + // LockWindowState replaces default WindowState of a child. + wm::WindowState* window_state = LockWindowState::SetLockWindowState(child); + wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); + window_state->OnWMEvent(&event); +} + +void LockLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) { + child->aura_window()->RemoveObserver(this); +} + +void LockLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {} + +void LockLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) {} + +void LockLayoutManager::SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) { + wm::WindowState* window_state = child->GetWindowState(); + wm::SetBoundsEvent event(wm::WM_EVENT_SET_BOUNDS, requested_bounds); + window_state->OnWMEvent(&event); +} + +void LockLayoutManager::OnWindowDestroying(aura::Window* window) { + window->RemoveObserver(this); + if (root_window_ == WmWindow::Get(window)) + root_window_ = nullptr; +} + +void LockLayoutManager::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (root_window_ == WmWindow::Get(window)) { + const wm::WMEvent wm_event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); + AdjustWindowsForWorkAreaChange(&wm_event); + } +} + +void LockLayoutManager::OnVirtualKeyboardStateChanged(bool activated) { + if (keyboard::KeyboardController::GetInstance()) { + if (activated) { + if (!is_observing_keyboard_) { + keyboard::KeyboardController::GetInstance()->AddObserver(this); + is_observing_keyboard_ = true; + } + } else { + keyboard::KeyboardController::GetInstance()->RemoveObserver(this); + is_observing_keyboard_ = false; + } + } +} + +void LockLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) { + keyboard_bounds_ = new_bounds; + OnWindowResized(); +} + +void LockLayoutManager::OnKeyboardClosed() {} + +void LockLayoutManager::AdjustWindowsForWorkAreaChange( + const wm::WMEvent* event) { + DCHECK(event->type() == wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED || + event->type() == wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); + + for (WmWindow* child : window_->GetChildren()) + child->GetWindowState()->OnWMEvent(event); +} + +} // namespace ash
diff --git a/ash/common/wm/lock_layout_manager.h b/ash/common/wm/lock_layout_manager.h new file mode 100644 index 0000000..9ba7473 --- /dev/null +++ b/ash/common/wm/lock_layout_manager.h
@@ -0,0 +1,85 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_LOCK_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_LOCK_LAYOUT_MANAGER_H_ + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h" +#include "ash/common/wm/wm_types.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace ash { +namespace wm { +class WindowState; +class WMEvent; +} + +// LockLayoutManager is used for the windows created in LockScreenContainer. +// For Chrome OS this includes out-of-box/login/lock/multi-profile login use +// cases. LockScreenContainer does not use default work area definition. +// By default work area is defined as display area minus shelf, docked windows +// and minus virtual keyboard bounds. +// For windows in LockScreenContainer work area is display area minus virtual +// keyboard bounds (only if keyboard overscroll is disabled). If keyboard +// overscroll is enabled then work area always equals to display area size since +// virtual keyboard changes inner workspace of each WebContents. +// For all windows in LockScreenContainer default wm::WindowState is replaced +// with LockWindowState. +class ASH_EXPORT LockLayoutManager + : public wm::WmSnapToPixelLayoutManager, + public aura::WindowObserver, + public ShellObserver, + public keyboard::KeyboardControllerObserver { + public: + explicit LockLayoutManager(WmWindow* window); + ~LockLayoutManager() override; + + // Overridden from WmSnapToPixelLayoutManager: + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override; + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + // Overriden from aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override; + + // ShellObserver: + void OnVirtualKeyboardStateChanged(bool activated) override; + + // keyboard::KeyboardControllerObserver overrides: + void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; + void OnKeyboardClosed() override; + + private: + // Adjusts the bounds of all managed windows when the display area changes. + // This happens when the display size, work area insets has changed. + void AdjustWindowsForWorkAreaChange(const wm::WMEvent* event); + + WmWindow* window_; + WmWindow* root_window_; + + // True is subscribed as keyboard controller observer. + bool is_observing_keyboard_; + + // The bounds of the keyboard. + gfx::Rect keyboard_bounds_; + + DISALLOW_COPY_AND_ASSIGN(LockLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_LOCK_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/lock_state_observer.h b/ash/common/wm/lock_state_observer.h new file mode 100644 index 0000000..a7d30fa0 --- /dev/null +++ b/ash/common/wm/lock_state_observer.h
@@ -0,0 +1,28 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_LOCK_STATE_OBSERVER_H_ +#define ASH_COMMON_WM_LOCK_STATE_OBSERVER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +// Interface for classes that want to be notified by LockStateController when +// session-related events occur. +class ASH_EXPORT LockStateObserver { + public: + enum EventType { + EVENT_PRELOCK_ANIMATION_STARTED, + EVENT_LOCK_ANIMATION_STARTED, + EVENT_LOCK_ANIMATION_FINISHED, + }; + + virtual void OnLockStateEvent(EventType event) = 0; + virtual ~LockStateObserver() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_LOCK_STATE_OBSERVER_H_
diff --git a/ash/common/wm/lock_window_state.cc b/ash/common/wm/lock_window_state.cc new file mode 100644 index 0000000..63af76d6 --- /dev/null +++ b/ash/common/wm/lock_window_state.cc
@@ -0,0 +1,184 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/lock_window_state.h" + +#include <utility> + +#include "ash/common/wm/lock_layout_manager.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_delegate.h" +#include "ash/common/wm/window_state_util.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/memory/ptr_util.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_util.h" + +namespace ash { + +LockWindowState::LockWindowState(WmWindow* window) + : current_state_type_(window->GetWindowState()->GetStateType()) {} + +LockWindowState::~LockWindowState() {} + +void LockWindowState::OnWMEvent(wm::WindowState* window_state, + const wm::WMEvent* event) { + switch (event->type()) { + case wm::WM_EVENT_TOGGLE_FULLSCREEN: + ToggleFullScreen(window_state, window_state->delegate()); + break; + case wm::WM_EVENT_FULLSCREEN: + UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN); + break; + case wm::WM_EVENT_PIN: + case wm::WM_EVENT_TRUSTED_PIN: + NOTREACHED(); + break; + case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: + case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: + case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: + case wm::WM_EVENT_TOGGLE_MAXIMIZE: + case wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT: + case wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: + case wm::WM_EVENT_CENTER: + case wm::WM_EVENT_SNAP_LEFT: + case wm::WM_EVENT_SNAP_RIGHT: + case wm::WM_EVENT_NORMAL: + case wm::WM_EVENT_MAXIMIZE: + case wm::WM_EVENT_DOCK: + UpdateWindow(window_state, + GetMaximizedOrCenteredWindowType(window_state)); + return; + case wm::WM_EVENT_MINIMIZE: + UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED); + return; + case wm::WM_EVENT_SHOW_INACTIVE: + return; + case wm::WM_EVENT_SET_BOUNDS: + if (window_state->IsMaximized() || window_state->IsFullscreen()) { + UpdateBounds(window_state); + } else { + const ash::wm::SetBoundsEvent* bounds_event = + static_cast<const ash::wm::SetBoundsEvent*>(event); + window_state->SetBoundsConstrained(bounds_event->requested_bounds()); + } + break; + case wm::WM_EVENT_ADDED_TO_WORKSPACE: + if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) { + UpdateWindow(window_state, + GetMaximizedOrCenteredWindowType(window_state)); + } else { + UpdateBounds(window_state); + } + break; + case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED: + case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED: + UpdateBounds(window_state); + break; + } +} + +wm::WindowStateType LockWindowState::GetType() const { + return current_state_type_; +} + +void LockWindowState::AttachState(wm::WindowState* window_state, + wm::WindowState::State* previous_state) { + current_state_type_ = previous_state->GetType(); + + // Initialize the state to a good preset. + if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) { + UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state)); + } +} + +void LockWindowState::DetachState(wm::WindowState* window_state) {} + +// static +wm::WindowState* LockWindowState::SetLockWindowState(WmWindow* window) { + std::unique_ptr<wm::WindowState::State> lock_state = + base::MakeUnique<LockWindowState>(window); + std::unique_ptr<wm::WindowState::State> old_state( + window->GetWindowState()->SetStateObject(std::move(lock_state))); + return window->GetWindowState(); +} + +void LockWindowState::UpdateWindow(wm::WindowState* window_state, + wm::WindowStateType target_state) { + DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED || + target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED || + (target_state == wm::WINDOW_STATE_TYPE_NORMAL && + !window_state->CanMaximize()) || + target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN); + + if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) { + if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED) + return; + + current_state_type_ = target_state; + window_state->window()->SetVisibilityAnimationType( + wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); + window_state->window()->Hide(); + if (window_state->IsActive()) + window_state->Deactivate(); + return; + } + + if (current_state_type_ == target_state) { + // If the state type did not change, update it accordingly. + UpdateBounds(window_state); + return; + } + + const wm::WindowStateType old_state_type = current_state_type_; + current_state_type_ = target_state; + window_state->UpdateWindowShowStateFromStateType(); + window_state->NotifyPreStateTypeChange(old_state_type); + UpdateBounds(window_state); + window_state->NotifyPostStateTypeChange(old_state_type); + + if ((window_state->window()->GetTargetVisibility() || + old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) && + !window_state->window()->GetLayer()->visible()) { + // The layer may be hidden if the window was previously minimized. Make + // sure it's visible. + window_state->window()->Show(); + } +} + +wm::WindowStateType LockWindowState::GetMaximizedOrCenteredWindowType( + wm::WindowState* window_state) { + return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED + : wm::WINDOW_STATE_TYPE_NORMAL; +} + +void LockWindowState::UpdateBounds(wm::WindowState* window_state) { + if (!window_state->IsMaximized() && !window_state->IsFullscreen()) + return; + + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + gfx::Rect keyboard_bounds; + + if (keyboard_controller && !keyboard::IsKeyboardOverscrollEnabled() && + keyboard_controller->keyboard_visible()) { + keyboard_bounds = keyboard_controller->current_keyboard_bounds(); + } + gfx::Rect bounds = wm::GetDisplayBoundsWithShelf(window_state->window()); + bounds.set_height(bounds.height() - keyboard_bounds.height()); + + VLOG(1) << "Updating window bounds to: " << bounds.ToString(); + window_state->SetBoundsDirect(bounds); +} + +} // namespace ash
diff --git a/ash/common/wm/lock_window_state.h b/ash/common/wm/lock_window_state.h new file mode 100644 index 0000000..e8abfc7 --- /dev/null +++ b/ash/common/wm/lock_window_state.h
@@ -0,0 +1,59 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_LOCK_WINDOW_STATE_H_ +#define ASH_COMMON_WM_LOCK_WINDOW_STATE_H_ + +#include "ash/common/wm/window_state.h" +#include "base/macros.h" + +namespace ash { + +// The LockWindowState implementation which reduces all possible window +// states to maximized (or normal if can't be maximized)/minimized/full-screen +// and is applied only on lock (login) window container. +// LockWindowState implements Ash behavior without state machine. +class LockWindowState : public wm::WindowState::State { + public: + // The |window|'s state object will be modified to use this new window mode + // state handler. + explicit LockWindowState(WmWindow* window); + ~LockWindowState() override; + + // WindowState::State overrides: + void OnWMEvent(wm::WindowState* window_state, + const wm::WMEvent* event) override; + wm::WindowStateType GetType() const override; + void AttachState(wm::WindowState* window_state, + wm::WindowState::State* previous_state) override; + void DetachState(wm::WindowState* window_state) override; + + // Creates new LockWindowState instance and attaches it to |window|. + static wm::WindowState* SetLockWindowState(WmWindow* window); + + private: + // Updates the window to |new_state_type| and resulting bounds: + // Either full screen, maximized centered or minimized. If the state does not + // change, only the bounds will be changed. + void UpdateWindow(wm::WindowState* window_state, + wm::WindowStateType new_state_type); + + // Depending on the capabilities of the window we either return + // |WINDOW_STATE_TYPE_MAXIMIZED| or |WINDOW_STATE_TYPE_NORMAL|. + wm::WindowStateType GetMaximizedOrCenteredWindowType( + wm::WindowState* window_state); + + // Updates the bounds taking virtual keyboard bounds into consideration. + void UpdateBounds(wm::WindowState* window_state); + + // The current state type. Due to the nature of this state, this can only be + // WM_STATE_TYPE{NORMAL, MINIMIZED, MAXIMIZED}. + wm::WindowStateType current_state_type_; + + DISALLOW_COPY_AND_ASSIGN(LockWindowState); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_LOCK_WINDOW_STATE_H_
diff --git a/ash/common/wm/maximize_mode/OWNERS b/ash/common/wm/maximize_mode/OWNERS new file mode 100644 index 0000000..0debac9 --- /dev/null +++ b/ash/common/wm/maximize_mode/OWNERS
@@ -0,0 +1,2 @@ +skuhne@chromium.org +
diff --git a/ash/common/wm/maximize_mode/maximize_mode_controller.cc b/ash/common/wm/maximize_mode/maximize_mode_controller.cc new file mode 100644 index 0000000..6ea28be --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_controller.cc
@@ -0,0 +1,427 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" + +#include <utility> + +#include "ash/common/ash_switches.h" +#include "ash/common/wm/maximize_mode/maximize_mode_window_manager.h" +#include "ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" +#include "ash/common/wm_shell.h" +#include "base/command_line.h" +#include "base/metrics/histogram_macros.h" +#include "base/time/default_tick_clock.h" +#include "base/time/tick_clock.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/chromeos/accelerometer/accelerometer_util.h" +#include "ui/display/display.h" +#include "ui/events/event.h" +#include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/geometry/vector3d_f.h" + +namespace ash { + +namespace { + +// The hinge angle at which to enter maximize mode. +const float kEnterMaximizeModeAngle = 200.0f; + +// The angle at which to exit maximize mode, this is specifically less than the +// angle to enter maximize mode to prevent rapid toggling when near the angle. +const float kExitMaximizeModeAngle = 160.0f; + +// Defines a range for which accelerometer readings are considered accurate. +// When the lid is near open (or near closed) the accelerometer readings may be +// inaccurate and a lid that is fully open may appear to be near closed (and +// vice versa). +const float kMinStableAngle = 20.0f; +const float kMaxStableAngle = 340.0f; + +// The time duration to consider the lid to be recently opened. +// This is used to prevent entering maximize mode if an erroneous accelerometer +// reading makes the lid appear to be fully open when the user is opening the +// lid from a closed position. +const int kLidRecentlyOpenedDurationSeconds = 2; + +// When the device approaches vertical orientation (i.e. portrait orientation) +// the accelerometers for the base and lid approach the same values (i.e. +// gravity pointing in the direction of the hinge). When this happens abrupt +// small acceleration perpendicular to the hinge can lead to incorrect hinge +// angle calculations. To prevent this the accelerometer updates will be +// smoothed over time in order to reduce this noise. +// This is the minimum acceleration parallel to the hinge under which to begin +// smoothing in m/s^2. +const float kHingeVerticalSmoothingStart = 7.0f; +// This is the maximum acceleration parallel to the hinge under which smoothing +// will incorporate new acceleration values, in m/s^2. +const float kHingeVerticalSmoothingMaximum = 8.7f; + +// The maximum deviation between the magnitude of the two accelerometers under +// which to detect hinge angle in m/s^2. These accelerometers are attached to +// the same physical device and so should be under the same acceleration. +const float kNoisyMagnitudeDeviation = 1.0f; + +// The angle between chromeos::AccelerometerReadings are considered stable if +// their magnitudes do not differ greatly. This returns false if the deviation +// between the screen and keyboard accelerometers is too high. +bool IsAngleBetweenAccelerometerReadingsStable( + const chromeos::AccelerometerUpdate& update) { + return std::abs( + ui::ConvertAccelerometerReadingToVector3dF( + update.get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) + .Length() - + ui::ConvertAccelerometerReadingToVector3dF( + update.get(chromeos::ACCELEROMETER_SOURCE_SCREEN)) + .Length()) <= kNoisyMagnitudeDeviation; +} + +bool IsEnabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshEnableTouchView); +} + +} // namespace + +MaximizeModeController::MaximizeModeController() + : have_seen_accelerometer_data_(false), + touchview_usage_interval_start_time_(base::Time::Now()), + tick_clock_(new base::DefaultTickClock()), + tablet_mode_switch_is_on_(false), + lid_is_closed_(false) { + WmShell::Get()->AddShellObserver(this); + WmShell::Get()->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_INITIALLY_DISABLED); + + // TODO(jonross): Do not create MaximizeModeController if the flag is + // unavailable. This will require refactoring + // IsMaximizeModeWindowManagerEnabled to check for the existance of the + // controller. + if (IsEnabled()) { + WmShell::Get()->AddDisplayObserver(this); + chromeos::AccelerometerReader::GetInstance()->AddObserver(this); + } + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( + this); +} + +MaximizeModeController::~MaximizeModeController() { + WmShell::Get()->RemoveShellObserver(this); + + if (IsEnabled()) { + WmShell::Get()->RemoveDisplayObserver(this); + chromeos::AccelerometerReader::GetInstance()->RemoveObserver(this); + } + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( + this); +} + +bool MaximizeModeController::CanEnterMaximizeMode() { + // If we have ever seen accelerometer data, then HandleHingeRotation may + // trigger maximize mode at some point in the future. + // All TouchView-enabled devices can enter maximized mode. + return have_seen_accelerometer_data_ || IsEnabled(); +} + +// TODO(jcliang): Hide or remove EnableMaximizeModeWindowManager +// (http://crbug.com/620241). +void MaximizeModeController::EnableMaximizeModeWindowManager( + bool should_enable) { + bool is_enabled = !!maximize_mode_window_manager_.get(); + if (should_enable == is_enabled) + return; + + WmShell* shell = WmShell::Get(); + + if (should_enable) { + maximize_mode_window_manager_.reset(new MaximizeModeWindowManager()); + // TODO(jonross): Move the maximize mode notifications from ShellObserver + // to MaximizeModeController::Observer + shell->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_ENABLED); + shell->OnMaximizeModeStarted(); + + observers_.ForAllPtrs([](mojom::TouchViewObserver* observer) { + observer->OnTouchViewToggled(true); + }); + + } else { + shell->OnMaximizeModeEnding(); + maximize_mode_window_manager_.reset(); + shell->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_DISABLED); + shell->OnMaximizeModeEnded(); + + observers_.ForAllPtrs([](mojom::TouchViewObserver* observer) { + observer->OnTouchViewToggled(false); + }); + } +} + +bool MaximizeModeController::IsMaximizeModeWindowManagerEnabled() const { + return maximize_mode_window_manager_.get() != NULL; +} + +void MaximizeModeController::AddWindow(WmWindow* window) { + if (IsMaximizeModeWindowManagerEnabled()) + maximize_mode_window_manager_->AddWindow(window); +} + +void MaximizeModeController::BindRequest( + mojom::TouchViewManagerRequest request) { + bindings_.AddBinding(this, std::move(request)); +} + +void MaximizeModeController::OnAccelerometerUpdated( + scoped_refptr<const chromeos::AccelerometerUpdate> update) { + bool first_accelerometer_update = !have_seen_accelerometer_data_; + have_seen_accelerometer_data_ = true; + + if (!update->has(chromeos::ACCELEROMETER_SOURCE_SCREEN)) + return; + + if (!display::Display::HasInternalDisplay()) + return; + + if (!WmShell::Get()->IsActiveDisplayId( + display::Display::InternalDisplayId())) { + return; + } + + // Whether or not we enter maximize mode affects whether we handle screen + // rotation, so determine whether to enter maximize mode first. + if (!update->has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) { + if (first_accelerometer_update) + EnterMaximizeMode(); + } else if (ui::IsAccelerometerReadingStable( + *update, chromeos::ACCELEROMETER_SOURCE_SCREEN) && + ui::IsAccelerometerReadingStable( + *update, chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) && + IsAngleBetweenAccelerometerReadingsStable(*update)) { + // update.has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) + // Ignore the reading if it appears unstable. The reading is considered + // unstable if it deviates too much from gravity and/or the magnitude of the + // reading from the lid differs too much from the reading from the base. + HandleHingeRotation(update); + } +} + +void MaximizeModeController::LidEventReceived(bool open, + const base::TimeTicks& time) { + if (open) + last_lid_open_time_ = time; + lid_is_closed_ = !open; + LeaveMaximizeMode(); +} + +void MaximizeModeController::TabletModeEventReceived( + bool on, + const base::TimeTicks& time) { + tablet_mode_switch_is_on_ = on; + // Do not change if docked. + if (!display::Display::HasInternalDisplay() || + !WmShell::Get()->IsActiveDisplayId( + display::Display::InternalDisplayId())) { + return; + } + if (on && !IsMaximizeModeWindowManagerEnabled()) + EnterMaximizeMode(); +} + +void MaximizeModeController::SuspendImminent() { + // The system is about to suspend, so record TouchView usage interval metrics + // based on whether TouchView mode is currently active. + RecordTouchViewUsageInterval(CurrentTouchViewIntervalType()); +} + +void MaximizeModeController::SuspendDone( + const base::TimeDelta& sleep_duration) { + // We do not want TouchView usage metrics to include time spent in suspend. + touchview_usage_interval_start_time_ = base::Time::Now(); +} + +void MaximizeModeController::HandleHingeRotation( + scoped_refptr<const chromeos::AccelerometerUpdate> update) { + static const gfx::Vector3dF hinge_vector(1.0f, 0.0f, 0.0f); + gfx::Vector3dF base_reading(ui::ConvertAccelerometerReadingToVector3dF( + update->get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD))); + gfx::Vector3dF lid_reading(ui::ConvertAccelerometerReadingToVector3dF( + update->get(chromeos::ACCELEROMETER_SOURCE_SCREEN))); + + // As the hinge approaches a vertical angle, the base and lid accelerometers + // approach the same values making any angle calculations highly inaccurate. + // Smooth out instantaneous acceleration when nearly vertical to increase + // accuracy. + float largest_hinge_acceleration = + std::max(std::abs(base_reading.x()), std::abs(lid_reading.x())); + float smoothing_ratio = + std::max(0.0f, std::min(1.0f, (largest_hinge_acceleration - + kHingeVerticalSmoothingStart) / + (kHingeVerticalSmoothingMaximum - + kHingeVerticalSmoothingStart))); + + // We cannot trust the computed lid angle when the device is held vertically. + bool is_angle_reliable = + largest_hinge_acceleration <= kHingeVerticalSmoothingMaximum; + + base_smoothed_.Scale(smoothing_ratio); + base_reading.Scale(1.0f - smoothing_ratio); + base_smoothed_.Add(base_reading); + + lid_smoothed_.Scale(smoothing_ratio); + lid_reading.Scale(1.0f - smoothing_ratio); + lid_smoothed_.Add(lid_reading); + + if (tablet_mode_switch_is_on_) + return; + + // Ignore the component of acceleration parallel to the hinge for the purposes + // of hinge angle calculation. + gfx::Vector3dF base_flattened(base_smoothed_); + gfx::Vector3dF lid_flattened(lid_smoothed_); + base_flattened.set_x(0.0f); + lid_flattened.set_x(0.0f); + + // Compute the angle between the base and the lid. + float lid_angle = 180.0f - gfx::ClockwiseAngleBetweenVectorsInDegrees( + base_flattened, lid_flattened, hinge_vector); + if (lid_angle < 0.0f) + lid_angle += 360.0f; + + bool is_angle_stable = is_angle_reliable && lid_angle >= kMinStableAngle && + lid_angle <= kMaxStableAngle; + + // Clear the last_lid_open_time_ for a stable reading so that there is less + // chance of a delay if the lid is moved from the close state to the fully + // open state very quickly. + if (is_angle_stable) + last_lid_open_time_ = base::TimeTicks(); + + // Toggle maximize mode on or off when corresponding thresholds are passed. + if (IsMaximizeModeWindowManagerEnabled() && is_angle_stable && + lid_angle <= kExitMaximizeModeAngle) { + LeaveMaximizeMode(); + } else if (!IsMaximizeModeWindowManagerEnabled() && !lid_is_closed_ && + lid_angle >= kEnterMaximizeModeAngle && + (is_angle_stable || !WasLidOpenedRecently())) { + EnterMaximizeMode(); + } +} + +void MaximizeModeController::EnterMaximizeMode() { + // Always reset first to avoid creation before destruction of a previous + // object. + event_blocker_ = + WmShell::Get()->CreateScopedDisableInternalMouseAndKeyboard(); + + if (IsMaximizeModeWindowManagerEnabled()) + return; + EnableMaximizeModeWindowManager(true); +} + +void MaximizeModeController::LeaveMaximizeMode() { + event_blocker_.reset(); + + if (!IsMaximizeModeWindowManagerEnabled()) + return; + EnableMaximizeModeWindowManager(false); +} + +// Called after maximize mode has started, windows might still animate though. +void MaximizeModeController::OnMaximizeModeStarted() { + RecordTouchViewUsageInterval(TOUCH_VIEW_INTERVAL_INACTIVE); +} + +// Called after maximize mode has ended, windows might still be returning to +// their original position. +void MaximizeModeController::OnMaximizeModeEnded() { + RecordTouchViewUsageInterval(TOUCH_VIEW_INTERVAL_ACTIVE); +} + +void MaximizeModeController::OnDisplayConfigurationChanged() { + if (!display::Display::HasInternalDisplay() || + !WmShell::Get()->IsActiveDisplayId( + display::Display::InternalDisplayId())) { + LeaveMaximizeMode(); + } else if (tablet_mode_switch_is_on_ && + !IsMaximizeModeWindowManagerEnabled()) { + // The internal display has returned, as we are exiting docked mode. + // The device is still in tablet mode, so trigger maximize mode, as this + // switch leads to the ignoring of accelerometer events. When the switch is + // not set the next stable accelerometer readings will trigger maximize + // mode. + EnterMaximizeMode(); + } +} + +void MaximizeModeController::RecordTouchViewUsageInterval( + TouchViewIntervalType type) { + if (!CanEnterMaximizeMode()) + return; + + base::Time current_time = base::Time::Now(); + base::TimeDelta delta = current_time - touchview_usage_interval_start_time_; + switch (type) { + case TOUCH_VIEW_INTERVAL_INACTIVE: + UMA_HISTOGRAM_LONG_TIMES("Ash.TouchView.TouchViewInactive", delta); + total_non_touchview_time_ += delta; + break; + case TOUCH_VIEW_INTERVAL_ACTIVE: + UMA_HISTOGRAM_LONG_TIMES("Ash.TouchView.TouchViewActive", delta); + total_touchview_time_ += delta; + break; + } + + touchview_usage_interval_start_time_ = current_time; +} + +MaximizeModeController::TouchViewIntervalType +MaximizeModeController::CurrentTouchViewIntervalType() { + if (IsMaximizeModeWindowManagerEnabled()) + return TOUCH_VIEW_INTERVAL_ACTIVE; + return TOUCH_VIEW_INTERVAL_INACTIVE; +} + +void MaximizeModeController::AddObserver(mojom::TouchViewObserverPtr observer) { + observer->OnTouchViewToggled(IsMaximizeModeWindowManagerEnabled()); + observers_.AddPtr(std::move(observer)); +} + +void MaximizeModeController::OnAppTerminating() { + // The system is about to shut down, so record TouchView usage interval + // metrics based on whether TouchView mode is currently active. + RecordTouchViewUsageInterval(CurrentTouchViewIntervalType()); + + if (CanEnterMaximizeMode()) { + UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchView.TouchViewActiveTotal", + total_touchview_time_.InMinutes(), 1, + base::TimeDelta::FromDays(7).InMinutes(), 50); + UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchView.TouchViewInactiveTotal", + total_non_touchview_time_.InMinutes(), 1, + base::TimeDelta::FromDays(7).InMinutes(), 50); + base::TimeDelta total_runtime = + total_touchview_time_ + total_non_touchview_time_; + if (total_runtime.InSeconds() > 0) { + UMA_HISTOGRAM_PERCENTAGE( + "Ash.TouchView.TouchViewActivePercentage", + 100 * total_touchview_time_.InSeconds() / total_runtime.InSeconds()); + } + } +} + +bool MaximizeModeController::WasLidOpenedRecently() const { + if (last_lid_open_time_.is_null()) + return false; + + base::TimeTicks now = tick_clock_->NowTicks(); + DCHECK(now >= last_lid_open_time_); + base::TimeDelta elapsed_time = now - last_lid_open_time_; + return elapsed_time.InSeconds() <= kLidRecentlyOpenedDurationSeconds; +} + +void MaximizeModeController::SetTickClockForTest( + std::unique_ptr<base::TickClock> tick_clock) { + DCHECK(tick_clock_); + tick_clock_ = std::move(tick_clock); +} + +} // namespace ash
diff --git a/ash/common/wm/maximize_mode/maximize_mode_controller.h b/ash/common/wm/maximize_mode/maximize_mode_controller.h new file mode 100644 index 0000000..32650fe --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_controller.h
@@ -0,0 +1,192 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_CONTROLLER_H_ +#define ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm_display_observer.h" +#include "ash/public/interfaces/touch_view.mojom.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "chromeos/accelerometer/accelerometer_reader.h" +#include "chromeos/accelerometer/accelerometer_types.h" +#include "chromeos/dbus/power_manager_client.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/interface_ptr_set.h" +#include "ui/gfx/geometry/vector3d_f.h" + +namespace base { +class TickClock; +} + +namespace gfx { +class Vector3dF; +} + +namespace ash { + +class MaximizeModeControllerTest; +class ScopedDisableInternalMouseAndKeyboard; +class MaximizeModeWindowManager; +class MaximizeModeWindowManagerTest; +class WmWindow; +namespace test { +class MultiUserWindowManagerChromeOSTest; +class VirtualKeyboardControllerTest; +} + +// MaximizeModeController listens to accelerometer events and automatically +// enters and exits maximize mode when the lid is opened beyond the triggering +// angle and rotates the display to match the device when in maximize mode. +class ASH_EXPORT MaximizeModeController : + public chromeos::AccelerometerReader::Observer, + public chromeos::PowerManagerClient::Observer, + NON_EXPORTED_BASE(public mojom::TouchViewManager), + public ShellObserver, + public WmDisplayObserver { + public: + MaximizeModeController(); + ~MaximizeModeController() override; + + // True if it is possible to enter maximize mode in the current + // configuration. If this returns false, it should never be the case that + // maximize mode becomes enabled. + bool CanEnterMaximizeMode(); + + // TODO(jonross): Merge this with EnterMaximizeMode. Currently these are + // separate for several reasons: there is no internal display when running + // unittests; the event blocker prevents keyboard input when running ChromeOS + // on linux. http://crbug.com/362881 + // Turn the always maximize mode window manager on or off. + void EnableMaximizeModeWindowManager(bool should_enable); + + // Test if the MaximizeModeWindowManager is enabled or not. + bool IsMaximizeModeWindowManagerEnabled() const; + + // Add a special window to the MaximizeModeWindowManager for tracking. This is + // only required for special windows which are handled by other window + // managers like the |MultiUserWindowManager|. + // If the maximize mode is not enabled no action will be performed. + void AddWindow(WmWindow* window); + + // Binds the mojom::TouchViewManager interface request to this object. + void BindRequest(mojom::TouchViewManagerRequest request); + + // ShellObserver: + void OnAppTerminating() override; + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + + // WmDisplayObserver: + void OnDisplayConfigurationChanged() override; + + // chromeos::AccelerometerReader::Observer: + void OnAccelerometerUpdated( + scoped_refptr<const chromeos::AccelerometerUpdate> update) override; + + // PowerManagerClient::Observer: + void LidEventReceived(bool open, const base::TimeTicks& time) override; + void TabletModeEventReceived(bool on, const base::TimeTicks& time) override; + void SuspendImminent() override; + void SuspendDone(const base::TimeDelta& sleep_duration) override; + + private: + friend class MaximizeModeControllerTest; + friend class MaximizeModeWindowManagerTest; + friend class test::MultiUserWindowManagerChromeOSTest; + friend class test::VirtualKeyboardControllerTest; + + // Used for recording metrics for intervals of time spent in + // and out of TouchView. + enum TouchViewIntervalType { + TOUCH_VIEW_INTERVAL_INACTIVE, + TOUCH_VIEW_INTERVAL_ACTIVE + }; + + // Set the TickClock. This is only to be used by tests that need to + // artificially and deterministically control the current time. + void SetTickClockForTest(std::unique_ptr<base::TickClock> tick_clock); + + // Detect hinge rotation from base and lid accelerometers and automatically + // start / stop maximize mode. + void HandleHingeRotation( + scoped_refptr<const chromeos::AccelerometerUpdate> update); + + // Returns true if the lid was recently opened. + bool WasLidOpenedRecently() const; + + // Enables MaximizeModeWindowManager, and determines the current state of + // rotation lock. + void EnterMaximizeMode(); + + // Removes MaximizeModeWindowManager and resets the display rotation if there + // is no rotation lock. + void LeaveMaximizeMode(); + + // Record UMA stats tracking TouchView usage. If |type| is + // TOUCH_VIEW_INTERVAL_INACTIVE, then record that TouchView has been + // inactive from |touchview_usage_interval_start_time_| until now. + // Similarly, record that TouchView has been active if |type| is + // TOUCH_VIEW_INTERVAL_ACTIVE. + void RecordTouchViewUsageInterval(TouchViewIntervalType type); + + // Returns TOUCH_VIEW_INTERVAL_ACTIVE if TouchView is currently active, + // otherwise returns TOUCH_VIEW_INTERNAL_INACTIVE. + TouchViewIntervalType CurrentTouchViewIntervalType(); + + // mojom::TouchViewManager: + void AddObserver(mojom::TouchViewObserverPtr observer) override; + + // The maximized window manager (if enabled). + std::unique_ptr<MaximizeModeWindowManager> maximize_mode_window_manager_; + + // A helper class which when instantiated will block native events from the + // internal keyboard and touchpad. + std::unique_ptr<ScopedDisableInternalMouseAndKeyboard> event_blocker_; + + // Whether we have ever seen accelerometer data. + bool have_seen_accelerometer_data_; + + // Tracks time spent in (and out of) touchview mode. + base::Time touchview_usage_interval_start_time_; + base::TimeDelta total_touchview_time_; + base::TimeDelta total_non_touchview_time_; + + // Tracks the last time we received a lid open event. This is used to suppress + // erroneous accelerometer readings as the lid is opened but the accelerometer + // reports readings that make the lid to appear near fully open. + base::TimeTicks last_lid_open_time_; + + // Source for the current time in base::TimeTicks. + std::unique_ptr<base::TickClock> tick_clock_; + + // Set when tablet mode switch is on. This is used to force maximize mode. + bool tablet_mode_switch_is_on_; + + // Tracks when the lid is closed. Used to prevent entering maximize mode. + bool lid_is_closed_; + + // Tracks smoothed accelerometer data over time. This is done when the hinge + // is approaching vertical to remove abrupt acceleration that can lead to + // incorrect calculations of hinge angles. + gfx::Vector3dF base_smoothed_; + gfx::Vector3dF lid_smoothed_; + + // Bindings for the TouchViewManager interface. + mojo::BindingSet<mojom::TouchViewManager> bindings_; + + // The set of touchview observers to be notified about mode changes. + mojo::InterfacePtrSet<mojom::TouchViewObserver> observers_; + + DISALLOW_COPY_AND_ASSIGN(MaximizeModeController); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_CONTROLLER_H_
diff --git a/ash/common/wm/maximize_mode/maximize_mode_event_handler.cc b/ash/common/wm/maximize_mode/maximize_mode_event_handler.cc new file mode 100644 index 0000000..da77506 --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_event_handler.cc
@@ -0,0 +1,72 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/maximize_mode/maximize_mode_event_handler.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/events/event.h" + +namespace ash { +namespace wm { +namespace { + +// The height of the area in which a touch operation leads to exiting the +// full screen mode. +const int kLeaveFullScreenAreaHeightInPixel = 2; + +} // namespace + +MaximizeModeEventHandler::MaximizeModeEventHandler() {} + +MaximizeModeEventHandler::~MaximizeModeEventHandler() {} + +bool MaximizeModeEventHandler::ToggleFullscreen(const ui::TouchEvent& event) { + if (event.type() != ui::ET_TOUCH_PRESSED) + return false; + + const SessionStateDelegate* delegate = + WmShell::Get()->GetSessionStateDelegate(); + + if (delegate->IsScreenLocked() || + delegate->GetSessionState() != session_manager::SessionState::ACTIVE) { + return false; + } + + // Find the active window (from the primary screen) to un-fullscreen. + WmWindow* window = WmShell::Get()->GetActiveWindow(); + if (!window) + return false; + + WindowState* window_state = window->GetWindowState(); + if (!window_state->IsFullscreen() || window_state->in_immersive_fullscreen()) + return false; + + // Test that the touch happened in the top or bottom lines. + int y = event.y(); + if (y >= kLeaveFullScreenAreaHeightInPixel && + y < (window->GetBounds().height() - kLeaveFullScreenAreaHeightInPixel)) { + return false; + } + + // Do not exit fullscreen in kiosk mode. + SystemTrayDelegate* system_tray_delegate = + WmShell::Get()->system_tray_delegate(); + if (system_tray_delegate->GetUserLoginStatus() == LoginStatus::KIOSK_APP || + system_tray_delegate->GetUserLoginStatus() == + LoginStatus::ARC_KIOSK_APP) { + return false; + } + + WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN); + window->GetWindowState()->OnWMEvent(&toggle_fullscreen); + return true; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/maximize_mode/maximize_mode_event_handler.h b/ash/common/wm/maximize_mode/maximize_mode_event_handler.h new file mode 100644 index 0000000..bb7d6b5 --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_event_handler.h
@@ -0,0 +1,37 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_H_ +#define ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_H_ + +#include "base/macros.h" + +namespace ui { +class TouchEvent; +} + +namespace ash { +namespace wm { + +// MaximizeModeEventHandler handles toggling fullscreen when appropriate. +// MaximizeModeEventHandler installs event handlers in an environment specific +// way, e.g. EventHandler for aura. +class MaximizeModeEventHandler { + public: + MaximizeModeEventHandler(); + virtual ~MaximizeModeEventHandler(); + + protected: + // Subclasses call this to toggle fullscreen. If a toggle happened returns + // true. + bool ToggleFullscreen(const ui::TouchEvent& event); + + private: + DISALLOW_COPY_AND_ASSIGN(MaximizeModeEventHandler); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_H_
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc new file mode 100644 index 0000000..9cafa32 --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
@@ -0,0 +1,332 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/maximize_mode/maximize_mode_window_manager.h" + +#include "ash/common/ash_switches.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_event_handler.h" +#include "ash/common/wm/maximize_mode/maximize_mode_window_state.h" +#include "ash/common/wm/maximize_mode/workspace_backdrop_delegate.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/wm/window_state_aura.h" +#include "base/command_line.h" +#include "base/memory/ptr_util.h" +#include "base/stl_util.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/display/screen.h" + +namespace ash { + +namespace { + +// Exits overview mode if it is currently active. +void CancelOverview() { + WindowSelectorController* controller = + WmShell::Get()->window_selector_controller(); + if (controller->IsSelecting()) + controller->OnSelectionEnded(); +} + +} // namespace + +MaximizeModeWindowManager::~MaximizeModeWindowManager() { + // Overview mode needs to be ended before exiting maximize mode to prevent + // transforming windows which are currently in + // overview: http://crbug.com/366605 + CancelOverview(); + for (aura::Window* window : added_windows_) + window->RemoveObserver(this); + added_windows_.clear(); + WmShell::Get()->RemoveShellObserver(this); + display::Screen::GetScreen()->RemoveObserver(this); + EnableBackdropBehindTopWindowOnEachDisplay(false); + RemoveWindowCreationObservers(); + RestoreAllWindows(); +} + +int MaximizeModeWindowManager::GetNumberOfManagedWindows() { + return window_state_map_.size(); +} + +void MaximizeModeWindowManager::AddWindow(WmWindow* window) { + // Only add the window if it is a direct dependent of a container window + // and not yet tracked. + if (!ShouldHandleWindow(window) || + base::ContainsKey(window_state_map_, window) || + !IsContainerWindow(window->GetParent()->aura_window())) { + return; + } + + MaximizeAndTrackWindow(window); +} + +void MaximizeModeWindowManager::WindowStateDestroyed(WmWindow* window) { + // At this time ForgetWindow() should already have been called. If not, + // someone else must have replaced the "window manager's state object". + DCHECK(!window->aura_window()->HasObserver(this)); + + auto it = window_state_map_.find(window); + DCHECK(it != window_state_map_.end()); + window_state_map_.erase(it); +} + +void MaximizeModeWindowManager::OnOverviewModeStarting() { + if (backdrops_hidden_) + return; + + EnableBackdropBehindTopWindowOnEachDisplay(false); + SetDeferBoundsUpdates(true); + backdrops_hidden_ = true; +} + +void MaximizeModeWindowManager::OnOverviewModeEnded() { + if (!backdrops_hidden_) + return; + + backdrops_hidden_ = false; + EnableBackdropBehindTopWindowOnEachDisplay(true); + SetDeferBoundsUpdates(false); +} + +void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) { + if (IsContainerWindow(window)) { + // container window can be removed on display destruction. + window->RemoveObserver(this); + observed_container_windows_.erase(window); + } else if (base::ContainsValue(added_windows_, window)) { + // Added window was destroyed before being shown. + added_windows_.erase(window); + window->RemoveObserver(this); + } else { + // If a known window gets destroyed we need to remove all knowledge about + // it. + ForgetWindow(WmWindow::Get(window)); + } +} + +void MaximizeModeWindowManager::OnWindowHierarchyChanged( + const HierarchyChangeParams& params) { + // A window can get removed and then re-added by a drag and drop operation. + if (params.new_parent && IsContainerWindow(params.new_parent) && + !base::ContainsKey(window_state_map_, WmWindow::Get(params.target))) { + // Don't register the window if the window is invisible. Instead, + // wait until it becomes visible because the client may update the + // flag to control if the window should be added. + if (!params.target->IsVisible()) { + if (!base::ContainsValue(added_windows_, params.target)) { + added_windows_.insert(params.target); + params.target->AddObserver(this); + } + return; + } + MaximizeAndTrackWindow(WmWindow::Get(params.target)); + // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got + // already sent and we have to notify our state again. + if (base::ContainsKey(window_state_map_, WmWindow::Get(params.target))) { + wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); + wm::GetWindowState(params.target)->OnWMEvent(&event); + } + } +} + +void MaximizeModeWindowManager::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + // Stop managing |window| if the always-on-top property is added. + if (key == aura::client::kAlwaysOnTopKey && + window->GetProperty(aura::client::kAlwaysOnTopKey)) { + ForgetWindow(WmWindow::Get(window)); + } +} + +void MaximizeModeWindowManager::OnWindowBoundsChanged( + aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (!IsContainerWindow(window)) + return; + // Reposition all non maximizeable windows. + for (auto& pair : window_state_map_) + pair.second->UpdateWindowPosition(pair.first->GetWindowState()); +} + +void MaximizeModeWindowManager::OnWindowVisibilityChanged(aura::Window* window, + bool visible) { + // Skip if it's already managed. + if (base::ContainsKey(window_state_map_, WmWindow::Get(window))) + return; + + if (IsContainerWindow(window->parent()) && + base::ContainsValue(added_windows_, window) && visible) { + added_windows_.erase(window); + window->RemoveObserver(this); + MaximizeAndTrackWindow(WmWindow::Get(window)); + // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got + // already sent and we have to notify our state again. + if (base::ContainsKey(window_state_map_, WmWindow::Get(window))) { + wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); + wm::GetWindowState(window)->OnWMEvent(&event); + } + } +} + +void MaximizeModeWindowManager::OnDisplayAdded( + const display::Display& display) { + DisplayConfigurationChanged(); +} + +void MaximizeModeWindowManager::OnDisplayRemoved( + const display::Display& display) { + DisplayConfigurationChanged(); +} + +void MaximizeModeWindowManager::OnDisplayMetricsChanged(const display::Display&, + uint32_t) { + // Nothing to do here. +} + +MaximizeModeWindowManager::MaximizeModeWindowManager() + : backdrops_hidden_(false) { + // The overview mode needs to be ended before the maximize mode is started. To + // guarantee the proper order, it will be turned off from here. + CancelOverview(); + + MaximizeAllWindows(); + AddWindowCreationObservers(); + EnableBackdropBehindTopWindowOnEachDisplay(true); + display::Screen::GetScreen()->AddObserver(this); + WmShell::Get()->AddShellObserver(this); + event_handler_ = WmShell::Get()->CreateMaximizeModeEventHandler(); +} + +void MaximizeModeWindowManager::MaximizeAllWindows() { + MruWindowTracker::WindowList windows = + WmShell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal(); + // Add all existing Mru windows. + for (WmWindow* window : windows) + MaximizeAndTrackWindow(window); +} + +void MaximizeModeWindowManager::RestoreAllWindows() { + while (window_state_map_.size()) + ForgetWindow(window_state_map_.begin()->first); +} + +void MaximizeModeWindowManager::SetDeferBoundsUpdates( + bool defer_bounds_updates) { + for (auto& pair : window_state_map_) + pair.second->SetDeferBoundsUpdates(defer_bounds_updates); +} + +void MaximizeModeWindowManager::MaximizeAndTrackWindow(WmWindow* window) { + if (!ShouldHandleWindow(window)) + return; + + DCHECK(!base::ContainsKey(window_state_map_, window)); + window->aura_window()->AddObserver(this); + + // We create and remember a maximize mode state which will attach itself to + // the provided state object. + window_state_map_[window] = new MaximizeModeWindowState(window, this); +} + +void MaximizeModeWindowManager::ForgetWindow(WmWindow* window) { + WindowToState::iterator it = window_state_map_.find(window); + + // The following DCHECK could fail if our window state object was destroyed + // earlier by someone else. However - at this point there is no other client + // which replaces the state object and therefore this should not happen. + DCHECK(it != window_state_map_.end()); + window->aura_window()->RemoveObserver(this); + + // By telling the state object to revert, it will switch back the old + // State object and destroy itself, calling WindowStateDestroyed(). + it->second->LeaveMaximizeMode(it->first->GetWindowState()); + DCHECK(!base::ContainsKey(window_state_map_, window)); +} + +bool MaximizeModeWindowManager::ShouldHandleWindow(WmWindow* window) { + DCHECK(window); + + // Windows with the always-on-top property should be free-floating and thus + // not managed by us. + if (window->IsAlwaysOnTop()) + return false; + + // Windows in the dock should not be managed by us. + if (window->GetWindowState()->IsDocked()) + return false; + + // If the changing bounds in the maximized/fullscreen is allowed, then + // let the client manage it even in maximized mode. + if (window->GetWindowState()->allow_set_bounds_in_maximized()) + return false; + + return window->GetType() == ui::wm::WINDOW_TYPE_NORMAL; +} + +void MaximizeModeWindowManager::AddWindowCreationObservers() { + DCHECK(observed_container_windows_.empty()); + // Observe window activations/creations in the default containers on all root + // windows. + for (aura::Window* root : Shell::GetInstance()->GetAllRootWindows()) { + aura::Window* default_container = + root->GetChildById(kShellWindowId_DefaultContainer); + DCHECK(!base::ContainsKey(observed_container_windows_, default_container)); + default_container->AddObserver(this); + observed_container_windows_.insert(default_container); + } +} + +void MaximizeModeWindowManager::RemoveWindowCreationObservers() { + for (aura::Window* window : observed_container_windows_) + window->RemoveObserver(this); + observed_container_windows_.clear(); +} + +void MaximizeModeWindowManager::DisplayConfigurationChanged() { + EnableBackdropBehindTopWindowOnEachDisplay(false); + RemoveWindowCreationObservers(); + AddWindowCreationObservers(); + EnableBackdropBehindTopWindowOnEachDisplay(true); +} + +bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) { + return base::ContainsKey(observed_container_windows_, window); +} + +void MaximizeModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay( + bool enable) { + // This function should be a no-op if backdrops have been disabled. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshDisableMaximizeModeWindowBackdrop)) { + return; + } + + if (backdrops_hidden_) + return; + + // Inform the WorkspaceLayoutManager that we want to show a backdrop behind + // the topmost window of its container. + for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { + RootWindowController* controller = root->GetRootWindowController(); + WmWindow* default_container = + root->GetChildByShellWindowId(kShellWindowId_DefaultContainer); + controller->workspace_controller()->SetMaximizeBackdropDelegate( + enable ? base::MakeUnique<WorkspaceBackdropDelegate>(default_container) + : nullptr); + } +} + +} // namespace ash
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_manager.h b/ash/common/wm/maximize_mode/maximize_mode_window_manager.h new file mode 100644 index 0000000..4033c522 --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_window_manager.h
@@ -0,0 +1,141 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_MANAGER_H_ +#define ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <unordered_set> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/window_state.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" +#include "ui/display/display_observer.h" + +namespace ash { +class MaximizeModeController; +class MaximizeModeWindowState; + +namespace wm { +class MaximizeModeEventHandler; +} + +// A window manager which - when created - will force all windows into maximized +// mode. Exception are panels and windows which cannot be maximized. +// Windows which cannot be maximized / resized are centered with a layer placed +// behind the window so that no other windows are visible and/or obscured. +// With the destruction of the manager all windows will be restored to their +// original state. +class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, + public display::DisplayObserver, + public ShellObserver { + public: + // This should only be deleted by the creator (ash::Shell). + ~MaximizeModeWindowManager() override; + + // Returns the number of maximized & tracked windows by this manager. + int GetNumberOfManagedWindows(); + + // Adds a window which needs to be maximized. This is used by other window + // managers for windows which needs to get tracked due to (upcoming) state + // changes. + // The call gets ignored if the window was already or should not be handled. + void AddWindow(WmWindow* window); + + // Called from a window state object when it gets destroyed. + void WindowStateDestroyed(WmWindow* window); + + // ShellObserver overrides: + void OnOverviewModeStarting() override; + void OnOverviewModeEnded() override; + + // Overridden from WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override; + void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; + + // display::DisplayObserver overrides: + void OnDisplayAdded(const display::Display& display) override; + void OnDisplayRemoved(const display::Display& display) override; + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t metrics) override; + + protected: + friend class MaximizeModeController; + + // The object should only be created by the ash::Shell. + MaximizeModeWindowManager(); + + private: + using WindowToState = std::map<WmWindow*, MaximizeModeWindowState*>; + + // Maximize all windows and restore their current state. + void MaximizeAllWindows(); + + // Restore all windows to their previous state. + void RestoreAllWindows(); + + // Set whether to defer bounds updates on all tracked windows. When set to + // false bounds will be updated as they may be stale. + void SetDeferBoundsUpdates(bool defer_bounds_updates); + + // If the given window should be handled by us, this function will maximize it + // and add it to the list of known windows (remembering the initial show + // state). + // Note: If the given window cannot be handled by us the function will return + // immediately. + void MaximizeAndTrackWindow(WmWindow* window); + + // Remove a window from our tracking list. + void ForgetWindow(WmWindow* window); + + // Returns true when the given window should be modified in any way by us. + bool ShouldHandleWindow(WmWindow* window); + + // Add window creation observers to track creation of new windows. + void AddWindowCreationObservers(); + + // Remove Window creation observers. + void RemoveWindowCreationObservers(); + + // Change the internal state (e.g. observers) when the display configuration + // changes. + void DisplayConfigurationChanged(); + + // Returns true when the |window| is a container window. + bool IsContainerWindow(aura::Window* window); + + // Add a backdrop behind the currently active window on each desktop. + void EnableBackdropBehindTopWindowOnEachDisplay(bool enable); + + // Every window which got touched by our window manager gets added here. + WindowToState window_state_map_; + + // All container windows which have to be tracked. + std::unordered_set<aura::Window*> observed_container_windows_; + + // Windows added to the container, but not yet shown. + std::unordered_set<aura::Window*> added_windows_; + + // True if all backdrops are hidden. + bool backdrops_hidden_; + + std::unique_ptr<wm::MaximizeModeEventHandler> event_handler_; + + DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_MANAGER_H_
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_state.cc b/ash/common/wm/maximize_mode/maximize_mode_window_state.cc new file mode 100644 index 0000000..fc240bb7 --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_window_state.cc
@@ -0,0 +1,337 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/maximize_mode/maximize_mode_window_state.h" + +#include <utility> + +#include "ash/common/wm/maximize_mode/maximize_mode_window_manager.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/window_state_util.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { +namespace { + +// Returns the biggest possible size for a window which is about to be +// maximized. +gfx::Size GetMaximumSizeOfWindow(wm::WindowState* window_state) { + DCHECK(window_state->CanMaximize() || window_state->CanResize()); + + gfx::Size workspace_size = + wm::GetMaximizedWindowBoundsInParent(window_state->window()).size(); + + gfx::Size size = window_state->window()->GetMaximumSize(); + if (size.IsEmpty()) + return workspace_size; + + size.SetToMin(workspace_size); + return size; +} + +// Returns the centered bounds of the given bounds in the work area. +gfx::Rect GetCenteredBounds(const gfx::Rect& bounds_in_parent, + wm::WindowState* state_object) { + gfx::Rect work_area_in_parent = + wm::GetDisplayWorkAreaBoundsInParent(state_object->window()); + work_area_in_parent.ClampToCenteredSize(bounds_in_parent.size()); + return work_area_in_parent; +} + +// Returns the maximized/full screen and/or centered bounds of a window. +gfx::Rect GetBoundsInMaximizedMode(wm::WindowState* state_object) { + if (state_object->IsFullscreen() || state_object->IsPinned()) + return wm::GetDisplayBoundsInParent(state_object->window()); + + gfx::Rect bounds_in_parent; + // Make the window as big as possible. + if (state_object->CanMaximize() || state_object->CanResize()) { + bounds_in_parent.set_size(GetMaximumSizeOfWindow(state_object)); + } else { + // We prefer the user given window dimensions over the current windows + // dimensions since they are likely to be the result from some other state + // object logic. + if (state_object->HasRestoreBounds()) + bounds_in_parent = state_object->GetRestoreBoundsInParent(); + else + bounds_in_parent = state_object->window()->GetBounds(); + } + return GetCenteredBounds(bounds_in_parent, state_object); +} + +gfx::Rect GetRestoreBounds(wm::WindowState* window_state) { + if (window_state->IsMinimized() || window_state->IsMaximized() || + window_state->IsFullscreen()) { + gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); + if (!restore_bounds.IsEmpty()) + return restore_bounds; + } + gfx::Rect bounds = window_state->window()->GetBoundsInScreen(); + if (window_state->IsDocked()) { + gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); + // Use current window horizontal offset origin in order to preserve docked + // alignment but preserve restored size and vertical offset for the time + // when the window gets undocked. + if (!restore_bounds.IsEmpty()) { + bounds.set_size(restore_bounds.size()); + bounds.set_y(restore_bounds.y()); + } + } + return bounds; +} + +} // namespace + +// static +void MaximizeModeWindowState::UpdateWindowPosition( + wm::WindowState* window_state) { + gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); + if (bounds_in_parent == window_state->window()->GetBounds()) + return; + window_state->SetBoundsDirect(bounds_in_parent); +} + +MaximizeModeWindowState::MaximizeModeWindowState( + WmWindow* window, + MaximizeModeWindowManager* creator) + : window_(window), + creator_(creator), + current_state_type_(window->GetWindowState()->GetStateType()), + defer_bounds_updates_(false) { + old_state_.reset(window_->GetWindowState() + ->SetStateObject(std::unique_ptr<State>(this)) + .release()); +} + +MaximizeModeWindowState::~MaximizeModeWindowState() { + creator_->WindowStateDestroyed(window_); +} + +void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState* window_state) { + // Note: When we return we will destroy ourselves with the |our_reference|. + std::unique_ptr<wm::WindowState::State> our_reference = + window_state->SetStateObject(std::move(old_state_)); +} + +void MaximizeModeWindowState::SetDeferBoundsUpdates(bool defer_bounds_updates) { + if (defer_bounds_updates_ == defer_bounds_updates) + return; + + defer_bounds_updates_ = defer_bounds_updates; + if (!defer_bounds_updates_) + UpdateBounds(window_->GetWindowState(), true); +} + +void MaximizeModeWindowState::OnWMEvent(wm::WindowState* window_state, + const wm::WMEvent* event) { + switch (event->type()) { + case wm::WM_EVENT_TOGGLE_FULLSCREEN: + ToggleFullScreen(window_state, window_state->delegate()); + break; + case wm::WM_EVENT_FULLSCREEN: + UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN, true); + break; + case wm::WM_EVENT_PIN: + if (!WmShell::Get()->IsPinned()) + UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_PINNED, true); + break; + case wm::WM_EVENT_TRUSTED_PIN: + if (!WmShell::Get()->IsPinned()) + UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_TRUSTED_PINNED, true); + break; + case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: + case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: + case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: + case wm::WM_EVENT_TOGGLE_MAXIMIZE: + case wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT: + case wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: + case wm::WM_EVENT_CENTER: + case wm::WM_EVENT_SNAP_LEFT: + case wm::WM_EVENT_SNAP_RIGHT: + case wm::WM_EVENT_NORMAL: + case wm::WM_EVENT_MAXIMIZE: + case wm::WM_EVENT_DOCK: + UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state), + true); + return; + case wm::WM_EVENT_MINIMIZE: + UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED, true); + return; + case wm::WM_EVENT_SHOW_INACTIVE: + return; + case wm::WM_EVENT_SET_BOUNDS: + if (window_state->allow_set_bounds_in_maximized()) { + window_state->SetBoundsConstrained( + static_cast<const wm::SetBoundsEvent*>(event)->requested_bounds()); + } else if (current_state_type_ == wm::WINDOW_STATE_TYPE_MAXIMIZED) { + // Having a maximized window, it could have been created with an empty + // size and the caller should get his size upon leaving the maximized + // mode. As such we set the restore bounds to the requested bounds. + gfx::Rect bounds_in_parent = + (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); + if (!bounds_in_parent.IsEmpty()) + window_state->SetRestoreBoundsInParent(bounds_in_parent); + } else if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && + current_state_type_ != wm::WINDOW_STATE_TYPE_PINNED && + current_state_type_ != wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { + // In all other cases (except for minimized windows) we respect the + // requested bounds and center it to a fully visible area on the screen. + gfx::Rect bounds_in_parent = + (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); + bounds_in_parent = GetCenteredBounds(bounds_in_parent, window_state); + if (bounds_in_parent != window_state->window()->GetBounds()) { + if (window_state->window()->IsVisible()) + window_state->SetBoundsDirectAnimated(bounds_in_parent); + else + window_state->SetBoundsDirect(bounds_in_parent); + } + } + break; + case wm::WM_EVENT_ADDED_TO_WORKSPACE: + if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && + current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) { + wm::WindowStateType new_state = + GetMaximizedOrCenteredWindowType(window_state); + UpdateWindow(window_state, new_state, true); + } + break; + case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED: + if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) + UpdateBounds(window_state, true); + break; + case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED: + // Don't animate on a screen rotation - just snap to new size. + if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) + UpdateBounds(window_state, false); + break; + } +} + +wm::WindowStateType MaximizeModeWindowState::GetType() const { + return current_state_type_; +} + +void MaximizeModeWindowState::AttachState( + wm::WindowState* window_state, + wm::WindowState::State* previous_state) { + current_state_type_ = previous_state->GetType(); + + gfx::Rect restore_bounds = GetRestoreBounds(window_state); + if (!restore_bounds.IsEmpty()) { + // We do not want to do a session restore to our window states. Therefore + // we tell the window to use the current default states instead. + window_state->window()->SetRestoreOverrides(restore_bounds, + window_state->GetShowState()); + } + + // Initialize the state to a good preset. + if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && + current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && + current_state_type_ != wm::WINDOW_STATE_TYPE_PINNED && + current_state_type_ != wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { + UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state), + true); + } + + window_state->set_can_be_dragged(false); +} + +void MaximizeModeWindowState::DetachState(wm::WindowState* window_state) { + // From now on, we can use the default session restore mechanism again. + window_state->window()->SetRestoreOverrides(gfx::Rect(), + ui::SHOW_STATE_NORMAL); + window_state->set_can_be_dragged(true); +} + +void MaximizeModeWindowState::UpdateWindow(wm::WindowState* window_state, + wm::WindowStateType target_state, + bool animated) { + DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED || + target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED || + target_state == wm::WINDOW_STATE_TYPE_PINNED || + target_state == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED || + (target_state == wm::WINDOW_STATE_TYPE_NORMAL && + !window_state->CanMaximize()) || + target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN); + + if (current_state_type_ == target_state) { + if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) + return; + // If the state type did not change, update it accordingly. + UpdateBounds(window_state, animated); + return; + } + + const wm::WindowStateType old_state_type = current_state_type_; + current_state_type_ = target_state; + window_state->UpdateWindowShowStateFromStateType(); + window_state->NotifyPreStateTypeChange(old_state_type); + + if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) { + window_state->window()->SetVisibilityAnimationType( + wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); + window_state->window()->Hide(); + if (window_state->IsActive()) + window_state->Deactivate(); + } else { + UpdateBounds(window_state, animated); + } + + window_state->NotifyPostStateTypeChange(old_state_type); + + if (old_state_type == wm::WINDOW_STATE_TYPE_PINNED || + target_state == wm::WINDOW_STATE_TYPE_PINNED || + old_state_type == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED || + target_state == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { + WmShell::Get()->SetPinnedWindow(window_state->window()); + } + + if ((window_state->window()->GetTargetVisibility() || + old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) && + !window_state->window()->GetLayer()->visible()) { + // The layer may be hidden if the window was previously minimized. Make + // sure it's visible. + window_state->window()->Show(); + } +} + +wm::WindowStateType MaximizeModeWindowState::GetMaximizedOrCenteredWindowType( + wm::WindowState* window_state) { + return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED + : wm::WINDOW_STATE_TYPE_NORMAL; +} + +void MaximizeModeWindowState::UpdateBounds(wm::WindowState* window_state, + bool animated) { + if (defer_bounds_updates_) + return; + gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); + // If we have a target bounds rectangle, we center it and set it + // accordingly. + if (!bounds_in_parent.IsEmpty() && + bounds_in_parent != window_state->window()->GetBounds()) { + if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED || + !window_state->window()->IsVisible() || !animated) { + window_state->SetBoundsDirect(bounds_in_parent); + } else { + // If we animate (to) maximized mode, we want to use the cross fade to + // avoid flashing. + if (window_state->IsMaximized()) + window_state->SetBoundsDirectCrossFade(bounds_in_parent); + else + window_state->SetBoundsDirectAnimated(bounds_in_parent); + } + } +} + +} // namespace ash
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_state.h b/ash/common/wm/maximize_mode/maximize_mode_window_state.h new file mode 100644 index 0000000..62f5b86 --- /dev/null +++ b/ash/common/wm/maximize_mode/maximize_mode_window_state.h
@@ -0,0 +1,88 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_STATE_H_ +#define ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_STATE_H_ + +#include <memory> + +#include "ash/common/wm/window_state.h" +#include "base/macros.h" + +namespace ash { +class MaximizeModeWindowManager; +class WmWindow; + +// The MaximizeModeWindowState implementation which reduces all possible window +// states to minimized and maximized. If a window cannot be maximized it will be +// set to normal. If a window cannot fill the entire workspace it will be +// centered within the workspace. +class MaximizeModeWindowState : public wm::WindowState::State { + public: + // Called when the window position might need to be updated. + static void UpdateWindowPosition(wm::WindowState* window_state); + + // The |window|'s state object will be modified to use this new window mode + // state handler. Upon destruction it will restore the previous state handler + // and call |creator::WindowStateDestroyed()| to inform that the window mode + // was reverted to the old window manager. + MaximizeModeWindowState(WmWindow* window, MaximizeModeWindowManager* creator); + ~MaximizeModeWindowState() override; + + // Leaves the maximize mode by reverting to previous state object. + void LeaveMaximizeMode(wm::WindowState* window_state); + + // Sets whether to ignore bounds updates. If set to false, immediately does a + // bounds update as the current window bounds may no longer be correct. + void SetDeferBoundsUpdates(bool defer_bounds_updates); + + // WindowState::State overrides: + void OnWMEvent(wm::WindowState* window_state, + const wm::WMEvent* event) override; + + wm::WindowStateType GetType() const override; + void AttachState(wm::WindowState* window_state, + wm::WindowState::State* previous_state) override; + void DetachState(wm::WindowState* window_state) override; + + private: + // Updates the window to |new_state_type| and resulting bounds: + // Either full screen, maximized centered or minimized. If the state does not + // change, only the bounds will be changed. If |animate| is set, the bound + // change get animated. + void UpdateWindow(wm::WindowState* window_state, + wm::WindowStateType new_state_type, + bool animate); + + // Depending on the capabilities of the window we either return + // |WINDOW_STATE_TYPE_MAXIMIZED| or |WINDOW_STATE_TYPE_NORMAL|. + wm::WindowStateType GetMaximizedOrCenteredWindowType( + wm::WindowState* window_state); + + // Updates the bounds to the maximum possible bounds according to the current + // window state. If |animated| is set we animate the change. + void UpdateBounds(wm::WindowState* window_state, bool animated); + + // The original state object of the window. + std::unique_ptr<wm::WindowState::State> old_state_; + + // The state object for this object which owns this instance. + WmWindow* window_; + + // The creator which needs to be informed when this state goes away. + MaximizeModeWindowManager* creator_; + + // The current state type. Due to the nature of this state, this can only be + // WM_STATE_TYPE{NORMAL, MINIMIZED, MAXIMIZED}. + wm::WindowStateType current_state_type_; + + // If true, do not update bounds. + bool defer_bounds_updates_; + + DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowState); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_STATE_H_
diff --git a/ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h b/ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h new file mode 100644 index 0000000..cfad8ee --- /dev/null +++ b/ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h
@@ -0,0 +1,17 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_H_ +#define ASH_COMMON_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_H_ + +namespace ash { + +class ScopedDisableInternalMouseAndKeyboard { + public: + virtual ~ScopedDisableInternalMouseAndKeyboard() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_H_
diff --git a/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc b/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc new file mode 100644 index 0000000..51113c24 --- /dev/null +++ b/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc
@@ -0,0 +1,177 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/maximize_mode/workspace_backdrop_delegate.h" + +#include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/auto_reset.h" +#include "ui/aura/window_observer.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/views/background.h" +#include "ui/views/widget/widget.h" +#include "ui/wm/core/window_animations.h" +#include "ui/wm/core/window_util.h" + +namespace ash { +namespace { + +// The opacity of the backdrop. +const float kBackdropOpacity = 0.5f; + +} // namespace + +class WorkspaceBackdropDelegate::WindowObserverImpl + : public aura::WindowObserver { + public: + explicit WindowObserverImpl(WorkspaceBackdropDelegate* delegate) + : delegate_(delegate) {} + ~WindowObserverImpl() override {} + + private: + // aura::WindowObserver overrides: + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override { + // The container size has changed and the layer needs to be adapt to it. + delegate_->AdjustToContainerBounds(); + } + + WorkspaceBackdropDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(WindowObserverImpl); +}; + +WorkspaceBackdropDelegate::WorkspaceBackdropDelegate(WmWindow* container) + : container_observer_(new WindowObserverImpl(this)), + container_(container), + in_restacking_(false) { + background_ = new views::Widget; + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.bounds = container_->GetBoundsInScreen(); + params.layer_type = ui::LAYER_SOLID_COLOR; + params.name = "WorkspaceBackdropDelegate"; + // To disallow the MRU list from picking this window up it should not be + // activateable. + params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; + DCHECK_NE(kShellWindowId_Invalid, container_->GetShellWindowId()); + container_->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + background_, container_->GetShellWindowId(), ¶ms); + background_->Init(params); + background_window_ = WmWindow::Get(background_->GetNativeWindow()); + // Do not use the animation system. We don't want the bounds animation and + // opacity needs to get set to |kBackdropOpacity|. + background_window_->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); + background_window_->GetLayer()->SetColor(SK_ColorBLACK); + // Make sure that the layer covers visibly everything - including the shelf. + background_window_->GetLayer()->SetBounds(params.bounds); + DCHECK(background_window_->GetBounds() == params.bounds); + Show(); + RestackBackdrop(); + container_->aura_window()->AddObserver(container_observer_.get()); +} + +WorkspaceBackdropDelegate::~WorkspaceBackdropDelegate() { + container_->aura_window()->RemoveObserver(container_observer_.get()); + // TODO: animations won't work right with mus: http://crbug.com/548396. + ::wm::ScopedHidingAnimationSettings hiding_settings( + background_->GetNativeView()); + background_->Close(); + background_window_->GetLayer()->SetOpacity(0.0f); +} + +void WorkspaceBackdropDelegate::OnWindowAddedToLayout(WmWindow* child) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnWindowRemovedFromLayout(WmWindow* child) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnWindowStackingChanged(WmWindow* window) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnPostWindowStateTypeChange( + wm::WindowState* window_state, + wm::WindowStateType old_type) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnDisplayWorkAreaInsetsChanged() { + AdjustToContainerBounds(); +} + +void WorkspaceBackdropDelegate::RestackBackdrop() { + // Avoid recursive calls. + if (in_restacking_) + return; + + WmWindow* window = GetCurrentTopWindow(); + if (!window) { + // Hide backdrop since no suitable window was found. + background_->Hide(); + return; + } + if (window == background_window_ && background_->IsVisible()) + return; + if (window->GetRootWindow() != background_window_->GetRootWindow()) + return; + // We are changing the order of windows which will cause recursion. + base::AutoReset<bool> lock(&in_restacking_, true); + if (!background_->IsVisible()) + Show(); + // Since the backdrop needs to be immediately behind the window and the + // stacking functions only guarantee a "it's above or below", we need + // to re-arrange the two windows twice. + container_->StackChildAbove(background_window_, window); + container_->StackChildAbove(window, background_window_); +} + +WmWindow* WorkspaceBackdropDelegate::GetCurrentTopWindow() { + const WmWindow::Windows windows = container_->GetChildren(); + for (auto window_iter = windows.rbegin(); window_iter != windows.rend(); + ++window_iter) { + WmWindow* window = *window_iter; + if (window->GetTargetVisibility() && + window->GetType() == ui::wm::WINDOW_TYPE_NORMAL && + window->CanActivate()) + return window; + } + return nullptr; +} + +void WorkspaceBackdropDelegate::AdjustToContainerBounds() { + // Cover the entire container window. + gfx::Rect target_rect(gfx::Point(0, 0), container_->GetBounds().size()); + if (target_rect != background_window_->GetBounds()) { + // TODO: this won't work right with mus: http://crbug.com/548396. + // This needs to be instant. + ui::ScopedLayerAnimationSettings settings( + background_window_->GetLayer()->GetAnimator()); + settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(0)); + background_window_->SetBounds(target_rect); + if (!background_->IsVisible()) + background_window_->GetLayer()->SetOpacity(kBackdropOpacity); + } +} + +void WorkspaceBackdropDelegate::Show() { + background_window_->GetLayer()->SetOpacity(0.0f); + background_->Show(); + ui::ScopedLayerAnimationSettings settings( + background_window_->GetLayer()->GetAnimator()); + background_window_->GetLayer()->SetOpacity(kBackdropOpacity); +} + +} // namespace ash
diff --git a/ash/common/wm/maximize_mode/workspace_backdrop_delegate.h b/ash/common/wm/maximize_mode/workspace_backdrop_delegate.h new file mode 100644 index 0000000..4145c2cb --- /dev/null +++ b/ash/common/wm/maximize_mode/workspace_backdrop_delegate.h
@@ -0,0 +1,73 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ +#define ASH_COMMON_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h" +#include "base/macros.h" + +namespace views { +class Widget; +} + +namespace ash { + +class WmWindow; + +// A background which gets created for a container |window| and which gets +// stacked behind the topmost window (within that container) covering the +// entire container. +class ASH_EXPORT WorkspaceBackdropDelegate + : public WorkspaceLayoutManagerBackdropDelegate { + public: + explicit WorkspaceBackdropDelegate(WmWindow* container); + ~WorkspaceBackdropDelegate() override; + + // WorkspaceLayoutManagerBackdropDelegate overrides: + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override; + void OnWindowStackingChanged(WmWindow* window) override; + void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) override; + void OnDisplayWorkAreaInsetsChanged() override; + + private: + class WindowObserverImpl; + + // Restack the backdrop relatively to the other windows in the container. + void RestackBackdrop(); + + // Returns the current visible top level window in the container. + WmWindow* GetCurrentTopWindow(); + + // Position & size the background over the container window. + void AdjustToContainerBounds(); + + // Show the overlay. + void Show(); + + std::unique_ptr<WindowObserverImpl> container_observer_; + + // The background which covers the rest of the screen. + views::Widget* background_ = nullptr; + // WmWindow for |background_|. + WmWindow* background_window_ = nullptr; + + // The window which is being "maximized". + WmWindow* container_; + + // If true, the |RestackOrHideWindow| might recurse. + bool in_restacking_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceBackdropDelegate); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_
diff --git a/ash/common/wm/mru_window_tracker.cc b/ash/common/wm/mru_window_tracker.cc new file mode 100644 index 0000000..df687d8 --- /dev/null +++ b/ash/common/wm/mru_window_tracker.cc
@@ -0,0 +1,161 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/mru_window_tracker.h" + +#include <algorithm> + +#include "ash/common/wm/focus_rules.h" +#include "ash/common/wm/switchable_windows.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "base/bind.h" +#include "ui/aura/window.h" + +namespace ash { + +namespace { + +using CanActivateWindowPredicate = base::Callback<bool(WmWindow*)>; + +bool CallCanActivate(WmWindow* window) { + return window->CanActivate(); +} + +// Adds the windows that can be cycled through for the specified window id to +// |windows|. +void AddTrackedWindows(WmWindow* root, + int container_id, + MruWindowTracker::WindowList* windows) { + WmWindow* container = root->GetChildByShellWindowId(container_id); + const MruWindowTracker::WindowList children(container->GetChildren()); + windows->insert(windows->end(), children.begin(), children.end()); +} + +// Returns a list of windows ordered by their stacking order. +// If |mru_windows| is passed, these windows are moved to the front of the list. +// It uses the given |should_include_window_predicate| to determine whether to +// include a window in the returned list or not. +MruWindowTracker::WindowList BuildWindowListInternal( + const std::list<WmWindow*>* mru_windows, + const CanActivateWindowPredicate& should_include_window_predicate) { + MruWindowTracker::WindowList windows; + WmWindow* active_root = WmShell::Get()->GetRootWindowForNewWindows(); + for (WmWindow* window : WmShell::Get()->GetAllRootWindows()) { + if (window == active_root) + continue; + for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) + AddTrackedWindows(window, wm::kSwitchableWindowContainerIds[i], &windows); + } + + // Add windows in the active root windows last so that the topmost window + // in the active root window becomes the front of the list. + for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) + AddTrackedWindows(active_root, wm::kSwitchableWindowContainerIds[i], + &windows); + + // Removes unfocusable windows. + std::vector<WmWindow*>::iterator itr = windows.begin(); + while (itr != windows.end()) { + if (!should_include_window_predicate.Run(*itr)) + itr = windows.erase(itr); + else + ++itr; + } + + // Put the windows in the mru_windows list at the head, if it's available. + if (mru_windows) { + // Iterate through the list backwards, so that we can move each window to + // the front of the windows list as we find them. + for (auto ix = mru_windows->rbegin(); ix != mru_windows->rend(); ++ix) { + // Exclude windows in non-switchable containers and those which cannot + // be activated. + if (!wm::IsSwitchableContainer((*ix)->GetParent()) || + !should_include_window_predicate.Run(*ix)) { + continue; + } + + MruWindowTracker::WindowList::iterator window = + std::find(windows.begin(), windows.end(), *ix); + if (window != windows.end()) { + windows.erase(window); + windows.push_back(*ix); + } + } + } + + // Window cycling expects the topmost window at the front of the list. + std::reverse(windows.begin(), windows.end()); + + return windows; +} + +} // namespace + +////////////////////////////////////////////////////////////////////////////// +// MruWindowTracker, public: + +MruWindowTracker::MruWindowTracker() : ignore_window_activations_(false) { + WmShell::Get()->AddActivationObserver(this); +} + +MruWindowTracker::~MruWindowTracker() { + WmShell::Get()->RemoveActivationObserver(this); + for (WmWindow* window : mru_windows_) + window->aura_window()->RemoveObserver(this); +} + +MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList() const { + return BuildWindowListInternal(&mru_windows_, base::Bind(&CallCanActivate)); +} + +MruWindowTracker::WindowList MruWindowTracker::BuildWindowListIgnoreModal() + const { + return BuildWindowListInternal(nullptr, + base::Bind(&IsWindowConsideredActivatable)); +} + +void MruWindowTracker::SetIgnoreActivations(bool ignore) { + ignore_window_activations_ = ignore; + + // If no longer ignoring window activations, move currently active window + // to front. + if (!ignore) + SetActiveWindow(WmShell::Get()->GetActiveWindow()); +} + +////////////////////////////////////////////////////////////////////////////// +// MruWindowTracker, private: + +void MruWindowTracker::SetActiveWindow(WmWindow* active_window) { + if (!active_window) + return; + + std::list<WmWindow*>::iterator iter = + std::find(mru_windows_.begin(), mru_windows_.end(), active_window); + // Observe all newly tracked windows. + if (iter == mru_windows_.end()) + active_window->aura_window()->AddObserver(this); + else + mru_windows_.erase(iter); + mru_windows_.push_front(active_window); +} + +void MruWindowTracker::OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) { + if (!ignore_window_activations_) + SetActiveWindow(gained_active); +} + +void MruWindowTracker::OnWindowDestroyed(aura::Window* window) { + // It's possible for OnWindowActivated() to be called after + // OnWindowDestroying(). This means we need to override OnWindowDestroyed() + // else we may end up with a deleted window in |mru_windows_|. + mru_windows_.remove(WmWindow::Get(window)); + window->RemoveObserver(this); +} + +} // namespace ash
diff --git a/ash/common/wm/mru_window_tracker.h b/ash/common/wm/mru_window_tracker.h new file mode 100644 index 0000000..1c820e3 --- /dev/null +++ b/ash/common/wm/mru_window_tracker.h
@@ -0,0 +1,68 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_MRU_WINDOW_TRACKER_H_ +#define ASH_COMMON_WM_MRU_WINDOW_TRACKER_H_ + +#include <list> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/wm_activation_observer.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" + +namespace ash { + +class WmWindow; + +// Maintains a most recently used list of windows. This is used for window +// cycling using Alt+Tab and overview mode. +class ASH_EXPORT MruWindowTracker : public WmActivationObserver, + public aura::WindowObserver { + public: + using WindowList = std::vector<WmWindow*>; + + MruWindowTracker(); + ~MruWindowTracker() override; + + // Returns the set of windows which can be cycled through using the tracked + // list of most recently used windows. + WindowList BuildMruWindowList() const; + + // This does the same thing as the above, but ignores the system modal dialog + // state and hence the returned list could contain more windows if a system + // modal dialog window is present. + WindowList BuildWindowListIgnoreModal() const; + + // Starts or stops ignoring window activations. If no longer ignoring + // activations the currently active window is moved to the front of the + // MRU window list. Used by WindowCycleList to avoid adding all cycled + // windows to the front of the MRU window list. + void SetIgnoreActivations(bool ignore); + + private: + // Updates the mru_windows_ list to insert/move |active_window| at/to the + // front. + void SetActiveWindow(WmWindow* active_window); + + // Overridden from WmActivationObserver: + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override; + + // Overridden from aura::WindowObserver: + void OnWindowDestroyed(aura::Window* window) override; + + // List of windows that have been activated in containers that we cycle + // through, sorted by most recently used. + std::list<WmWindow*> mru_windows_; + + bool ignore_window_activations_; + + DISALLOW_COPY_AND_ASSIGN(MruWindowTracker); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_MRU_WINDOW_TRACKER_H_
diff --git a/ash/common/wm/mru_window_tracker_unittest.cc b/ash/common/wm/mru_window_tracker_unittest.cc new file mode 100644 index 0000000..cf92338fb --- /dev/null +++ b/ash/common/wm/mru_window_tracker_unittest.cc
@@ -0,0 +1,116 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/mru_window_tracker.h" + +#include "ash/common/test/ash_test.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ui/base/hit_test.h" + +namespace ash { + +class MruWindowTrackerTest : public AshTest { + public: + MruWindowTrackerTest() {} + ~MruWindowTrackerTest() override {} + + std::unique_ptr<WindowOwner> CreateTestWindow() { + return AshTest::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); + } + + MruWindowTracker* mru_window_tracker() { + return WmShell::Get()->mru_window_tracker(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MruWindowTrackerTest); +}; + +// Basic test that the activation order is tracked. +TEST_F(MruWindowTrackerTest, Basic) { + std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); + WmWindow* w1 = w1_owner->window(); + std::unique_ptr<WindowOwner> w2_owner(CreateTestWindow()); + WmWindow* w2 = w2_owner->window(); + std::unique_ptr<WindowOwner> w3_owner(CreateTestWindow()); + WmWindow* w3 = w3_owner->window(); + w3->Activate(); + w2->Activate(); + w1->Activate(); + + WmWindow::Windows window_list = mru_window_tracker()->BuildMruWindowList(); + ASSERT_EQ(3u, window_list.size()); + EXPECT_EQ(w1, window_list[0]); + EXPECT_EQ(w2, window_list[1]); + EXPECT_EQ(w3, window_list[2]); +} + +// Test that minimized windows are not treated specially. +TEST_F(MruWindowTrackerTest, MinimizedWindowsAreLru) { + // TODO(sky): fix me. Fails in mash because of http://crbug.com/654887. + if (WmShell::Get()->IsRunningInMash()) + return; + + std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); + WmWindow* w1 = w1_owner->window(); + std::unique_ptr<WindowOwner> w2_owner(CreateTestWindow()); + WmWindow* w2 = w2_owner->window(); + std::unique_ptr<WindowOwner> w3_owner(CreateTestWindow()); + WmWindow* w3 = w3_owner->window(); + std::unique_ptr<WindowOwner> w4_owner(CreateTestWindow()); + WmWindow* w4 = w4_owner->window(); + std::unique_ptr<WindowOwner> w5_owner(CreateTestWindow()); + WmWindow* w5 = w5_owner->window(); + std::unique_ptr<WindowOwner> w6_owner(CreateTestWindow()); + WmWindow* w6 = w6_owner->window(); + w6->Activate(); + w5->Activate(); + w4->Activate(); + w3->Activate(); + w2->Activate(); + w1->Activate(); + + w1->GetWindowState()->Minimize(); + w4->GetWindowState()->Minimize(); + w5->GetWindowState()->Minimize(); + + // By minimizing the first window, we activate w2 which will move it to the + // front of the MRU queue. + EXPECT_TRUE(w2->IsActive()); + + WmWindow::Windows window_list = mru_window_tracker()->BuildMruWindowList(); + EXPECT_EQ(w2, window_list[0]); + EXPECT_EQ(w1, window_list[1]); + EXPECT_EQ(w3, window_list[2]); + EXPECT_EQ(w4, window_list[3]); + EXPECT_EQ(w5, window_list[4]); + EXPECT_EQ(w6, window_list[5]); +} + +// Tests that windows being dragged are only in the WindowList once. +TEST_F(MruWindowTrackerTest, DraggedWindowsInListOnlyOnce) { + std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); + WmWindow* w1 = w1_owner->window(); + w1->Activate(); + + // Start dragging the window. + w1->GetWindowState()->CreateDragDetails( + gfx::Point(), HTRIGHT, aura::client::WINDOW_MOVE_SOURCE_TOUCH); + + // During a drag the window is reparented by the Docked container. + WmWindow* drag_container = w1->GetRootWindow()->GetChildByShellWindowId( + kShellWindowId_DockedContainer); + drag_container->AddChild(w1); + EXPECT_TRUE(w1->GetWindowState()->is_dragged()); + + // The dragged window should only be in the list once. + WmWindow::Windows window_list = + mru_window_tracker()->BuildWindowListIgnoreModal(); + EXPECT_EQ(1, std::count(window_list.begin(), window_list.end(), w1)); +} + +} // namespace ash
diff --git a/ash/common/wm/overview/cleanup_animation_observer.cc b/ash/common/wm/overview/cleanup_animation_observer.cc new file mode 100644 index 0000000..9feed4c --- /dev/null +++ b/ash/common/wm/overview/cleanup_animation_observer.cc
@@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/cleanup_animation_observer.h" + +#include "ui/views/widget/widget.h" + +namespace ash { + +CleanupAnimationObserver::CleanupAnimationObserver( + std::unique_ptr<views::Widget> widget) + : widget_(std::move(widget)), owner_(nullptr) { + DCHECK(widget_); +} + +CleanupAnimationObserver::~CleanupAnimationObserver() {} + +void CleanupAnimationObserver::OnImplicitAnimationsCompleted() { + // |widget_| may get reset if Shutdown() is called prior to this method. + if (!widget_) + return; + if (owner_) { + owner_->RemoveAndDestroyAnimationObserver(this); + return; + } + delete this; +} + +void CleanupAnimationObserver::SetOwner(WindowSelectorDelegate* owner) { + owner_ = owner; +} + +void CleanupAnimationObserver::Shutdown() { + widget_.reset(); + owner_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/wm/overview/cleanup_animation_observer.h b/ash/common/wm/overview/cleanup_animation_observer.h new file mode 100644 index 0000000..a3ad4ffd --- /dev/null +++ b/ash/common/wm/overview/cleanup_animation_observer.h
@@ -0,0 +1,48 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_ +#define ASH_COMMON_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/overview/window_selector_delegate.h" +#include "base/macros.h" +#include "ui/compositor/layer_animation_observer.h" + +namespace views { +class Widget; +} + +namespace ash { + +// An observer which holds onto the passed widget until the animation is +// complete. +class ASH_EXPORT CleanupAnimationObserver + : public ui::ImplicitAnimationObserver, + public DelayedAnimationObserver { + public: + explicit CleanupAnimationObserver(std::unique_ptr<views::Widget> widget); + ~CleanupAnimationObserver() override; + + // ui::ImplicitAnimationObserver: + // TODO(varkha): Look into all cases when animations are not started such as + // zero-duration animations and ensure that the object lifetime is handled. + void OnImplicitAnimationsCompleted() override; + + // DelayedAnimationObserver: + void SetOwner(WindowSelectorDelegate* owner) override; + void Shutdown() override; + + private: + std::unique_ptr<views::Widget> widget_; + WindowSelectorDelegate* owner_; + + DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserver); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_
diff --git a/ash/common/wm/overview/cleanup_animation_observer_unittest.cc b/ash/common/wm/overview/cleanup_animation_observer_unittest.cc new file mode 100644 index 0000000..a4db1ed --- /dev/null +++ b/ash/common/wm/overview/cleanup_animation_observer_unittest.cc
@@ -0,0 +1,185 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/cleanup_animation_observer.h" + +#include <vector> + +#include "ash/common/wm/overview/window_selector_delegate.h" +#include "ash/common/wm_window.h" +#include "ash/test/ash_test_base.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" + +namespace ash { +namespace { + +class TestWindowSelectorDelegate : public WindowSelectorDelegate { + public: + TestWindowSelectorDelegate() = default; + + ~TestWindowSelectorDelegate() override { + // Destroy widgets that may be still animating if shell shuts down soon + // after exiting overview mode. + for (std::unique_ptr<DelayedAnimationObserver>& observer : observers_) + observer->Shutdown(); + } + + // WindowSelectorDelegate: + void OnSelectionEnded() override {} + + void AddDelayedAnimationObserver( + std::unique_ptr<DelayedAnimationObserver> animation_observer) override { + animation_observer->SetOwner(this); + observers_.push_back(std::move(animation_observer)); + } + + void RemoveAndDestroyAnimationObserver( + DelayedAnimationObserver* animation_observer) override { + class IsEqual { + public: + explicit IsEqual(DelayedAnimationObserver* animation_observer) + : animation_observer_(animation_observer) {} + bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) { + return (other.get() == animation_observer_); + } + + private: + const DelayedAnimationObserver* animation_observer_; + }; + observers_.erase(std::remove_if(observers_.begin(), observers_.end(), + IsEqual(animation_observer)), + observers_.end()); + } + + private: + std::vector<std::unique_ptr<DelayedAnimationObserver>> observers_; + + DISALLOW_COPY_AND_ASSIGN(TestWindowSelectorDelegate); +}; + +class CleanupAnimationObserverTest : public test::AshTestBase, + public views::WidgetObserver { + public: + CleanupAnimationObserverTest() = default; + + ~CleanupAnimationObserverTest() override { + if (widget_) + widget_->RemoveObserver(this); + } + + // Creates a Widget containing a Window with the given |bounds|. This should + // be used when the test requires a Widget. For example any test that will + // cause a window to be closed via + // views::Widget::GetWidgetForNativeView(window)->Close(). + std::unique_ptr<views::Widget> CreateWindowWidget(const gfx::Rect& bounds) { + std::unique_ptr<views::Widget> widget(new views::Widget); + views::Widget::InitParams params; + params.bounds = bounds; + params.type = views::Widget::InitParams::TYPE_WINDOW; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + widget->Init(params); + widget->Show(); + ParentWindowInPrimaryRootWindow(widget->GetNativeWindow()); + widget->AddObserver(this); + widget_ = widget.get(); + return widget; + } + + protected: + bool widget_destroyed() { return !widget_; } + + private: + void OnWidgetDestroyed(views::Widget* widget) override { + if (widget_ == widget) + widget_ = nullptr; + } + + views::Widget* widget_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserverTest); +}; + +} // namespace + +// Tests that basic create-destroy sequence does not crash. +TEST_F(CleanupAnimationObserverTest, CreateDestroy) { + TestWindowSelectorDelegate delegate; + std::unique_ptr<views::Widget> widget( + CreateWindowWidget(gfx::Rect(0, 0, 40, 40))); + std::unique_ptr<CleanupAnimationObserver> observer( + new CleanupAnimationObserver(std::move(widget))); + delegate.AddDelayedAnimationObserver(std::move(observer)); +} + +// Tests that completing animation deletes the animation observer and the +// test widget and that deleting the WindowSelectorDelegate instance which +// owns the observer does not crash. +TEST_F(CleanupAnimationObserverTest, CreateAnimateComplete) { + TestWindowSelectorDelegate delegate; + std::unique_ptr<views::Widget> widget( + CreateWindowWidget(gfx::Rect(0, 0, 40, 40))); + WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); + { + ui::ScopedLayerAnimationSettings animation_settings( + widget_window->GetLayer()->GetAnimator()); + animation_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(1000)); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + + std::unique_ptr<CleanupAnimationObserver> observer( + new CleanupAnimationObserver(std::move(widget))); + animation_settings.AddObserver(observer.get()); + delegate.AddDelayedAnimationObserver(std::move(observer)); + + widget_window->SetBounds(gfx::Rect(50, 50, 60, 60)); + } + // The widget should be destroyed when |animation_settings| gets out of scope + // which in absence of NON_ZERO_DURATION animation duration mode completes + // the animation and calls OnImplicitAnimationsCompleted() on the cleanup + // observer and auto-deletes the owned widget. + EXPECT_TRUE(widget_destroyed()); + // TestWindowSelectorDelegate going out of scope should not crash. +} + +// Tests that starting an animation and exiting doesn't crash. If not for +// TestWindowSelectorDelegate calling Shutdown() on a CleanupAnimationObserver +// instance in destructor, this test would have crashed. +TEST_F(CleanupAnimationObserverTest, CreateAnimateShutdown) { + TestWindowSelectorDelegate delegate; + std::unique_ptr<views::Widget> widget( + CreateWindowWidget(gfx::Rect(0, 0, 40, 40))); + WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); + { + // Normal animations for tests have ZERO_DURATION, make sure we are actually + // animating the movement. + ui::ScopedAnimationDurationScaleMode animation_scale_mode( + ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + ui::ScopedLayerAnimationSettings animation_settings( + widget_window->GetLayer()->GetAnimator()); + animation_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(1000)); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + + std::unique_ptr<CleanupAnimationObserver> observer( + new CleanupAnimationObserver(std::move(widget))); + animation_settings.AddObserver(observer.get()); + delegate.AddDelayedAnimationObserver(std::move(observer)); + + widget_window->SetBounds(gfx::Rect(50, 50, 60, 60)); + } + // The widget still exists. + EXPECT_FALSE(widget_destroyed()); + // The test widget is auto-deleted when |delegate| that owns it goes out of + // scope. The animation is still active when this happens which should not + // crash. +} + +} // namespace ash
diff --git a/ash/common/wm/overview/overview_animation_type.h b/ash/common/wm/overview/overview_animation_type.h new file mode 100644 index 0000000..4f8f03f31 --- /dev/null +++ b/ash/common/wm/overview/overview_animation_type.h
@@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_OVERVIEW_ANIMATION_TYPE_H_ +#define ASH_COMMON_WM_OVERVIEW_OVERVIEW_ANIMATION_TYPE_H_ + +namespace ash { + +// Enumeration of the different overview mode animations. +enum OverviewAnimationType { + // TODO(bruthig): Remove OVERVIEW_ANIMATION_NONE value and replace it with + // correct animation type actions. + OVERVIEW_ANIMATION_NONE, + // Used to fade in the close button and label. + OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, + // Used to fade out the label. + OVERVIEW_ANIMATION_EXIT_OVERVIEW_MODE_FADE_OUT, + // Used to position windows when entering/exiting overview mode and when a + // window is closed while overview mode is active. + OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS, + // Used to restore windows to their original position when exiting overview + // mode. + OVERVIEW_ANIMATION_RESTORE_WINDOW, + // Used to animate scaling down of a window that is about to get closed while + // overview mode is active. + OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM, + // Used to animate hiding of a window that is closed while overview mode is + // active. + OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_OVERVIEW_ANIMATION_TYPE_H_
diff --git a/ash/common/wm/overview/scoped_overview_animation_settings.h b/ash/common/wm/overview/scoped_overview_animation_settings.h new file mode 100644 index 0000000..a5176ed --- /dev/null +++ b/ash/common/wm/overview/scoped_overview_animation_settings.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_H_ +#define ASH_COMMON_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_H_ + +namespace ui { +class ImplicitAnimationObserver; +} // namespace ui + +namespace ash { + +// ScopedOverviewAnimationSettings correctly configures the animation +// settings for a WmWindow given an OverviewAnimationType. +class ScopedOverviewAnimationSettings { + public: + virtual ~ScopedOverviewAnimationSettings() {} + virtual void AddObserver(ui::ImplicitAnimationObserver* observer) = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_H_
diff --git a/ash/common/wm/overview/scoped_overview_animation_settings_factory.cc b/ash/common/wm/overview/scoped_overview_animation_settings_factory.cc new file mode 100644 index 0000000..ebe5f528 --- /dev/null +++ b/ash/common/wm/overview/scoped_overview_animation_settings_factory.cc
@@ -0,0 +1,33 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h" + +#include "base/logging.h" + +namespace ash { + +// static +ScopedOverviewAnimationSettingsFactory* + ScopedOverviewAnimationSettingsFactory::instance_ = nullptr; + +// static +ScopedOverviewAnimationSettingsFactory* +ScopedOverviewAnimationSettingsFactory::Get() { + return instance_; +} + +ScopedOverviewAnimationSettingsFactory:: + ScopedOverviewAnimationSettingsFactory() { + DCHECK(!instance_); + instance_ = this; +} + +ScopedOverviewAnimationSettingsFactory:: + ~ScopedOverviewAnimationSettingsFactory() { + DCHECK_EQ(instance_, this); + instance_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/wm/overview/scoped_overview_animation_settings_factory.h b/ash/common/wm/overview/scoped_overview_animation_settings_factory.h new file mode 100644 index 0000000..e0340e1 --- /dev/null +++ b/ash/common/wm/overview/scoped_overview_animation_settings_factory.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_FACTORY_H_ +#define ASH_COMMON_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_FACTORY_H_ + +#include <memory> + +#include "ash/common/wm/overview/overview_animation_type.h" + +namespace ash { + +class ScopedOverviewAnimationSettings; +class WmWindow; + +// Factory for creating ScopedOverviewAnimationSettings. +class ScopedOverviewAnimationSettingsFactory { + public: + static ScopedOverviewAnimationSettingsFactory* Get(); + + virtual std::unique_ptr<ScopedOverviewAnimationSettings> + CreateOverviewAnimationSettings(OverviewAnimationType animation_type, + WmWindow* window) = 0; + + protected: + ScopedOverviewAnimationSettingsFactory(); + virtual ~ScopedOverviewAnimationSettingsFactory(); + + private: + static ScopedOverviewAnimationSettingsFactory* instance_; +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_FACTORY_H_
diff --git a/ash/common/wm/overview/scoped_transform_overview_window.cc b/ash/common/wm/overview/scoped_transform_overview_window.cc new file mode 100644 index 0000000..db63b3d --- /dev/null +++ b/ash/common/wm/overview/scoped_transform_overview_window.cc
@@ -0,0 +1,507 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/scoped_transform_overview_window.h" + +#include <algorithm> +#include <vector> + +#include "ash/common/wm/overview/scoped_overview_animation_settings.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h" +#include "ash/common/wm/overview/window_selector_item.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/compositor/layer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" +#include "ui/gfx/transform_util.h" +#include "ui/views/widget/widget.h" + +using WmWindows = std::vector<ash::WmWindow*>; + +namespace ash { + +namespace { + +// When set to true by tests makes closing the widget synchronous. +bool immediate_close_for_tests = false; + +// Delay closing window to allow it to shrink and fade out. +const int kCloseWindowDelayInMilliseconds = 150; + +WmWindow* GetTransientRoot(WmWindow* window) { + while (window && window->GetTransientParent()) + window = window->GetTransientParent(); + return window; +} + +std::unique_ptr<ScopedOverviewAnimationSettings> +CreateScopedOverviewAnimationSettings(OverviewAnimationType animation_type, + WmWindow* window) { + return ScopedOverviewAnimationSettingsFactory::Get() + ->CreateOverviewAnimationSettings(animation_type, window); +} + +// An iterator class that traverses a WmWindow and all of its transient +// descendants. +class TransientDescendantIterator { + public: + // Creates an empty iterator. + TransientDescendantIterator(); + + // Copy constructor required for iterator purposes. + TransientDescendantIterator(const TransientDescendantIterator& other) = + default; + + // Iterates over |root_window| and all of its transient descendants. + // Note |root_window| must not have a transient parent. + explicit TransientDescendantIterator(WmWindow* root_window); + + // Prefix increment operator. This assumes there are more items (i.e. + // *this != TransientDescendantIterator()). + const TransientDescendantIterator& operator++(); + + // Comparison for STL-based loops. + bool operator!=(const TransientDescendantIterator& other) const; + + // Dereference operator for STL-compatible iterators. + WmWindow* operator*() const; + + private: + // Explicit assignment operator defined because an explicit copy constructor + // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used. + TransientDescendantIterator& operator=( + const TransientDescendantIterator& other) = default; + + // The current window that |this| refers to. A null |current_window_| denotes + // an empty iterator and is used as the last possible value in the traversal. + WmWindow* current_window_; +}; + +// Provides a virtual container implementing begin() and end() for a sequence of +// TransientDescendantIterators. This can be used in range-based for loops. +class TransientDescendantIteratorRange { + public: + explicit TransientDescendantIteratorRange( + const TransientDescendantIterator& begin); + + // Copy constructor required for iterator purposes. + TransientDescendantIteratorRange( + const TransientDescendantIteratorRange& other) = default; + + const TransientDescendantIterator& begin() const { return begin_; } + const TransientDescendantIterator& end() const { return end_; } + + private: + // Explicit assignment operator defined because an explicit copy constructor + // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used. + TransientDescendantIteratorRange& operator=( + const TransientDescendantIteratorRange& other) = default; + + TransientDescendantIterator begin_; + TransientDescendantIterator end_; +}; + +TransientDescendantIterator::TransientDescendantIterator() + : current_window_(nullptr) {} + +TransientDescendantIterator::TransientDescendantIterator(WmWindow* root_window) + : current_window_(root_window) { + DCHECK(!root_window->GetTransientParent()); +} + +// Performs a pre-order traversal of the transient descendants. +const TransientDescendantIterator& TransientDescendantIterator::operator++() { + DCHECK(current_window_); + + const WmWindows transient_children = current_window_->GetTransientChildren(); + + if (!transient_children.empty()) { + current_window_ = transient_children.front(); + } else { + while (current_window_) { + WmWindow* parent = current_window_->GetTransientParent(); + if (!parent) { + current_window_ = nullptr; + break; + } + const WmWindows transient_siblings = parent->GetTransientChildren(); + auto iter = std::find(transient_siblings.begin(), + transient_siblings.end(), current_window_); + ++iter; + if (iter != transient_siblings.end()) { + current_window_ = *iter; + break; + } + current_window_ = current_window_->GetTransientParent(); + } + } + return *this; +} + +bool TransientDescendantIterator::operator!=( + const TransientDescendantIterator& other) const { + return current_window_ != other.current_window_; +} + +WmWindow* TransientDescendantIterator::operator*() const { + return current_window_; +} + +TransientDescendantIteratorRange::TransientDescendantIteratorRange( + const TransientDescendantIterator& begin) + : begin_(begin) {} + +TransientDescendantIteratorRange GetTransientTreeIterator(WmWindow* window) { + return TransientDescendantIteratorRange( + TransientDescendantIterator(GetTransientRoot(window))); +} + +} // namespace + +ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(WmWindow* window) + : window_(window), + determined_original_window_shape_(false), + ignored_by_shelf_(window->GetWindowState()->ignored_by_shelf()), + overview_started_(false), + original_transform_(window->GetTargetTransform()), + original_opacity_(window->GetTargetOpacity()), + weak_ptr_factory_(this) {} + +ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {} + +void ScopedTransformOverviewWindow::RestoreWindow() { + ShowHeader(); + if (minimized_widget_) { + // TODO(oshima): Use unminimize animation instead of hiding animation. + minimized_widget_->CloseNow(); + minimized_widget_.reset(); + return; + } + ScopedAnimationSettings animation_settings_list; + BeginScopedAnimation(OverviewAnimationType::OVERVIEW_ANIMATION_RESTORE_WINDOW, + &animation_settings_list); + SetTransform(window()->GetRootWindow(), original_transform_); + std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings = + CreateScopedOverviewAnimationSettings( + OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS, + window_); + window_->GetWindowState()->set_ignored_by_shelf(ignored_by_shelf_); + SetOpacity(original_opacity_); +} + +void ScopedTransformOverviewWindow::BeginScopedAnimation( + OverviewAnimationType animation_type, + ScopedAnimationSettings* animation_settings) { + for (auto* window : GetTransientTreeIterator(GetOverviewWindow())) { + animation_settings->push_back( + CreateScopedOverviewAnimationSettings(animation_type, window)); + } +} + +bool ScopedTransformOverviewWindow::Contains(const WmWindow* target) const { + for (auto* window : GetTransientTreeIterator(window_)) { + if (window->Contains(target)) + return true; + } + WmWindow* mirror = GetOverviewWindowForMinimizedState(); + return mirror && mirror->Contains(target); +} + +gfx::Rect ScopedTransformOverviewWindow::GetTargetBoundsInScreen() const { + gfx::Rect bounds; + WmWindow* overview_window = GetOverviewWindow(); + for (auto* window : GetTransientTreeIterator(overview_window)) { + // Ignore other window types when computing bounding box of window + // selector target item. + if (window != overview_window && + window->GetType() != ui::wm::WINDOW_TYPE_NORMAL && + window->GetType() != ui::wm::WINDOW_TYPE_PANEL) { + continue; + } + bounds.Union( + window->GetParent()->ConvertRectToScreen(window->GetTargetBounds())); + } + return bounds; +} + +gfx::Rect ScopedTransformOverviewWindow::GetTransformedBounds() const { + const int top_inset = GetTopInset(); + gfx::Rect bounds; + WmWindow* overview_window = GetOverviewWindow(); + for (auto* window : GetTransientTreeIterator(overview_window)) { + // Ignore other window types when computing bounding box of window + // selector target item. + if (window != overview_window && + (window->GetType() != ui::wm::WINDOW_TYPE_NORMAL && + window->GetType() != ui::wm::WINDOW_TYPE_PANEL)) { + continue; + } + gfx::RectF window_bounds(window->GetTargetBounds()); + gfx::Transform new_transform = + TransformAboutPivot(gfx::Point(window_bounds.x(), window_bounds.y()), + window->GetTargetTransform()); + new_transform.TransformRect(&window_bounds); + + // The preview title is shown above the preview window. Hide the window + // header for apps or browser windows with no tabs (web apps) to avoid + // showing both the window header and the preview title. + if (top_inset > 0) { + gfx::RectF header_bounds(window_bounds); + header_bounds.set_height(top_inset); + new_transform.TransformRect(&header_bounds); + window_bounds.Inset(0, gfx::ToCeiledInt(header_bounds.height()), 0, 0); + } + bounds.Union(window->GetParent()->ConvertRectToScreen( + ToEnclosingRect(window_bounds))); + } + return bounds; +} + +SkColor ScopedTransformOverviewWindow::GetTopColor() const { + for (auto* window : GetTransientTreeIterator(window_)) { + // If there are regular windows in the transient ancestor tree, all those + // windows are shown in the same overview item and the header is not masked. + if (window != window_ && (window->GetType() == ui::wm::WINDOW_TYPE_NORMAL || + window->GetType() == ui::wm::WINDOW_TYPE_PANEL)) { + return SK_ColorTRANSPARENT; + } + } + return window_->aura_window()->GetProperty(aura::client::kTopViewColor); +} + +int ScopedTransformOverviewWindow::GetTopInset() const { + // Mirror window doesn't have insets. + if (minimized_widget_) + return 0; + for (auto* window : GetTransientTreeIterator(window_)) { + // If there are regular windows in the transient ancestor tree, all those + // windows are shown in the same overview item and the header is not masked. + if (window != window_ && (window->GetType() == ui::wm::WINDOW_TYPE_NORMAL || + window->GetType() == ui::wm::WINDOW_TYPE_PANEL)) { + return 0; + } + } + return window_->aura_window()->GetProperty(aura::client::kTopViewInset); +} + +void ScopedTransformOverviewWindow::OnWindowDestroyed() { + window_ = nullptr; +} + +float ScopedTransformOverviewWindow::GetItemScale(const gfx::Size& source, + const gfx::Size& target, + int top_view_inset, + int title_height) { + return std::min(2.0f, static_cast<float>((target.height() - title_height)) / + (source.height() - top_view_inset)); +} + +gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio( + const gfx::Rect& rect, + const gfx::Rect& bounds, + int top_view_inset, + int title_height) { + DCHECK(!rect.IsEmpty()); + DCHECK_LE(top_view_inset, rect.height()); + const float scale = + GetItemScale(rect.size(), bounds.size(), top_view_inset, title_height); + const int horizontal_offset = gfx::ToFlooredInt( + 0.5 * (bounds.width() - gfx::ToFlooredInt(scale * rect.width()))); + const int width = bounds.width() - 2 * horizontal_offset; + const int vertical_offset = + title_height - gfx::ToCeiledInt(scale * top_view_inset); + const int height = std::min(gfx::ToCeiledInt(scale * rect.height()), + bounds.height() - vertical_offset); + return gfx::Rect(bounds.x() + horizontal_offset, bounds.y() + vertical_offset, + width, height); +} + +gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect( + const gfx::Rect& src_rect, + const gfx::Rect& dst_rect) { + DCHECK(!src_rect.IsEmpty()); + gfx::Transform transform; + transform.Translate(dst_rect.x() - src_rect.x(), dst_rect.y() - src_rect.y()); + transform.Scale(static_cast<float>(dst_rect.width()) / src_rect.width(), + static_cast<float>(dst_rect.height()) / src_rect.height()); + return transform; +} + +void ScopedTransformOverviewWindow::SetTransform( + WmWindow* root_window, + const gfx::Transform& transform) { + DCHECK(overview_started_); + + if (&transform != &original_transform_ && + !determined_original_window_shape_) { + determined_original_window_shape_ = true; + SkRegion* window_shape = window()->GetLayer()->alpha_shape(); + if (!original_window_shape_ && window_shape) + original_window_shape_.reset(new SkRegion(*window_shape)); + } + + gfx::Point target_origin(GetTargetBoundsInScreen().origin()); + for (auto* window : GetTransientTreeIterator(GetOverviewWindow())) { + WmWindow* parent_window = window->GetParent(); + gfx::Point original_origin = + parent_window->ConvertRectToScreen(window->GetTargetBounds()).origin(); + gfx::Transform new_transform = + TransformAboutPivot(gfx::Point(target_origin.x() - original_origin.x(), + target_origin.y() - original_origin.y()), + transform); + window->SetTransform(new_transform); + } +} + +void ScopedTransformOverviewWindow::SetOpacity(float opacity) { + for (auto* window : GetTransientTreeIterator(GetOverviewWindow())) { + window->SetOpacity(opacity); + } +} + +void ScopedTransformOverviewWindow::HideHeader() { + // Mirrored Window does not have a header. + if (minimized_widget_) + return; + gfx::Rect bounds(GetTargetBoundsInScreen().size()); + const int inset = GetTopInset(); + if (inset > 0) { + // Use alpha shape to hide the window header. + bounds.Inset(0, inset, 0, 0); + std::unique_ptr<SkRegion> region(new SkRegion); + region->setRect(RectToSkIRect(bounds)); + if (original_window_shape_) + region->op(*original_window_shape_, SkRegion::kIntersect_Op); + WmWindow* window = GetOverviewWindow(); + window->GetLayer()->SetAlphaShape(std::move(region)); + window->SetMasksToBounds(true); + } +} + +void ScopedTransformOverviewWindow::ShowHeader() { + ui::Layer* layer = window()->GetLayer(); + if (original_window_shape_) { + layer->SetAlphaShape( + base::MakeUnique<SkRegion>(*original_window_shape_.get())); + } else { + layer->SetAlphaShape(nullptr); + } + window()->SetMasksToBounds(false); +} + +void ScopedTransformOverviewWindow::UpdateMirrorWindowForMinimizedState() { + // TODO(oshima): Disable animation. + if (window_->GetShowState() == ui::SHOW_STATE_MINIMIZED) { + if (!minimized_widget_) + CreateMirrorWindowForMinimizedState(); + } else { + minimized_widget_->CloseNow(); + minimized_widget_.reset(); + } +} + +void ScopedTransformOverviewWindow::Close() { + if (immediate_close_for_tests) { + CloseWidget(); + return; + } + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, base::Bind(&ScopedTransformOverviewWindow::CloseWidget, + weak_ptr_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCloseWindowDelayInMilliseconds)); +} + +void ScopedTransformOverviewWindow::PrepareForOverview() { + DCHECK(!overview_started_); + overview_started_ = true; + window_->GetWindowState()->set_ignored_by_shelf(true); + if (window_->GetShowState() == ui::SHOW_STATE_MINIMIZED) + CreateMirrorWindowForMinimizedState(); +} + +void ScopedTransformOverviewWindow::CloseWidget() { + WmWindow* parent_window = GetTransientRoot(window_); + if (parent_window) + parent_window->CloseWidget(); +} + +// static +void ScopedTransformOverviewWindow::SetImmediateCloseForTests() { + immediate_close_for_tests = true; +} + +WmWindow* ScopedTransformOverviewWindow::GetOverviewWindow() const { + if (minimized_widget_) + return GetOverviewWindowForMinimizedState(); + return window_; +} + +void ScopedTransformOverviewWindow::EnsureVisible() { + original_opacity_ = 1.f; +} + +void ScopedTransformOverviewWindow::OnGestureEvent(ui::GestureEvent* event) { + if (event->type() == ui::ET_GESTURE_TAP) { + EnsureVisible(); + window_->Show(); + window_->Activate(); + } +} + +void ScopedTransformOverviewWindow::OnMouseEvent(ui::MouseEvent* event) { + if (event->type() == ui::ET_MOUSE_PRESSED && event->IsOnlyLeftMouseButton()) { + EnsureVisible(); + window_->Show(); + window_->Activate(); + } +} + +WmWindow* ScopedTransformOverviewWindow::GetOverviewWindowForMinimizedState() + const { + return minimized_widget_ ? WmWindow::Get(minimized_widget_->GetNativeWindow()) + : nullptr; +} + +void ScopedTransformOverviewWindow::CreateMirrorWindowForMinimizedState() { + DCHECK(!minimized_widget_.get()); + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.visible_on_all_workspaces = true; + params.name = "OverviewModeMinimized"; + params.activatable = views::Widget::InitParams::Activatable::ACTIVATABLE_NO; + params.accept_events = true; + minimized_widget_.reset(new views::Widget); + window_->GetRootWindow() + ->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + minimized_widget_.get(), window_->GetParent()->GetShellWindowId(), + ¶ms); + minimized_widget_->set_focus_on_creation(false); + minimized_widget_->Init(params); + + views::View* mirror_view = window_->CreateViewWithRecreatedLayers().release(); + mirror_view->SetVisible(true); + mirror_view->SetTargetHandler(this); + minimized_widget_->SetContentsView(mirror_view); + gfx::Rect bounds(window_->GetBoundsInScreen()); + gfx::Size preferred = mirror_view->GetPreferredSize(); + // In unit tests, the content view can have empty size. + if (!preferred.IsEmpty()) { + int inset = bounds.height() - preferred.height(); + bounds.Inset(0, 0, 0, inset); + } + minimized_widget_->SetBounds(bounds); + minimized_widget_->Show(); +} + +} // namespace ash
diff --git a/ash/common/wm/overview/scoped_transform_overview_window.h b/ash/common/wm/overview/scoped_transform_overview_window.h new file mode 100644 index 0000000..c197e64 --- /dev/null +++ b/ash/common/wm/overview/scoped_transform_overview_window.h
@@ -0,0 +1,198 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ +#define ASH_COMMON_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/wm/overview/overview_animation_type.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "third_party/skia/include/core/SkColor.h" +#include "ui/events/event_handler.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/transform.h" + +class SkRegion; + +namespace gfx { +class Rect; +} + +namespace views { +class Widget; +} + +namespace ash { + +class ScopedOverviewAnimationSettings; +class WmWindow; + +// Manages a window, and it's transient children, in the overview mode. This +// class allows transforming the windows with a helper to determine the best +// fit in certain bounds. The window's state is restored on destruction of this +// object. +class ASH_EXPORT ScopedTransformOverviewWindow : public ui::EventHandler { + public: + class OverviewContentMask; + using ScopedAnimationSettings = + std::vector<std::unique_ptr<ScopedOverviewAnimationSettings>>; + + // Calculates and returns an optimal scale ratio. With MD this is only + // taking into account |size.height()| as the width can vary. Without MD this + // returns the scale that allows the item to fully fit within |size|. + static float GetItemScale(const gfx::Size& source, + const gfx::Size& target, + int top_view_inset, + int title_height); + + // Returns |rect| having been shrunk to fit within |bounds| (preserving the + // aspect ratio). Takes into account a window header that is |top_view_inset| + // tall in the original window getting replaced by a window caption that is + // |title_height| tall in transformed window. + static gfx::Rect ShrinkRectToFitPreservingAspectRatio(const gfx::Rect& rect, + const gfx::Rect& bounds, + int top_view_inset, + int title_height); + + // Returns the transform turning |src_rect| into |dst_rect|. + static gfx::Transform GetTransformForRect(const gfx::Rect& src_rect, + const gfx::Rect& dst_rect); + + explicit ScopedTransformOverviewWindow(WmWindow* window); + ~ScopedTransformOverviewWindow() override; + + // Starts an animation sequence which will use animation settings specified by + // |animation_type|. The |animation_settings| container is populated with + // scoped entities and the container should be destroyed at the end of the + // animation sequence. + // + // Example: + // ScopedTransformOverviewWindow overview_window(window); + // ScopedTransformOverviewWindow::ScopedAnimationSettings scoped_settings; + // overview_window.BeginScopedAnimation( + // OverviewAnimationType::OVERVIEW_ANIMATION_SELECTOR_ITEM_SCROLL_CANCEL, + // &animation_settings); + // // Calls to SetTransform & SetOpacity will use the same animation settings + // // until scoped_settings is destroyed. + // overview_window.SetTransform(root_window, new_transform); + // overview_window.SetOpacity(1); + void BeginScopedAnimation(OverviewAnimationType animation_type, + ScopedAnimationSettings* animation_settings); + + // Returns true if this window selector window contains the |target|. + bool Contains(const WmWindow* target) const; + + // Returns the original target bounds of all transformed windows. + gfx::Rect GetTargetBoundsInScreen() const; + + // Calculates the bounds of a |window_| after being transformed to the + // selector's space. Those bounds are a union of all regular (normal and + // panel) windows in the |window_|'s transient hierarchy. The returned Rect is + // in virtual screen coordinates. The returned bounds are adjusted to allow + // the original |window_|'s header to be hidden. + gfx::Rect GetTransformedBounds() const; + + // Returns TOP_VIEW_COLOR property of |window_| unless there are transient + // ancestors in which case returns SK_ColorTRANSPARENT. + SkColor GetTopColor() const; + + // Returns TOP_VIEW_INSET property of |window_| unless there are transient + // ancestors in which case returns 0. + int GetTopInset() const; + + // Restores and animates the managed window to it's non overview mode state. + void RestoreWindow(); + + // Informs the ScopedTransformOverviewWindow that the window being watched was + // destroyed. This resets the internal window pointer. + void OnWindowDestroyed(); + + // Prepares for overview mode by doing any necessary actions before entering. + void PrepareForOverview(); + + // Applies the |transform| to the overview window and all of its transient + // children. + void SetTransform(WmWindow* root_window, const gfx::Transform& transform); + + // Set's the opacity of the managed windows. + void SetOpacity(float opacity); + + // Hides the window header whose size is given in |TOP_VIEW_INSET| + // window property. + void HideHeader(); + + // Shows the window header that is hidden by HideHeader(). + void ShowHeader(); + + // Creates/Deletes a mirror window for minimized windows. + void UpdateMirrorWindowForMinimizedState(); + + WmWindow* window() const { return window_; } + + // Closes the transient root of the window managed by |this|. + void Close(); + + // Returns the window used to show the content in overview mdoe. + // For minmiezd window, this will be a window that hosts mirrored layers. + WmWindow* GetOverviewWindow() const; + + // Ensures that a window is visible by setting its opacity to 1. + void EnsureVisible(); + + // Returns the window created for minimized window, or nullptr + // if it does not exit. + WmWindow* GetOverviewWindowForMinimizedState() const; + + // ui::EventHandler: + void OnGestureEvent(ui::GestureEvent* event) override; + void OnMouseEvent(ui::MouseEvent* event) override; + + private: + friend class WindowSelectorTest; + + // Closes the window managed by |this|. + void CloseWidget(); + + void CreateMirrorWindowForMinimizedState(); + + // Makes Close() execute synchronously when used in tests. + static void SetImmediateCloseForTests(); + + // A weak pointer to the real window in the overview. + WmWindow* window_; + + // Original window shape, if it was set on a window. + std::unique_ptr<SkRegion> original_window_shape_; + + // True after the |original_window_shape_| has been set or after it has + // been determined that window shape was not originally set on the |window_|. + bool determined_original_window_shape_; + + // Tracks if this window was ignored by the shelf. + bool ignored_by_shelf_; + + // True if the window has been transformed for overview mode. + bool overview_started_; + + // The original transform of the window before entering overview mode. + gfx::Transform original_transform_; + + // The original opacity of the window before entering overview mode. + float original_opacity_; + + // A window that holds the content for minimized window. + std::unique_ptr<views::Widget> minimized_widget_; + + base::WeakPtrFactory<ScopedTransformOverviewWindow> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ScopedTransformOverviewWindow); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_
diff --git a/ash/common/wm/overview/window_grid.cc b/ash/common/wm/overview/window_grid.cc new file mode 100644 index 0000000..eced1f5 --- /dev/null +++ b/ash/common/wm/overview/window_grid.cc
@@ -0,0 +1,844 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/window_grid.h" + +#include <algorithm> +#include <functional> +#include <set> +#include <utility> +#include <vector> + +#include "ash/common/ash_switches.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/overview/cleanup_animation_observer.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h" +#include "ash/common/wm/overview/window_selector.h" +#include "ash/common/wm/overview/window_selector_delegate.h" +#include "ash/common/wm/overview/window_selector_item.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shelf_types.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_state_aura.h" +#include "base/command_line.h" +#include "base/i18n/string_search.h" +#include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/pathops/SkPathOps.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/animation/tween.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/gfx/scoped_canvas.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/painter.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/wm/core/shadow.h" +#include "ui/wm/core/shadow_types.h" +#include "ui/wm/core/window_animations.h" + +namespace ash { +namespace { + +using Windows = std::vector<WmWindow*>; + +// A comparator for locating a given target window. +struct WindowSelectorItemComparator { + explicit WindowSelectorItemComparator(const WmWindow* target_window) + : target(target_window) {} + + bool operator()(std::unique_ptr<WindowSelectorItem>& window) const { + return window->GetWindow() == target; + } + + const WmWindow* target; +}; + +// Time it takes for the selector widget to move to the next target. The same +// time is used for fading out shield widget when the overview mode is opened +// or closed. +const int kOverviewSelectorTransitionMilliseconds = 250; + +// The color and opacity of the screen shield in overview. +const SkColor kShieldColor = SkColorSetARGB(255, 0, 0, 0); +const float kShieldOpacity = 0.7f; + +// The color and opacity of the overview selector. +const SkColor kWindowSelectionColor = SkColorSetARGB(51, 255, 255, 255); +const SkColor kWindowSelectionBorderColor = SkColorSetARGB(76, 255, 255, 255); + +// Border thickness of overview selector. +const int kWindowSelectionBorderThickness = 1; + +// Corner radius of the overview selector border. +const int kWindowSelectionRadius = 4; + +// In the conceptual overview table, the window margin is the space reserved +// around the window within the cell. This margin does not overlap so the +// closest distance between adjacent windows will be twice this amount. +const int kWindowMargin = 5; + +// Windows are not allowed to get taller than this. +const int kMaxHeight = 512; + +// Margins reserved in the overview mode. +const float kOverviewInsetRatio = 0.05f; + +// Additional vertical inset reserved for windows in overview mode. +const float kOverviewVerticalInset = 0.1f; + +// A View having rounded corners and a specified background color which is +// only painted within the bounds defined by the rounded corners. +// TODO(varkha): This duplicates code from RoundedImageView. Refactor these +// classes and move into ui/views. +class RoundedRectView : public views::View { + public: + RoundedRectView(int corner_radius, SkColor background) + : corner_radius_(corner_radius), background_(background) {} + + ~RoundedRectView() override {} + + void OnPaint(gfx::Canvas* canvas) override { + views::View::OnPaint(canvas); + + SkScalar radius = SkIntToScalar(corner_radius_); + const SkScalar kRadius[8] = {radius, radius, radius, radius, + radius, radius, radius, radius}; + SkPath path; + gfx::Rect bounds(size()); + bounds.set_height(bounds.height() + radius); + path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); + + canvas->ClipPath(path, true); + canvas->DrawColor(background_); + } + + private: + int corner_radius_; + SkColor background_; + + DISALLOW_COPY_AND_ASSIGN(RoundedRectView); +}; + +// BackgroundWith1PxBorder renders a solid background color, with a one pixel +// border with rounded corners. This accounts for the scaling of the canvas, so +// that the border is 1 pixel thick regardless of display scaling. +class BackgroundWith1PxBorder : public views::Background { + public: + BackgroundWith1PxBorder(SkColor background, + SkColor border_color, + int border_thickness, + int corner_radius); + + void Paint(gfx::Canvas* canvas, views::View* view) const override; + + private: + // Color for the one pixel border. + SkColor border_color_; + + // Thickness of border inset. + int border_thickness_; + + // Corner radius of the inside edge of the roundrect border stroke. + int corner_radius_; + + DISALLOW_COPY_AND_ASSIGN(BackgroundWith1PxBorder); +}; + +BackgroundWith1PxBorder::BackgroundWith1PxBorder(SkColor background, + SkColor border_color, + int border_thickness, + int corner_radius) + : border_color_(border_color), + border_thickness_(border_thickness), + corner_radius_(corner_radius) { + SetNativeControlColor(background); +} + +void BackgroundWith1PxBorder::Paint(gfx::Canvas* canvas, + views::View* view) const { + gfx::RectF border_rect_f(view->GetContentsBounds()); + + gfx::ScopedCanvas scoped_canvas(canvas); + const float scale = canvas->UndoDeviceScaleFactor(); + border_rect_f.Scale(scale); + const float inset = border_thickness_ * scale - 0.5f; + border_rect_f.Inset(inset, inset); + + SkPath path; + const SkScalar scaled_corner_radius = + SkFloatToScalar(corner_radius_ * scale + 0.5f); + path.addRoundRect(gfx::RectFToSkRect(border_rect_f), scaled_corner_radius, + scaled_corner_radius); + + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kStroke_Style); + flags.setStrokeWidth(1); + flags.setAntiAlias(true); + + SkPath stroke_path; + flags.getFillPath(path, &stroke_path); + + SkPath fill_path; + Op(path, stroke_path, kDifference_SkPathOp, &fill_path); + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(get_color()); + canvas->sk_canvas()->drawPath(fill_path, flags); + + if (border_thickness_ > 0) { + flags.setColor(border_color_); + canvas->sk_canvas()->drawPath(stroke_path, flags); + } +} + +// Returns the vector for the fade in animation. +gfx::Vector2d GetSlideVectorForFadeIn(WindowSelector::Direction direction, + const gfx::Rect& bounds) { + gfx::Vector2d vector; + switch (direction) { + case WindowSelector::UP: + case WindowSelector::LEFT: + vector.set_x(-bounds.width()); + break; + case WindowSelector::DOWN: + case WindowSelector::RIGHT: + vector.set_x(bounds.width()); + break; + } + return vector; +} + +// Creates and returns a background translucent widget parented in +// |root_window|'s default container and having |background_color|. +// When |border_thickness| is non-zero, a border is created having +// |border_color|, otherwise |border_color| parameter is ignored. +// The new background widget starts with |initial_opacity| and then fades in. +views::Widget* CreateBackgroundWidget(WmWindow* root_window, + ui::LayerType layer_type, + SkColor background_color, + int border_thickness, + int border_radius, + SkColor border_color, + float initial_opacity) { + views::Widget* widget = new views::Widget; + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.keep_on_top = false; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.layer_type = layer_type; + params.accept_events = false; + widget->set_focus_on_creation(false); + // Parenting in kShellWindowId_WallpaperContainer allows proper layering of + // the shield and selection widgets. Since that container is created with + // USE_LOCAL_COORDINATES BoundsInScreenBehavior local bounds in |root_window_| + // need to be provided. + root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + widget, kShellWindowId_WallpaperContainer, ¶ms); + widget->Init(params); + WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); + // Disable the "bounce in" animation when showing the window. + widget_window->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); + // The background widget should not activate the shelf when passing under it. + widget_window->GetWindowState()->set_ignored_by_shelf(true); + if (params.layer_type == ui::LAYER_SOLID_COLOR) { + widget_window->GetLayer()->SetColor(background_color); + } else { + views::View* content_view = + new RoundedRectView(border_radius, SK_ColorTRANSPARENT); + content_view->set_background(new BackgroundWith1PxBorder( + background_color, border_color, border_thickness, border_radius)); + widget->SetContentsView(content_view); + } + widget_window->GetParent()->StackChildAtTop(widget_window); + widget->Show(); + widget_window->SetOpacity(initial_opacity); + return widget; +} + +bool IsMinimizedStateType(wm::WindowStateType type) { + return type == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED || + type == wm::WINDOW_STATE_TYPE_MINIMIZED; +} + +} // namespace + +WindowGrid::WindowGrid(WmWindow* root_window, + const std::vector<WmWindow*>& windows, + WindowSelector* window_selector) + : root_window_(root_window), + window_selector_(window_selector), + window_observer_(this), + window_state_observer_(this), + selected_index_(0), + num_columns_(0), + prepared_for_overview_(false) { + std::vector<WmWindow*> windows_in_root; + for (auto* window : windows) { + if (window->GetRootWindow() == root_window) + windows_in_root.push_back(window); + } + + for (auto* window : windows_in_root) { + window_observer_.Add(window->aura_window()); + window_state_observer_.Add(window->GetWindowState()); + window_list_.push_back( + base::MakeUnique<WindowSelectorItem>(window, window_selector_)); + } +} + +WindowGrid::~WindowGrid() {} + +void WindowGrid::Shutdown() { + for (const auto& window : window_list_) + window->Shutdown(); + + if (shield_widget_) { + // Fade out the shield widget. This animation continues past the lifetime + // of |this|. + WmWindow* widget_window = WmWindow::Get(shield_widget_->GetNativeWindow()); + ui::ScopedLayerAnimationSettings animation_settings( + widget_window->GetLayer()->GetAnimator()); + animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + kOverviewSelectorTransitionMilliseconds)); + animation_settings.SetTweenType(gfx::Tween::EASE_OUT); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + // CleanupAnimationObserver will delete itself (and the shield widget) when + // the opacity animation is complete. + // Ownership over the observer is passed to the window_selector_->delegate() + // which has longer lifetime so that animations can continue even after the + // overview mode is shut down. + views::Widget* shield_widget = shield_widget_.get(); + std::unique_ptr<CleanupAnimationObserver> observer( + new CleanupAnimationObserver(std::move(shield_widget_))); + animation_settings.AddObserver(observer.get()); + window_selector_->delegate()->AddDelayedAnimationObserver( + std::move(observer)); + shield_widget->SetOpacity(0.f); + } +} + +void WindowGrid::PrepareForOverview() { + InitShieldWidget(); + for (const auto& window : window_list_) + window->PrepareForOverview(); + prepared_for_overview_ = true; +} + +void WindowGrid::PositionWindows(bool animate) { + if (window_selector_->is_shut_down() || window_list_.empty()) + return; + DCHECK(shield_widget_.get()); + // Keep the background shield widget covering the whole screen. + WmWindow* widget_window = WmWindow::Get(shield_widget_->GetNativeWindow()); + const gfx::Rect bounds = widget_window->GetParent()->GetBounds(); + widget_window->SetBounds(bounds); + gfx::Rect total_bounds = + root_window_->ConvertRectToScreen(wm::GetDisplayWorkAreaBoundsInParent( + root_window_->GetChildByShellWindowId( + kShellWindowId_DefaultContainer))); + // Windows occupy vertically centered area with additional vertical insets. + int horizontal_inset = + gfx::ToFlooredInt(std::min(kOverviewInsetRatio * total_bounds.width(), + kOverviewInsetRatio * total_bounds.height())); + int vertical_inset = + horizontal_inset + + kOverviewVerticalInset * (total_bounds.height() - 2 * horizontal_inset); + total_bounds.Inset(std::max(0, horizontal_inset - kWindowMargin), + std::max(0, vertical_inset - kWindowMargin)); + std::vector<gfx::Rect> rects; + + // Keep track of the lowest coordinate. + int max_bottom = total_bounds.y(); + + // Right bound of the narrowest row. + int min_right = total_bounds.right(); + // Right bound of the widest row. + int max_right = total_bounds.x(); + + // Keep track of the difference between the narrowest and the widest row. + // Initially this is set to the worst it can ever be assuming the windows fit. + int width_diff = total_bounds.width(); + + // Initially allow the windows to occupy all available width. Shrink this + // available space horizontally to find the breakdown into rows that achieves + // the minimal |width_diff|. + int right_bound = total_bounds.right(); + + // Determine the optimal height bisecting between |low_height| and + // |high_height|. Once this optimal height is known, |height_fixed| is set to + // true and the rows are balanced by repeatedly squeezing the widest row to + // cause windows to overflow to the subsequent rows. + int low_height = 2 * kWindowMargin; + int high_height = + std::max(low_height, static_cast<int>(total_bounds.height() + 1)); + int height = 0.5 * (low_height + high_height); + bool height_fixed = false; + + // Repeatedly try to fit the windows |rects| within |right_bound|. + // If a maximum |height| is found such that all window |rects| fit, this + // fitting continues while shrinking the |right_bound| in order to balance the + // rows. If the windows fit the |right_bound| would have been decremented at + // least once so it needs to be incremented once before getting out of this + // loop and one additional pass made to actually fit the |rects|. + // If the |rects| cannot fit (e.g. there are too many windows) the bisection + // will still finish and we might increment the |right_bound| once pixel extra + // which is acceptable since there is an unused margin on the right. + bool make_last_adjustment = false; + while (true) { + gfx::Rect overview_bounds(total_bounds); + overview_bounds.set_width(right_bound - total_bounds.x()); + bool windows_fit = FitWindowRectsInBounds( + overview_bounds, std::min(kMaxHeight + 2 * kWindowMargin, height), + &rects, &max_bottom, &min_right, &max_right); + + if (height_fixed) { + if (!windows_fit) { + // Revert the previous change to |right_bound| and do one last pass. + right_bound++; + make_last_adjustment = true; + break; + } + // Break if all the windows are zero-width at the current scale. + if (max_right <= total_bounds.x()) + break; + } else { + // Find the optimal row height bisecting between |low_height| and + // |high_height|. + if (windows_fit) + low_height = height; + else + high_height = height; + height = 0.5 * (low_height + high_height); + // When height can no longer be improved, start balancing the rows. + if (height == low_height) + height_fixed = true; + } + + if (windows_fit && height_fixed) { + if (max_right - min_right <= width_diff) { + // Row alignment is getting better. Try to shrink the |right_bound| in + // order to squeeze the widest row. + right_bound = max_right - 1; + width_diff = max_right - min_right; + } else { + // Row alignment is getting worse. + // Revert the previous change to |right_bound| and do one last pass. + right_bound++; + make_last_adjustment = true; + break; + } + } + } + // Once the windows in |window_list_| no longer fit, the change to + // |right_bound| was reverted. Perform one last pass to position the |rects|. + if (make_last_adjustment) { + gfx::Rect overview_bounds(total_bounds); + overview_bounds.set_width(right_bound - total_bounds.x()); + FitWindowRectsInBounds(overview_bounds, + std::min(kMaxHeight + 2 * kWindowMargin, height), + &rects, &max_bottom, &min_right, &max_right); + } + // Position the windows centering the left-aligned rows vertically. + gfx::Vector2d offset(0, (total_bounds.bottom() - max_bottom) / 2); + for (size_t i = 0; i < window_list_.size(); ++i) { + window_list_[i]->SetBounds( + rects[i] + offset, + animate + ? OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS + : OverviewAnimationType::OVERVIEW_ANIMATION_NONE); + } + + // If the selection widget is active, reposition it without any animation. + if (selection_widget_) + MoveSelectionWidgetToTarget(animate); +} + +bool WindowGrid::Move(WindowSelector::Direction direction, bool animate) { + bool recreate_selection_widget = false; + bool out_of_bounds = false; + bool changed_selection_index = false; + gfx::Rect old_bounds; + if (SelectedWindow()) { + old_bounds = SelectedWindow()->target_bounds(); + // Make the old selected window header non-transparent first. + SelectedWindow()->SetSelected(false); + } + + // [up] key is equivalent to [left] key and [down] key is equivalent to + // [right] key. + if (!selection_widget_) { + switch (direction) { + case WindowSelector::UP: + case WindowSelector::LEFT: + selected_index_ = window_list_.size() - 1; + break; + case WindowSelector::DOWN: + case WindowSelector::RIGHT: + selected_index_ = 0; + break; + } + changed_selection_index = true; + } + while (!changed_selection_index || + (!out_of_bounds && window_list_[selected_index_]->dimmed())) { + switch (direction) { + case WindowSelector::UP: + case WindowSelector::LEFT: + if (selected_index_ == 0) + out_of_bounds = true; + selected_index_--; + break; + case WindowSelector::DOWN: + case WindowSelector::RIGHT: + if (selected_index_ >= window_list_.size() - 1) + out_of_bounds = true; + selected_index_++; + break; + } + if (!out_of_bounds && SelectedWindow()) { + if (SelectedWindow()->target_bounds().y() != old_bounds.y()) + recreate_selection_widget = true; + } + changed_selection_index = true; + } + MoveSelectionWidget(direction, recreate_selection_widget, out_of_bounds, + animate); + + // Make the new selected window header fully transparent. + if (SelectedWindow()) + SelectedWindow()->SetSelected(true); + return out_of_bounds; +} + +WindowSelectorItem* WindowGrid::SelectedWindow() const { + if (!selection_widget_) + return nullptr; + CHECK(selected_index_ < window_list_.size()); + return window_list_[selected_index_].get(); +} + +bool WindowGrid::Contains(const WmWindow* window) const { + for (const auto& window_item : window_list_) { + if (window_item->Contains(window)) + return true; + } + return false; +} + +void WindowGrid::FilterItems(const base::string16& pattern) { + base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents finder(pattern); + for (const auto& window : window_list_) { + if (finder.Search(window->GetWindow()->GetTitle(), nullptr, nullptr)) { + window->SetDimmed(false); + } else { + window->SetDimmed(true); + if (selection_widget_ && SelectedWindow() == window.get()) { + SelectedWindow()->SetSelected(false); + selection_widget_.reset(); + selector_shadow_.reset(); + } + } + } +} + +void WindowGrid::WindowClosing(WindowSelectorItem* window) { + if (!selection_widget_ || SelectedWindow() != window) + return; + WmWindow* selection_widget_window = + WmWindow::Get(selection_widget_->GetNativeWindow()); + std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings_label = + ScopedOverviewAnimationSettingsFactory::Get() + ->CreateOverviewAnimationSettings( + OverviewAnimationType::OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM, + selection_widget_window); + selection_widget_->SetOpacity(0.f); +} + +void WindowGrid::OnWindowDestroying(aura::Window* window) { + window_observer_.Remove(window); + window_state_observer_.Remove(wm::GetWindowState(window)); + auto iter = std::find_if(window_list_.begin(), window_list_.end(), + WindowSelectorItemComparator(WmWindow::Get(window))); + + DCHECK(iter != window_list_.end()); + + size_t removed_index = iter - window_list_.begin(); + window_list_.erase(iter); + + if (empty()) { + // If the grid is now empty, notify the window selector so that it erases us + // from its grid list. + window_selector_->OnGridEmpty(this); + return; + } + + // If selecting, update the selection index. + if (selection_widget_) { + bool send_focus_alert = selected_index_ == removed_index; + if (selected_index_ >= removed_index && selected_index_ != 0) + selected_index_--; + SelectedWindow()->SetSelected(true); + if (send_focus_alert) + SelectedWindow()->SendAccessibleSelectionEvent(); + } + + PositionWindows(true); +} + +void WindowGrid::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + // During preparation, window bounds can change. Ignore bounds + // change notifications in this case; we'll reposition soon. + if (!prepared_for_overview_) + return; + + auto iter = std::find_if(window_list_.begin(), window_list_.end(), + WindowSelectorItemComparator(WmWindow::Get(window))); + DCHECK(iter != window_list_.end()); + + // Immediately finish any active bounds animation. + window->layer()->GetAnimator()->StopAnimatingProperty( + ui::LayerAnimationElement::BOUNDS); + PositionWindows(false); +} + +void WindowGrid::OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) { + // During preparation, window state can change, e.g. updating shelf + // visibility may show the temporarily hidden (minimized) panels. + if (!prepared_for_overview_) + return; + + wm::WindowStateType new_type = window_state->GetStateType(); + if (IsMinimizedStateType(old_type) == IsMinimizedStateType(new_type)) + return; + + auto iter = + std::find_if(window_list_.begin(), window_list_.end(), + [window_state](std::unique_ptr<WindowSelectorItem>& item) { + return item->Contains(window_state->window()); + }); + if (iter != window_list_.end()) { + (*iter)->OnMinimizedStateChanged(); + PositionWindows(false); + } +} + +void WindowGrid::InitShieldWidget() { + // TODO(varkha): The code assumes that SHELF_BACKGROUND_MAXIMIZED is + // synonymous with a black shelf background. Update this code if that + // assumption is no longer valid. + const float initial_opacity = + (WmShelf::ForWindow(root_window_)->GetBackgroundType() == + SHELF_BACKGROUND_MAXIMIZED) + ? 1.f + : 0.f; + shield_widget_.reset( + CreateBackgroundWidget(root_window_, ui::LAYER_SOLID_COLOR, kShieldColor, + 0, 0, SK_ColorTRANSPARENT, initial_opacity)); + WmWindow* widget_window = WmWindow::Get(shield_widget_->GetNativeWindow()); + const gfx::Rect bounds = widget_window->GetParent()->GetBounds(); + widget_window->SetBounds(bounds); + widget_window->SetName("OverviewModeShield"); + + ui::ScopedLayerAnimationSettings animation_settings( + widget_window->GetLayer()->GetAnimator()); + animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + kOverviewSelectorTransitionMilliseconds)); + animation_settings.SetTweenType(gfx::Tween::EASE_OUT); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + shield_widget_->SetOpacity(kShieldOpacity); +} + +void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) { + selection_widget_.reset(CreateBackgroundWidget( + root_window_, ui::LAYER_TEXTURED, kWindowSelectionColor, + kWindowSelectionBorderThickness, kWindowSelectionRadius, + kWindowSelectionBorderColor, 0.f)); + WmWindow* widget_window = WmWindow::Get(selection_widget_->GetNativeWindow()); + const gfx::Rect target_bounds = + root_window_->ConvertRectFromScreen(SelectedWindow()->target_bounds()); + gfx::Vector2d fade_out_direction = + GetSlideVectorForFadeIn(direction, target_bounds); + widget_window->SetBounds(target_bounds - fade_out_direction); + widget_window->SetName("OverviewModeSelector"); + + selector_shadow_.reset(new ::wm::Shadow()); + selector_shadow_->Init(::wm::ShadowElevation::LARGE); + selector_shadow_->layer()->SetVisible(true); + selection_widget_->GetLayer()->SetMasksToBounds(false); + selection_widget_->GetLayer()->Add(selector_shadow_->layer()); + selector_shadow_->SetContentBounds(gfx::Rect(target_bounds.size())); +} + +void WindowGrid::MoveSelectionWidget(WindowSelector::Direction direction, + bool recreate_selection_widget, + bool out_of_bounds, + bool animate) { + // If the selection widget is already active, fade it out in the selection + // direction. + if (selection_widget_ && (recreate_selection_widget || out_of_bounds)) { + // Animate the old selection widget and then destroy it. + views::Widget* old_selection = selection_widget_.get(); + WmWindow* old_selection_window = + WmWindow::Get(old_selection->GetNativeWindow()); + gfx::Vector2d fade_out_direction = + GetSlideVectorForFadeIn(direction, old_selection_window->GetBounds()); + + ui::ScopedLayerAnimationSettings animation_settings( + old_selection_window->GetLayer()->GetAnimator()); + animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + kOverviewSelectorTransitionMilliseconds)); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + animation_settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN); + // CleanupAnimationObserver will delete itself (and the widget) when the + // motion animation is complete. + // Ownership over the observer is passed to the window_selector_->delegate() + // which has longer lifetime so that animations can continue even after the + // overview mode is shut down. + std::unique_ptr<CleanupAnimationObserver> observer( + new CleanupAnimationObserver(std::move(selection_widget_))); + animation_settings.AddObserver(observer.get()); + window_selector_->delegate()->AddDelayedAnimationObserver( + std::move(observer)); + old_selection->SetOpacity(0.f); + old_selection_window->SetBounds(old_selection_window->GetBounds() + + fade_out_direction); + old_selection->Hide(); + } + if (out_of_bounds) + return; + + if (!selection_widget_) + InitSelectionWidget(direction); + // Send an a11y alert so that if ChromeVox is enabled, the item label is + // read. + SelectedWindow()->SendAccessibleSelectionEvent(); + // The selection widget is moved to the newly selected item in the same + // grid. + MoveSelectionWidgetToTarget(animate); +} + +void WindowGrid::MoveSelectionWidgetToTarget(bool animate) { + gfx::Rect bounds = + root_window_->ConvertRectFromScreen(SelectedWindow()->target_bounds()); + if (animate) { + WmWindow* selection_widget_window = + WmWindow::Get(selection_widget_->GetNativeWindow()); + ui::ScopedLayerAnimationSettings animation_settings( + selection_widget_window->GetLayer()->GetAnimator()); + animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + kOverviewSelectorTransitionMilliseconds)); + animation_settings.SetTweenType(gfx::Tween::EASE_IN_OUT); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + selection_widget_->SetBounds(bounds); + selection_widget_->SetOpacity(1.f); + + if (selector_shadow_) { + ui::ScopedLayerAnimationSettings animation_settings_shadow( + selector_shadow_->shadow_layer()->GetAnimator()); + animation_settings_shadow.SetTransitionDuration( + base::TimeDelta::FromMilliseconds( + kOverviewSelectorTransitionMilliseconds)); + animation_settings_shadow.SetTweenType(gfx::Tween::EASE_IN_OUT); + animation_settings_shadow.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + bounds.Inset(1, 1); + selector_shadow_->SetContentBounds( + gfx::Rect(gfx::Point(1, 1), bounds.size())); + } + return; + } + selection_widget_->SetBounds(bounds); + selection_widget_->SetOpacity(1.f); + if (selector_shadow_) { + bounds.Inset(1, 1); + selector_shadow_->SetContentBounds( + gfx::Rect(gfx::Point(1, 1), bounds.size())); + } +} + +bool WindowGrid::FitWindowRectsInBounds(const gfx::Rect& bounds, + int height, + std::vector<gfx::Rect>* rects, + int* max_bottom, + int* min_right, + int* max_right) { + rects->resize(window_list_.size()); + bool windows_fit = true; + + // Start in the top-left corner of |bounds|. + int left = bounds.x(); + int top = bounds.y(); + + // Keep track of the lowest coordinate. + *max_bottom = bounds.y(); + + // Right bound of the narrowest row. + *min_right = bounds.right(); + // Right bound of the widest row. + *max_right = bounds.x(); + + // All elements are of same height and only the height is necessary to + // determine each item's scale. + const gfx::Size item_size(0, height); + size_t i = 0; + for (const auto& window : window_list_) { + const gfx::Rect target_bounds = window->GetTargetBoundsInScreen(); + const int width = + std::max(1, gfx::ToFlooredInt(target_bounds.width() * + window->GetItemScale(item_size)) + + 2 * kWindowMargin); + if (left + width > bounds.right()) { + // Move to the next row if possible. + if (*min_right > left) + *min_right = left; + if (*max_right < left) + *max_right = left; + top += height; + + // Check if the new row reaches the bottom or if the first item in the new + // row does not fit within the available width. + if (top + height > bounds.bottom() || + bounds.x() + width > bounds.right()) { + windows_fit = false; + break; + } + left = bounds.x(); + } + + // Position the current rect. + (*rects)[i].SetRect(left, top, width, height); + + // Increment horizontal position using sanitized positive |width()|. + left += (*rects)[i].width(); + + if (++i == window_list_.size()) { + // Update the narrowest and widest row width for the last row. + if (*min_right > left) + *min_right = left; + if (*max_right < left) + *max_right = left; + } + *max_bottom = top + height; + } + return windows_fit; +} + +} // namespace ash
diff --git a/ash/common/wm/overview/window_grid.h b/ash/common/wm/overview/window_grid.h new file mode 100644 index 0000000..67f4f56 --- /dev/null +++ b/ash/common/wm/overview/window_grid.h
@@ -0,0 +1,198 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_WINDOW_GRID_H_ +#define ASH_COMMON_WM_OVERVIEW_WINDOW_GRID_H_ + +#include <stddef.h> + +#include <memory> +#include <set> +#include <vector> + +#include "ash/common/wm/overview/window_selector.h" +#include "ash/common/wm/window_state_observer.h" +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "ui/aura/window_observer.h" + +namespace views { +class Widget; +} + +namespace wm { +class Shadow; +} + +namespace ash { + +class WindowSelectorItem; + +// Represents a grid of windows in the Overview Mode in a particular root +// window, and manages a selection widget that can be moved with the arrow keys. +// The idea behind the movement strategy is that it should be possible to access +// any window pressing a given arrow key repeatedly. +// +-------+ +-------+ +-------+ +// | 0 | | 1 | | 2 | +// +-------+ +-------+ +-------+ +// +-------+ +-------+ +-------+ +// | 3 | | 4 | | 5 | +// +-------+ +-------+ +-------+ +// +-------+ +// | 6 | +// +-------+ +// Example sequences: +// - Going right to left +// 0, 1, 2, 3, 4, 5, 6 +// The selector is switched to the next window grid (if available) or wrapped if +// it reaches the end of its movement sequence. +class ASH_EXPORT WindowGrid : public aura::WindowObserver, + public wm::WindowStateObserver { + public: + WindowGrid(WmWindow* root_window, + const std::vector<WmWindow*>& window_list, + WindowSelector* window_selector); + ~WindowGrid() override; + + // Exits overview mode, fading out the |shield_widget_| if necessary. + void Shutdown(); + + // Prepares the windows in this grid for overview. This will restore all + // minimized windows and ensure they are visible. + void PrepareForOverview(); + + // Positions all the windows in rows of equal height scaling each window to + // fit that height. + // Layout is done in 2 stages maintaining fixed MRU ordering. + // 1. Optimal height is determined. In this stage |height| is bisected to find + // maximum height which still allows all the windows to fit. + // 2. Row widths are balanced. In this stage the available width is reduced + // until some windows are no longer fitting or until the difference between + // the narrowest and the widest rows starts growing. + // Overall this achieves the goals of maximum size for previews (or maximum + // row height which is equivalent assuming fixed height), balanced rows and + // minimal wasted space. + // Optionally animates the windows to their targets when |animate| is true. + void PositionWindows(bool animate); + + // Updates |selected_index_| according to the specified |direction| and calls + // MoveSelectionWidget(). Returns |true| if the new selection index is out of + // this window grid bounds. + bool Move(WindowSelector::Direction direction, bool animate); + + // Returns the target selected window, or NULL if there is none selected. + WindowSelectorItem* SelectedWindow() const; + + // Returns true if a window is contained in any of the WindowSelectorItems + // this grid owns. + bool Contains(const WmWindow* window) const; + + // Dims the items whose titles do not contain |pattern| and prevents their + // selection. The pattern has its accents removed and is converted to + // lowercase in a l10n sensitive context. + // If |pattern| is empty, no item is dimmed. + void FilterItems(const base::string16& pattern); + + // Called when |window| is about to get closed. If the |window| is currently + // selected the implementation fades out |selection_widget_| to transparent + // opacity, effectively hiding the selector widget. + void WindowClosing(WindowSelectorItem* window); + + // Returns true if the grid has no more windows. + bool empty() const { return window_list_.empty(); } + + // Returns how many window selector items are in the grid. + size_t size() const { return window_list_.size(); } + + // Returns true if the selection widget is active. + bool is_selecting() const { return selection_widget_ != nullptr; } + + // Returns the root window in which the grid displays the windows. + const WmWindow* root_window() const { return root_window_; } + + const std::vector<std::unique_ptr<WindowSelectorItem>>& window_list() const { + return window_list_; + } + + // aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + // TODO(flackr): Handle window bounds changed in WindowSelectorItem. + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override; + + // wm::WindowStateObserver: + void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) override; + + private: + friend class WindowSelectorTest; + + // Initializes the screen shield widget. + void InitShieldWidget(); + + // Internal function to initialize the selection widget. + void InitSelectionWidget(WindowSelector::Direction direction); + + // Moves the selection widget to the specified |direction|. + void MoveSelectionWidget(WindowSelector::Direction direction, + bool recreate_selection_widget, + bool out_of_bounds, + bool animate); + + // Moves the selection widget to the targeted window. + void MoveSelectionWidgetToTarget(bool animate); + + // Attempts to fit all |rects| inside |bounds|. The method ensures that + // the |rects| vector has appropriate size and populates it with the values + // placing Rects next to each other left-to-right in rows of equal |height|. + // While fitting |rects| several metrics are collected that can be used by the + // caller. |max_bottom| specifies the bottom that the rects are extending to. + // |min_right| and |max_right| report the right bound of the narrowest and the + // widest rows respectively. In-values of the |max_bottom|, |min_right| and + // |max_right| parameters are ignored and their values are always initialized + // inside this method. Returns true on success and false otherwise. + bool FitWindowRectsInBounds(const gfx::Rect& bounds, + int height, + std::vector<gfx::Rect>* rects, + int* max_bottom, + int* min_right, + int* max_right); + + // Root window the grid is in. + WmWindow* root_window_; + + // Pointer to the window selector that spawned this grid. + WindowSelector* window_selector_; + + // Vector containing all the windows in this grid. + std::vector<std::unique_ptr<WindowSelectorItem>> window_list_; + + ScopedObserver<aura::Window, WindowGrid> window_observer_; + ScopedObserver<wm::WindowState, WindowGrid> window_state_observer_; + + // Widget that darkens the screen background. + std::unique_ptr<views::Widget> shield_widget_; + + // Widget that indicates to the user which is the selected window. + std::unique_ptr<views::Widget> selection_widget_; + + // Shadow around the selector. + std::unique_ptr<::wm::Shadow> selector_shadow_; + + // Current selected window position. + size_t selected_index_; + + // Number of columns in the grid. + size_t num_columns_; + + // True only after all windows have been prepared for overview. + bool prepared_for_overview_; + + DISALLOW_COPY_AND_ASSIGN(WindowGrid); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_WINDOW_GRID_H_
diff --git a/ash/common/wm/overview/window_selector.cc b/ash/common/wm/overview/window_selector.cc new file mode 100644 index 0000000..1905eaf --- /dev/null +++ b/ash/common/wm/overview/window_selector.cc
@@ -0,0 +1,685 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/window_selector.h" + +#include <algorithm> +#include <functional> +#include <set> +#include <utility> +#include <vector> + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/accessibility_types.h" +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_grid.h" +#include "ash/common/wm/overview/window_selector_delegate.h" +#include "ash/common/wm/overview/window_selector_item.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/switchable_windows.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/auto_reset.h" +#include "base/command_line.h" +#include "base/metrics/histogram_macros.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/display/screen.h" +#include "ui/events/event.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/skia_util.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/layout/box_layout.h" + +namespace ash { + +namespace { + +// The amount of padding surrounding the text in the text filtering textbox. +const int kTextFilterHorizontalPadding = 10; + +// The height of the text filtering textbox. +const int kTextFilterHeight = 40; + +// The margin at the bottom to make sure the text filter layer is hidden. +// This is needed because positioning the text filter directly touching the top +// edge of the screen still allows the shadow to peek through. +const int kTextFieldBottomMargin = 2; + +// Distance from top of overview to the top of text filtering textbox as a +// proportion of the total overview area. +const float kTextFilterTopScreenProportion = 0.02f; + +// Width of the text filter area. +const int kTextFilterWidth = 280; + +// The font style used for text filtering textbox. +static const ui::ResourceBundle::FontStyle kTextFilterFontStyle = + ui::ResourceBundle::FontStyle::BaseFont; + +// The color of the text and its background in the text filtering textbox. +const SkColor kTextFilterTextColor = SkColorSetARGB(222, 0, 0, 0); +const SkColor kTextFilterBackgroundColor = SK_ColorWHITE; + +// The color or search icon. +const SkColor kTextFilterIconColor = SkColorSetARGB(138, 0, 0, 0); + +// The size of search icon. +const int kTextFilterIconSize = 20; + +// The radius used for the rounded corners on the text filtering textbox. +const int kTextFilterCornerRadius = 2; + +// A comparator for locating a selector item for a given root. +struct WindowSelectorItemForRoot { + explicit WindowSelectorItemForRoot(const WmWindow* root) + : root_window(root) {} + + bool operator()(WindowSelectorItem* item) const { + return item->root_window() == root_window; + } + + const WmWindow* root_window; +}; + +// A View having rounded corners and a specified background color which is +// only painted within the bounds defined by the rounded corners. +// TODO(tdanderson): This duplicates code from RoundedImageView. Refactor these +// classes and move into ui/views. +class RoundedContainerView : public views::View { + public: + RoundedContainerView(int corner_radius, SkColor background) + : corner_radius_(corner_radius), background_(background) {} + + ~RoundedContainerView() override {} + + void OnPaint(gfx::Canvas* canvas) override { + views::View::OnPaint(canvas); + + SkScalar radius = SkIntToScalar(corner_radius_); + const SkScalar kRadius[8] = {radius, radius, radius, radius, + radius, radius, radius, radius}; + SkPath path; + gfx::Rect bounds(size()); + path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); + + canvas->ClipPath(path, true); + canvas->DrawColor(background_); + } + + private: + int corner_radius_; + SkColor background_; + + DISALLOW_COPY_AND_ASSIGN(RoundedContainerView); +}; + +// Triggers a shelf visibility update on all root window controllers. +void UpdateShelfVisibility() { + for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) + WmShelf::ForWindow(root)->UpdateVisibilityState(); +} + +gfx::Rect GetTextFilterPosition(WmWindow* root_window) { + gfx::Rect total_bounds = root_window->ConvertRectToScreen( + wm::GetDisplayWorkAreaBoundsInParent(root_window->GetChildByShellWindowId( + kShellWindowId_DefaultContainer))); + return gfx::Rect( + 0.5 * (total_bounds.width() - + std::min(kTextFilterWidth, total_bounds.width())), + total_bounds.y() + total_bounds.height() * kTextFilterTopScreenProportion, + std::min(kTextFilterWidth, total_bounds.width()), kTextFilterHeight); +} + +// Initializes the text filter on the top of the main root window and requests +// focus on its textfield. Uses |image| to place an icon to the left of the text +// field. +views::Widget* CreateTextFilter(views::TextfieldController* controller, + WmWindow* root_window, + const gfx::ImageSkia& image, + int* text_filter_bottom) { + views::Widget* widget = new views::Widget; + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.accept_events = true; + params.bounds = GetTextFilterPosition(root_window); + params.name = "OverviewModeTextFilter"; + *text_filter_bottom = params.bounds.bottom() + kTextFieldBottomMargin; + root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + widget, kShellWindowId_StatusContainer, ¶ms); + widget->Init(params); + + // Use |container| to specify the padding surrounding the text and to give + // the textfield rounded corners. + views::View* container = new RoundedContainerView(kTextFilterCornerRadius, + kTextFilterBackgroundColor); + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + const int text_height = + std::max(kTextFilterIconSize, + bundle.GetFontList(kTextFilterFontStyle).GetHeight()); + DCHECK(text_height); + const int vertical_padding = (params.bounds.height() - text_height) / 2; + views::BoxLayout* layout = new views::BoxLayout( + views::BoxLayout::kHorizontal, kTextFilterHorizontalPadding, + vertical_padding, kTextFilterHorizontalPadding); + container->SetLayoutManager(layout); + + views::Textfield* textfield = new views::Textfield; + textfield->set_controller(controller); + textfield->SetBorder(views::NullBorder()); + textfield->SetBackgroundColor(kTextFilterBackgroundColor); + textfield->SetTextColor(kTextFilterTextColor); + views::ImageView* image_view = new views::ImageView; + image_view->SetImage(image); + container->AddChildView(image_view); + textfield->SetFontList(bundle.GetFontList(kTextFilterFontStyle)); + container->AddChildView(textfield); + layout->SetFlexForView(textfield, 1); + widget->SetContentsView(container); + + // The textfield initially contains no text, so shift its position to be + // outside the visible bounds of the screen. + gfx::Transform transform; + transform.Translate(0, -(*text_filter_bottom)); + WmWindow* text_filter_widget_window = + WmWindow::Get(widget->GetNativeWindow()); + text_filter_widget_window->SetOpacity(0); + text_filter_widget_window->SetTransform(transform); + widget->Show(); + textfield->RequestFocus(); + + return widget; +} + +} // namespace + +// static +bool WindowSelector::IsSelectable(WmWindow* window) { + wm::WindowState* state = window->GetWindowState(); + return state->IsUserPositionable(); +} + +WindowSelector::WindowSelector(WindowSelectorDelegate* delegate) + : delegate_(delegate), + restore_focus_window_(WmShell::Get()->GetFocusedWindow()), + ignore_activations_(false), + selected_grid_index_(0), + overview_start_time_(base::Time::Now()), + num_key_presses_(0), + num_items_(0), + showing_text_filter_(false), + text_filter_string_length_(0), + num_times_textfield_cleared_(0), + restoring_minimized_windows_(false), + text_filter_bottom_(0) { + DCHECK(delegate_); +} + +WindowSelector::~WindowSelector() { + RemoveAllObservers(); +} + +// NOTE: The work done in Init() is not done in the constructor because it may +// cause other, unrelated classes, (ie PanelLayoutManager) to make indirect +// calls to restoring_minimized_windows() on a partially constructed object. +void WindowSelector::Init(const WindowList& windows) { + if (restore_focus_window_) + restore_focus_window_->aura_window()->AddObserver(this); + + WmShell* shell = WmShell::Get(); + + std::vector<WmWindow*> root_windows = shell->GetAllRootWindows(); + std::sort(root_windows.begin(), root_windows.end(), + [](const WmWindow* a, const WmWindow* b) { + // Since we don't know if windows are vertically or horizontally + // oriented we use both x and y position. This may be confusing + // if you have 3 or more monitors which are not strictly + // horizontal or vertical but that case is not yet supported. + return (a->GetBoundsInScreen().x() + a->GetBoundsInScreen().y()) < + (b->GetBoundsInScreen().x() + b->GetBoundsInScreen().y()); + }); + + for (WmWindow* root : root_windows) { + // Observed switchable containers for newly created windows on all root + // windows. + for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) { + WmWindow* container = + root->GetChildByShellWindowId(wm::kSwitchableWindowContainerIds[i]); + container->aura_window()->AddObserver(this); + observed_windows_.insert(container); + } + + // Hide the callout widgets for panels. It is safe to call this for + // root windows that don't contain any panel windows. + PanelLayoutManager::Get(root)->SetShowCalloutWidgets(false); + + std::unique_ptr<WindowGrid> grid(new WindowGrid(root, windows, this)); + if (grid->empty()) + continue; + num_items_ += grid->size(); + grid_list_.push_back(std::move(grid)); + } + + { + // The calls to WindowGrid::PrepareForOverview() and CreateTextFilter(...) + // requires some LayoutManagers (ie PanelLayoutManager) to perform layouts + // so that windows are correctly visible and properly animated in overview + // mode. Otherwise these layouts should be suppressed during overview mode + // so they don't conflict with overview mode animations. The + // |restoring_minimized_windows_| flag enables the PanelLayoutManager to + // make this decision. + base::AutoReset<bool> auto_restoring_minimized_windows( + &restoring_minimized_windows_, true); + + // Do not call PrepareForOverview until all items are added to window_list_ + // as we don't want to cause any window updates until all windows in + // overview are observed. See http://crbug.com/384495. + for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { + window_grid->PrepareForOverview(); + window_grid->PositionWindows(true); + } + + search_image_ = + gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH, + kTextFilterIconSize, kTextFilterIconColor); + WmWindow* root_window = shell->GetPrimaryRootWindow(); + text_filter_widget_.reset(CreateTextFilter(this, root_window, search_image_, + &text_filter_bottom_)); + } + + DCHECK(!grid_list_.empty()); + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", num_items_); + + shell->AddActivationObserver(this); + + display::Screen::GetScreen()->AddObserver(this); + shell->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW); + // Send an a11y alert. + WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert( + A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED); + + UpdateShelfVisibility(); +} + +// NOTE: The work done in Shutdown() is not done in the destructor because it +// may cause other, unrelated classes, (ie PanelLayoutManager) to make indirect +// calls to restoring_minimized_windows() on a partially destructed object. +void WindowSelector::Shutdown() { + is_shut_down_ = true; + // Stop observing screen metrics changes first to avoid auto-positioning + // windows in response to work area changes from window activation. + display::Screen::GetScreen()->RemoveObserver(this); + + size_t remaining_items = 0; + for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { + for (const auto& window_selector_item : window_grid->window_list()) + window_selector_item->RestoreWindow(); + remaining_items += window_grid->size(); + } + + // Setting focus after restoring windows' state avoids unnecessary animations. + ResetFocusRestoreWindow(true); + RemoveAllObservers(); + + std::vector<WmWindow*> root_windows = WmShell::Get()->GetAllRootWindows(); + for (WmWindow* window : root_windows) { + // Un-hide the callout widgets for panels. It is safe to call this for + // root_windows that don't contain any panel windows. + PanelLayoutManager::Get(window)->SetShowCalloutWidgets(true); + } + + for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) + window_grid->Shutdown(); + + DCHECK(num_items_ >= remaining_items); + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems", + num_items_ - remaining_items); + UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowSelector.TimeInOverview", + base::Time::Now() - overview_start_time_); + + // Record metrics related to text filtering. + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringStringLength", + text_filter_string_length_); + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringTextfieldCleared", + num_times_textfield_cleared_); + if (text_filter_string_length_) { + UMA_HISTOGRAM_MEDIUM_TIMES( + "Ash.WindowSelector.TimeInOverviewWithTextFiltering", + base::Time::Now() - overview_start_time_); + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ItemsWhenTextFilteringUsed", + remaining_items); + } + + // Clearing the window list resets the ignored_by_shelf flag on the windows. + grid_list_.clear(); + UpdateShelfVisibility(); +} + +void WindowSelector::RemoveAllObservers() { + for (WmWindow* window : observed_windows_) + window->aura_window()->RemoveObserver(this); + + WmShell::Get()->RemoveActivationObserver(this); + display::Screen::GetScreen()->RemoveObserver(this); + if (restore_focus_window_) + restore_focus_window_->aura_window()->RemoveObserver(this); +} + +void WindowSelector::CancelSelection() { + delegate_->OnSelectionEnded(); +} + +void WindowSelector::OnGridEmpty(WindowGrid* grid) { + size_t index = 0; + for (auto iter = grid_list_.begin(); iter != grid_list_.end(); ++iter) { + if (grid == (*iter).get()) { + index = iter - grid_list_.begin(); + grid_list_.erase(iter); + break; + } + } + if (index > 0 && selected_grid_index_ >= index) { + selected_grid_index_--; + // If the grid which became empty was the one with the selected window, we + // need to select a window on the newly selected grid. + if (selected_grid_index_ == index - 1) + Move(LEFT, true); + } + if (grid_list_.empty()) + CancelSelection(); +} + +void WindowSelector::IncrementSelection(int increment) { + const Direction direction = + increment > 0 ? WindowSelector::RIGHT : WindowSelector::LEFT; + for (int step = 0; step < abs(increment); ++step) + Move(direction, true); +} + +bool WindowSelector::AcceptSelection() { + if (!grid_list_[selected_grid_index_]->is_selecting()) + return false; + SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow()); + return true; +} + +void WindowSelector::SelectWindow(WindowSelectorItem* item) { + WmWindow* window = item->GetWindow(); + std::vector<WmWindow*> window_list = + WmShell::Get()->mru_window_tracker()->BuildMruWindowList(); + if (!window_list.empty()) { + // Record UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED if the user is selecting + // a window other than the window that was active prior to entering overview + // mode (i.e., the window at the front of the MRU list). + if (window_list[0] != window) { + WmShell::Get()->RecordUserMetricsAction( + UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED); + } + const auto it = std::find(window_list.begin(), window_list.end(), window); + if (it != window_list.end()) { + // Record 1-based index so that selecting a top MRU window will record 1. + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.SelectionDepth", + 1 + it - window_list.begin()); + } + } + item->EnsureVisible(); + window->GetWindowState()->Activate(); +} + +void WindowSelector::WindowClosing(WindowSelectorItem* window) { + grid_list_[selected_grid_index_]->WindowClosing(window); +} + +bool WindowSelector::HandleKeyEvent(views::Textfield* sender, + const ui::KeyEvent& key_event) { + if (key_event.type() != ui::ET_KEY_PRESSED) + return false; + + switch (key_event.key_code()) { + case ui::VKEY_ESCAPE: + CancelSelection(); + break; + case ui::VKEY_UP: + num_key_presses_++; + Move(WindowSelector::UP, true); + break; + case ui::VKEY_DOWN: + num_key_presses_++; + Move(WindowSelector::DOWN, true); + break; + case ui::VKEY_RIGHT: + case ui::VKEY_TAB: + if (key_event.key_code() == ui::VKEY_RIGHT || + !(key_event.flags() & ui::EF_SHIFT_DOWN)) { + num_key_presses_++; + Move(WindowSelector::RIGHT, true); + break; + } + case ui::VKEY_LEFT: + num_key_presses_++; + Move(WindowSelector::LEFT, true); + break; + case ui::VKEY_W: + if (!(key_event.flags() & ui::EF_CONTROL_DOWN) || + !grid_list_[selected_grid_index_]->is_selecting()) { + // Allow the textfield to handle 'W' key when not used with Ctrl. + return false; + } + WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_CLOSE_KEY); + grid_list_[selected_grid_index_]->SelectedWindow()->CloseWindow(); + break; + case ui::VKEY_RETURN: + // Ignore if no item is selected. + if (!grid_list_[selected_grid_index_]->is_selecting()) + return false; + UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ArrowKeyPresses", + num_key_presses_); + UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.WindowSelector.KeyPressesOverItemsRatio", + (num_key_presses_ * 100) / num_items_, 1, 300, + 30); + WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_ENTER_KEY); + SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow()); + break; + default: + // Not a key we are interested in, allow the textfield to handle it. + return false; + } + return true; +} + +void WindowSelector::OnDisplayAdded(const display::Display& display) {} + +void WindowSelector::OnDisplayRemoved(const display::Display& display) { + // TODO(flackr): Keep window selection active on remaining displays. + CancelSelection(); +} + +void WindowSelector::OnDisplayMetricsChanged(const display::Display& display, + uint32_t metrics) { + PositionWindows(/* animate */ false); + RepositionTextFilterOnDisplayMetricsChange(); +} + +void WindowSelector::OnWindowHierarchyChanged( + const HierarchyChangeParams& params) { + // Only care about newly added children of |observed_windows_|. + if (!observed_windows_.count(WmWindow::Get(params.receiver)) || + !observed_windows_.count(WmWindow::Get(params.new_parent))) { + return; + } + + WmWindow* new_window = WmWindow::Get(params.target); + if (!IsSelectable(new_window)) + return; + + for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) { + if (new_window->GetParent()->GetShellWindowId() == + wm::kSwitchableWindowContainerIds[i] && + !new_window->GetTransientParent()) { + // The new window is in one of the switchable containers, abort overview. + CancelSelection(); + return; + } + } +} + +void WindowSelector::OnWindowDestroying(aura::Window* window) { + window->RemoveObserver(this); + observed_windows_.erase(WmWindow::Get(window)); + if (WmWindow::Get(window) == restore_focus_window_) + restore_focus_window_ = nullptr; +} + +void WindowSelector::OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) { + if (ignore_activations_ || !gained_active || + gained_active == GetTextFilterWidgetWindow()) { + return; + } + + WmWindow* root_window = gained_active->GetRootWindow(); + auto grid = + std::find_if(grid_list_.begin(), grid_list_.end(), + [root_window](const std::unique_ptr<WindowGrid>& grid) { + return grid->root_window() == root_window; + }); + if (grid == grid_list_.end()) + return; + const auto& windows = (*grid)->window_list(); + + auto iter = std::find_if( + windows.begin(), windows.end(), + [gained_active](const std::unique_ptr<WindowSelectorItem>& window) { + return window->Contains(gained_active); + }); + + if (iter == windows.end() && showing_text_filter_ && + lost_active == GetTextFilterWidgetWindow()) { + return; + } + + // Don't restore focus on exit if a window was just activated. + ResetFocusRestoreWindow(false); + CancelSelection(); +} + +void WindowSelector::OnAttemptToReactivateWindow(WmWindow* request_active, + WmWindow* actual_active) { + OnWindowActivated(request_active, actual_active); +} + +void WindowSelector::ContentsChanged(views::Textfield* sender, + const base::string16& new_contents) { + text_filter_string_length_ = new_contents.length(); + if (!text_filter_string_length_) + num_times_textfield_cleared_++; + + bool should_show_text_filter = !new_contents.empty(); + if (showing_text_filter_ != should_show_text_filter) { + WmWindow* text_filter_widget_window = GetTextFilterWidgetWindow(); + ui::ScopedLayerAnimationSettings animation_settings( + text_filter_widget_window->GetLayer()->GetAnimator()); + animation_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + animation_settings.SetTweenType(showing_text_filter_ + ? gfx::Tween::FAST_OUT_LINEAR_IN + : gfx::Tween::LINEAR_OUT_SLOW_IN); + + gfx::Transform transform; + if (should_show_text_filter) { + transform.Translate(0, 0); + text_filter_widget_window->SetOpacity(1); + } else { + transform.Translate(0, -text_filter_bottom_); + text_filter_widget_window->SetOpacity(0); + } + + text_filter_widget_window->SetTransform(transform); + showing_text_filter_ = should_show_text_filter; + } + for (auto iter = grid_list_.begin(); iter != grid_list_.end(); iter++) + (*iter)->FilterItems(new_contents); + + // If the selection widget is not active, execute a Move() command so that it + // shows up on the first undimmed item. + if (grid_list_[selected_grid_index_]->is_selecting()) + return; + Move(WindowSelector::RIGHT, false); +} + +WmWindow* WindowSelector::GetTextFilterWidgetWindow() { + return WmWindow::Get(text_filter_widget_->GetNativeWindow()); +} + +void WindowSelector::PositionWindows(bool animate) { + for (std::unique_ptr<WindowGrid>& grid : grid_list_) + grid->PositionWindows(animate); +} + +void WindowSelector::RepositionTextFilterOnDisplayMetricsChange() { + WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow(); + const gfx::Rect rect = GetTextFilterPosition(root_window); + text_filter_bottom_ = rect.bottom() + kTextFieldBottomMargin; + text_filter_widget_->SetBounds(rect); + + gfx::Transform transform; + transform.Translate( + 0, text_filter_string_length_ == 0 ? -text_filter_bottom_ : 0); + WmWindow* text_filter_window = GetTextFilterWidgetWindow(); + text_filter_window->SetOpacity(text_filter_string_length_ == 0 ? 0 : 1); + text_filter_window->SetTransform(transform); +} + +void WindowSelector::ResetFocusRestoreWindow(bool focus) { + if (!restore_focus_window_) + return; + if (focus) { + base::AutoReset<bool> restoring_focus(&ignore_activations_, true); + restore_focus_window_->Activate(); + } + // If the window is in the observed_windows_ list it needs to continue to be + // observed. + if (observed_windows_.find(restore_focus_window_) == + observed_windows_.end()) { + restore_focus_window_->aura_window()->RemoveObserver(this); + } + restore_focus_window_ = nullptr; +} + +void WindowSelector::Move(Direction direction, bool animate) { + // Direction to move if moving past the end of a display. + int display_direction = (direction == RIGHT || direction == DOWN) ? 1 : -1; + + // If this is the first move and it's going backwards, start on the last + // display. + if (display_direction == -1 && !grid_list_.empty() && + !grid_list_[selected_grid_index_]->is_selecting()) { + selected_grid_index_ = grid_list_.size() - 1; + } + + // Keep calling Move() on the grids until one of them reports no overflow or + // we made a full cycle on all the grids. + for (size_t i = 0; i <= grid_list_.size() && + grid_list_[selected_grid_index_]->Move(direction, animate); + i++) { + selected_grid_index_ = + (selected_grid_index_ + display_direction + grid_list_.size()) % + grid_list_.size(); + } +} + +} // namespace ash
diff --git a/ash/common/wm/overview/window_selector.h b/ash/common/wm/overview/window_selector.h new file mode 100644 index 0000000..a5cb743 --- /dev/null +++ b/ash/common/wm/overview/window_selector.h
@@ -0,0 +1,200 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_H_ +#define ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <set> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/wm_activation_observer.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "ui/aura/window_observer.h" +#include "ui/display/display_observer.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/views/controls/textfield/textfield_controller.h" + +namespace views { +class Textfield; +class Widget; +} + +namespace ash { +class WindowSelectorDelegate; +class WindowSelectorItem; +class WindowSelectorTest; +class WindowGrid; + +// The WindowSelector shows a grid of all of your windows, allowing to select +// one by clicking or tapping on it. +class ASH_EXPORT WindowSelector : public display::DisplayObserver, + public aura::WindowObserver, + public WmActivationObserver, + public views::TextfieldController { + public: + // Returns true if the window can be selected in overview mode. + static bool IsSelectable(WmWindow* window); + + enum Direction { LEFT, UP, RIGHT, DOWN }; + + using WindowList = std::vector<WmWindow*>; + + explicit WindowSelector(WindowSelectorDelegate* delegate); + ~WindowSelector() override; + + // Initialize with the windows that can be selected. + void Init(const WindowList& windows); + + // Perform cleanup that cannot be done in the destructor. + void Shutdown(); + + // Cancels window selection. + void CancelSelection(); + + // Called when the last window selector item from a grid is deleted. + void OnGridEmpty(WindowGrid* grid); + + // Moves the current selection by |increment| items. Positive values of + // |increment| move the selection forward, negative values move it backward. + void IncrementSelection(int increment); + + // Accepts current selection if any. Returns true if a selection was made, + // false otherwise. + bool AcceptSelection(); + + // Activates |item's| window. + void SelectWindow(WindowSelectorItem* item); + + // Called when |window| is about to get closed. + void WindowClosing(WindowSelectorItem* window); + + WindowSelectorDelegate* delegate() { return delegate_; } + + bool restoring_minimized_windows() const { + return restoring_minimized_windows_; + } + + int text_filter_bottom() const { return text_filter_bottom_; } + + bool is_shut_down() const { return is_shut_down_; } + + // display::DisplayObserver: + void OnDisplayAdded(const display::Display& display) override; + void OnDisplayRemoved(const display::Display& display) override; + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t metrics) override; + + // aura::WindowObserver: + void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; + void OnWindowDestroying(aura::Window* window) override; + + // WmActivationObserver + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override; + void OnAttemptToReactivateWindow(WmWindow* request_active, + WmWindow* actual_active) override; + + // views::TextfieldController: + void ContentsChanged(views::Textfield* sender, + const base::string16& new_contents) override; + bool HandleKeyEvent(views::Textfield* sender, + const ui::KeyEvent& key_event) override; + + private: + friend class WindowSelectorTest; + + // Returns the WmWindow for |text_filter_widget_|. + WmWindow* GetTextFilterWidgetWindow(); + + // Position all of the windows in the overview. + void PositionWindows(bool animate); + + // Repositions and resizes |text_filter_widget_| on + // DisplayMetricsChanged event. + void RepositionTextFilterOnDisplayMetricsChange(); + + // |focus|, restores focus to the stored window. + void ResetFocusRestoreWindow(bool focus); + + // Helper function that moves the selection widget to |direction| on the + // corresponding window grid. + void Move(Direction direction, bool animate); + + // Removes all observers that were registered during construction and/or + // initialization. + void RemoveAllObservers(); + + // Tracks observed windows. + std::set<WmWindow*> observed_windows_; + + // Weak pointer to the selector delegate which will be called when a + // selection is made. + WindowSelectorDelegate* delegate_; + + // A weak pointer to the window which was focused on beginning window + // selection. If window selection is canceled the focus should be restored to + // this window. + WmWindow* restore_focus_window_; + + // True when performing operations that may cause window activations. This is + // used to prevent handling the resulting expected activation. + bool ignore_activations_; + + // List of all the window overview grids, one for each root window. + std::vector<std::unique_ptr<WindowGrid>> grid_list_; + + // Tracks the index of the root window the selection widget is in. + size_t selected_grid_index_; + + // The following variables are used for metric collection purposes. All of + // them refer to this particular overview session and are not cumulative: + // The time when overview was started. + base::Time overview_start_time_; + + // The number of arrow key presses. + size_t num_key_presses_; + + // The number of items in the overview. + size_t num_items_; + + // Indicates if the text filter is shown on screen (rather than above it). + bool showing_text_filter_; + + // Window text filter widget. As the user writes on it, we filter the items + // in the overview. It is also responsible for handling overview key events, + // such as enter key to select. + std::unique_ptr<views::Widget> text_filter_widget_; + + // Image used for text filter textfield. + gfx::ImageSkia search_image_; + + // The current length of the string entered into the text filtering textfield. + size_t text_filter_string_length_; + + // The number of times the text filtering textfield has been cleared of text + // during this overview mode session. + size_t num_times_textfield_cleared_; + + // Tracks whether minimized windows are currently being restored for overview + // mode. + bool restoring_minimized_windows_; + + // The distance between the top edge of the screen and the bottom edge of + // the text filtering textfield. + int text_filter_bottom_; + + bool is_shut_down_ = false; + + DISALLOW_COPY_AND_ASSIGN(WindowSelector); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_H_
diff --git a/ash/common/wm/overview/window_selector_controller.cc b/ash/common/wm/overview/window_selector_controller.cc new file mode 100644 index 0000000..2c8b4efa --- /dev/null +++ b/ash/common/wm/overview/window_selector_controller.cc
@@ -0,0 +1,134 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/window_selector_controller.h" + +#include <vector> + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_selector.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/metrics/histogram_macros.h" + +namespace ash { + +WindowSelectorController::WindowSelectorController() {} + +WindowSelectorController::~WindowSelectorController() { + // Destroy widgets that may be still animating if shell shuts down soon after + // exiting overview mode. + for (std::unique_ptr<DelayedAnimationObserver>& animation_observer : + delayed_animations_) { + animation_observer->Shutdown(); + } +} + +// static +bool WindowSelectorController::CanSelect() { + // Don't allow a window overview if the screen is locked or a modal dialog is + // open or running in kiosk app session. + WmShell* wm_shell = WmShell::Get(); + SessionStateDelegate* session_state_delegate = + wm_shell->GetSessionStateDelegate(); + SystemTrayDelegate* system_tray_delegate = wm_shell->system_tray_delegate(); + return session_state_delegate->IsActiveUserSessionStarted() && + !session_state_delegate->IsScreenLocked() && + !wm_shell->IsSystemModalWindowOpen() && !wm_shell->IsPinned() && + system_tray_delegate->GetUserLoginStatus() != LoginStatus::KIOSK_APP && + system_tray_delegate->GetUserLoginStatus() != + LoginStatus::ARC_KIOSK_APP; +} + +bool WindowSelectorController::ToggleOverview() { + if (IsSelecting()) { + OnSelectionEnded(); + } else { + // Don't start overview if window selection is not allowed. + if (!CanSelect()) + return false; + + std::vector<WmWindow*> windows = + WmShell::Get()->mru_window_tracker()->BuildMruWindowList(); + auto end = + std::remove_if(windows.begin(), windows.end(), + std::not1(std::ptr_fun(&WindowSelector::IsSelectable))); + windows.resize(end - windows.begin()); + + // Don't enter overview mode with no windows. + if (windows.empty()) + return false; + + WmShell::Get()->OnOverviewModeStarting(); + window_selector_.reset(new WindowSelector(this)); + window_selector_->Init(windows); + OnSelectionStarted(); + } + return true; +} + +bool WindowSelectorController::IsSelecting() const { + return window_selector_.get() != NULL; +} + +void WindowSelectorController::IncrementSelection(int increment) { + DCHECK(IsSelecting()); + window_selector_->IncrementSelection(increment); +} + +bool WindowSelectorController::AcceptSelection() { + DCHECK(IsSelecting()); + return window_selector_->AcceptSelection(); +} + +bool WindowSelectorController::IsRestoringMinimizedWindows() const { + return window_selector_.get() != NULL && + window_selector_->restoring_minimized_windows(); +} + +// TODO(flackr): Make WindowSelectorController observe the activation of +// windows, so we can remove WindowSelectorDelegate. +void WindowSelectorController::OnSelectionEnded() { + window_selector_->Shutdown(); + window_selector_.reset(); + last_selection_time_ = base::Time::Now(); + WmShell::Get()->OnOverviewModeEnded(); +} + +void WindowSelectorController::AddDelayedAnimationObserver( + std::unique_ptr<DelayedAnimationObserver> animation_observer) { + animation_observer->SetOwner(this); + delayed_animations_.push_back(std::move(animation_observer)); +} + +void WindowSelectorController::RemoveAndDestroyAnimationObserver( + DelayedAnimationObserver* animation_observer) { + class IsEqual { + public: + explicit IsEqual(DelayedAnimationObserver* animation_observer) + : animation_observer_(animation_observer) {} + bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) { + return (other.get() == animation_observer_); + } + + private: + const DelayedAnimationObserver* animation_observer_; + }; + delayed_animations_.erase( + std::remove_if(delayed_animations_.begin(), delayed_animations_.end(), + IsEqual(animation_observer)), + delayed_animations_.end()); +} + +void WindowSelectorController::OnSelectionStarted() { + if (!last_selection_time_.is_null()) { + UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse", + base::Time::Now() - last_selection_time_); + } +} + +} // namespace ash
diff --git a/ash/common/wm/overview/window_selector_controller.h b/ash/common/wm/overview/window_selector_controller.h new file mode 100644 index 0000000..830ee92 --- /dev/null +++ b/ash/common/wm/overview/window_selector_controller.h
@@ -0,0 +1,78 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ +#define ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ + +#include <list> +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/wm/overview/window_selector.h" +#include "ash/common/wm/overview/window_selector_delegate.h" +#include "base/macros.h" +#include "base/time/time.h" + +namespace ash { +class WindowSelector; +class WindowSelectorTest; + +// Manages a window selector which displays an overview of all windows and +// allows selecting a window to activate it. +class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate { + public: + WindowSelectorController(); + ~WindowSelectorController() override; + + // Returns true if selecting windows in an overview is enabled. This is false + // at certain times, such as when the lock screen is visible. + static bool CanSelect(); + + // Attempts to toggle overview mode and returns true if successful (showing + // overview would be unsuccessful if there are no windows to show). + bool ToggleOverview(); + + // Returns true if window selection mode is active. + bool IsSelecting() const; + + // Moves the current selection by |increment| items. Positive values of + // |increment| move the selection forward, negative values move it backward. + void IncrementSelection(int increment); + + // Accepts current selection if any. Returns true if a selection was made, + // false otherwise. + bool AcceptSelection(); + + // Returns true if overview mode is restoring minimized windows so that they + // are visible during overview mode. + bool IsRestoringMinimizedWindows() const; + + // WindowSelectorDelegate: + void OnSelectionEnded() override; + void AddDelayedAnimationObserver( + std::unique_ptr<DelayedAnimationObserver> animation) override; + void RemoveAndDestroyAnimationObserver( + DelayedAnimationObserver* animation) override; + + private: + friend class WindowSelectorTest; + + // Dispatched when window selection begins. + void OnSelectionStarted(); + + // Collection of DelayedAnimationObserver objects that own widgets that may be + // still animating after overview mode ends. If shell needs to shut down while + // those animations are in progress, the animations are shut down and the + // widgets destroyed. + std::vector<std::unique_ptr<DelayedAnimationObserver>> delayed_animations_; + std::unique_ptr<WindowSelector> window_selector_; + base::Time last_selection_time_; + + DISALLOW_COPY_AND_ASSIGN(WindowSelectorController); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_
diff --git a/ash/common/wm/overview/window_selector_delegate.h b/ash/common/wm/overview/window_selector_delegate.h new file mode 100644 index 0000000..655198d3 --- /dev/null +++ b/ash/common/wm/overview/window_selector_delegate.h
@@ -0,0 +1,54 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ +#define ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "base/compiler_specific.h" + +namespace ash { + +class WindowSelectorDelegate; + +class ASH_EXPORT DelayedAnimationObserver { + public: + virtual ~DelayedAnimationObserver() {} + + // Sets an |owner| that can be notified when the animation that |this| + // observes completes. + virtual void SetOwner(WindowSelectorDelegate* owner) = 0; + + // Can be called by the |owner| to delete the owned widget. The |owner| is + // then responsible for deleting |this| instance of the + // DelayedAnimationObserver. + virtual void Shutdown() = 0; +}; + +// Implement this class to handle the selection event from WindowSelector. +class ASH_EXPORT WindowSelectorDelegate { + public: + // Invoked if selection is ended. + virtual void OnSelectionEnded() = 0; + + // Passes ownership of |animation_observer| to |this| delegate. + virtual void AddDelayedAnimationObserver( + std::unique_ptr<DelayedAnimationObserver> animation_observer) = 0; + + // Finds and erases |animation_observer| from the list deleting the widget + // owned by the |animation_observer|. + // This method should be called when a scheduled animation completes. + // If the animation completion callback is a result of a window getting + // destroyed then the DelayedAnimationObserver::Shutdown() should be called + // first before destroying the window. + virtual void RemoveAndDestroyAnimationObserver( + DelayedAnimationObserver* animation_observer) = 0; + + protected: + virtual ~WindowSelectorDelegate() {} +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_
diff --git a/ash/common/wm/overview/window_selector_item.cc b/ash/common/wm/overview/window_selector_item.cc new file mode 100644 index 0000000..f6a7b94 --- /dev/null +++ b/ash/common/wm/overview/window_selector_item.cc
@@ -0,0 +1,764 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/overview/window_selector_item.h" + +#include <algorithm> +#include <vector> + +#include "ash/common/material_design/material_design_controller.h" +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/wm/overview/cleanup_animation_observer.h" +#include "ash/common/wm/overview/overview_animation_type.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h" +#include "ash/common/wm/overview/scoped_transform_overview_window.h" +#include "ash/common/wm/overview/window_selector.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/root_window_controller.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/auto_reset.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/time/time.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/compositor/layer_animation_sequence.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/gfx/animation/slide_animation.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/geometry/safe_integer_conversions.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/transform_util.h" +#include "ui/strings/grit/ui_strings.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/window/non_client_view.h" +#include "ui/wm/core/shadow.h" +#include "ui/wm/core/window_util.h" + +namespace ash { + +namespace { + +// In the conceptual overview table, the window margin is the space reserved +// around the window within the cell. This margin does not overlap so the +// closest distance between adjacent windows will be twice this amount. +static const int kWindowMargin = 5; + +// Cover the transformed window including the gaps between the windows with a +// transparent shield to block the input events from reaching the transformed +// window while in overview. +static const int kWindowSelectorMargin = kWindowMargin * 2; + +// Foreground label color. +static const SkColor kLabelColor = SK_ColorWHITE; + +// TODO(tdanderson): Move this to a central location. +static const SkColor kCloseButtonColor = SK_ColorWHITE; + +// Label background color once in overview mode. +static const SkColor kLabelBackgroundColor = SkColorSetARGB(25, 255, 255, 255); + +// Label background color when exiting overview mode. +static const SkColor kLabelExitColor = SkColorSetARGB(255, 90, 90, 90); + +// Corner radius for the selection tiles. +static int kLabelBackgroundRadius = 2; + +// Horizontal padding for the label, on both sides. +static const int kHorizontalLabelPadding = 8; + +// Height of an item header. +static const int kHeaderHeight = 32; + +// Opacity for dimmed items. +static const float kDimmedItemOpacity = 0.5f; + +// Opacity for fading out during closing a window. +static const float kClosingItemOpacity = 0.8f; + +// Opacity for the item header. +static const float kHeaderOpacity = + (SkColorGetA(kLabelBackgroundColor) / 255.f); + +// Duration it takes for the header to shift from opaque header color to +// |kLabelBackgroundColor|. +static const int kSelectorColorSlideMilliseconds = 240; + +// Duration of background opacity transition for the selected label. +static const int kSelectorFadeInMilliseconds = 350; + +// Duration of background opacity transition when exiting overview mode. +static const int kExitFadeInMilliseconds = 30; + +// Before closing a window animate both the window and the caption to shrink by +// this fraction of size. +static const float kPreCloseScale = 0.02f; + +// Convenience method to fade in a Window with predefined animation settings. +// Note: The fade in animation will occur after a delay where the delay is how +// long the lay out animations take. +void SetupFadeInAfterLayout(views::Widget* widget) { + WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); + window->SetOpacity(0.0f); + std::unique_ptr<ScopedOverviewAnimationSettings> + scoped_overview_animation_settings = + ScopedOverviewAnimationSettingsFactory::Get() + ->CreateOverviewAnimationSettings( + OverviewAnimationType:: + OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, + window); + window->SetOpacity(1.0f); +} + +// A Button that has a listener and listens to mouse clicks on the visible part +// of an overview window. +class ShieldButton : public views::CustomButton { + public: + ShieldButton(views::ButtonListener* listener, const base::string16& name) + : views::CustomButton(listener) { + SetAccessibleName(name); + } + ~ShieldButton() override {} + + // When WindowSelectorItem (which is a ButtonListener) is destroyed, its + // |item_widget_| is allowed to stay around to complete any animations. + // Resetting the listener in all views that are targeted by events is + // necessary to prevent a crash when a user clicks on the fading out widget + // after the WindowSelectorItem has been destroyed. + void ResetListener() { listener_ = nullptr; } + + protected: + // views::View: + const char* GetClassName() const override { return "ShieldButton"; } + + private: + DISALLOW_COPY_AND_ASSIGN(ShieldButton); +}; + +} // namespace + +WindowSelectorItem::OverviewCloseButton::OverviewCloseButton( + views::ButtonListener* listener) + : views::ImageButton(listener) { + SetImage(views::CustomButton::STATE_NORMAL, + gfx::CreateVectorIcon(kWindowControlCloseIcon, kCloseButtonColor)); + SetImageAlignment(views::ImageButton::ALIGN_CENTER, + views::ImageButton::ALIGN_MIDDLE); + SetMinimumImageSize(gfx::Size(kHeaderHeight, kHeaderHeight)); +} + +WindowSelectorItem::OverviewCloseButton::~OverviewCloseButton() {} + +// A View having rounded top corners and a specified background color which is +// only painted within the bounds defined by the rounded corners. +// This class coordinates the transitions of the overview mode header when +// entering the overview mode. Those animations are: +// - Opacity animation. The header is initially same color as the original +// window's header. It starts as transparent and is faded in. When the full +// opacity is reached the original header is hidden (which is nearly +// imperceptable because this view obscures the original header) and a color +// animation starts. +// - Color animation is used to change the color from the opaque color of the +// original window's header to semi-transparent color of the overview mode +// header (on entry to overview). It is also used on exit from overview to +// quickly change the color to a close opaque color in parallel with an +// opacity transition to mask the original header reappearing. +class WindowSelectorItem::RoundedContainerView + : public views::View, + public gfx::AnimationDelegate, + public ui::LayerAnimationObserver { + public: + RoundedContainerView(WindowSelectorItem* item, + WmWindow* item_window, + int corner_radius, + SkColor background) + : item_(item), + item_window_(item_window), + corner_radius_(corner_radius), + initial_color_(background), + target_color_(background), + current_value_(0), + layer_(nullptr), + animation_(new gfx::SlideAnimation(this)) { + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + } + + ~RoundedContainerView() override { StopObservingLayerAnimations(); } + + void OnItemRestored() { + item_ = nullptr; + item_window_ = nullptr; + } + + // Starts observing layer animations so that actions can be taken when + // particular animations (opacity) complete. It should only be called once + // when the initial fade in animation is started. + void ObserveLayerAnimations(ui::Layer* layer) { + DCHECK(!layer_); + layer_ = layer; + layer_->GetAnimator()->AddObserver(this); + } + + // Stops observing layer animations + void StopObservingLayerAnimations() { + if (!layer_) + return; + layer_->GetAnimator()->RemoveObserver(this); + layer_ = nullptr; + } + + // Used by tests to set animation state. + gfx::SlideAnimation* animation() { return animation_.get(); } + + void set_color(SkColor target_color) { target_color_ = target_color; } + + // Starts a color animation using |tween_type|. The animation will change the + // color from |initial_color_| to |target_color_| over |duration| specified + // in milliseconds. + // This animation can start once the implicit layer fade-in opacity animation + // is completed. It is used to transition color from the opaque original + // window header color to |kLabelBackgroundColor| on entry into overview mode + // and from |kLabelBackgroundColor| back to the original window header color + // on exit from the overview mode. + void AnimateColor(gfx::Tween::Type tween_type, int duration) { + DCHECK(!layer_); // layer animations should be completed. + animation_->SetSlideDuration(duration); + animation_->SetTweenType(tween_type); + animation_->Reset(0); + animation_->Show(); + + // Tests complete animations immediately. Emulate by invoking the callback. + if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() == + ui::ScopedAnimationDurationScaleMode::ZERO_DURATION) { + AnimationEnded(animation_.get()); + } + } + + // Changes the view opacity by animating its background color. The animation + // will change the alpha value in |target_color_| from its current value to + // |opacity| * 255 but preserve the RGB values. + void AnimateBackgroundOpacity(float opacity) { + animation_->SetSlideDuration(kSelectorFadeInMilliseconds); + animation_->SetTweenType(gfx::Tween::EASE_OUT); + animation_->Reset(0); + animation_->Show(); + target_color_ = SkColorSetA(target_color_, opacity * 255); + } + + // views::View: + void OnPaint(gfx::Canvas* canvas) override { + views::View::OnPaint(canvas); + SkScalar radius = SkIntToScalar(corner_radius_); + const SkScalar kRadius[8] = {radius, radius, radius, radius, 0, 0, 0, 0}; + SkPath path; + gfx::Rect bounds(size()); + path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); + + cc::PaintFlags flags; + flags.setAntiAlias(true); + canvas->ClipPath(path, true); + + SkColor target_color = initial_color_; + if (target_color_ != target_color) { + target_color = color_utils::AlphaBlend(target_color_, initial_color_, + current_value_); + } + canvas->DrawColor(target_color); + } + + const char* GetClassName() const override { return "RoundedContainerView"; } + + private: + // gfx::AnimationDelegate: + void AnimationEnded(const gfx::Animation* animation) override { + initial_color_ = target_color_; + // Tabbed browser windows show the overview mode header behind the window + // during the initial animation. Once the initial fade-in completes and the + // overview header is fully exposed update stacking to keep the label above + // the item which prevents input events from reaching the window. + WmWindow* widget_window = WmWindow::Get(GetWidget()->GetNativeWindow()); + if (widget_window && item_window_) + widget_window->GetParent()->StackChildAbove(widget_window, item_window_); + item_window_ = nullptr; + } + + void AnimationProgressed(const gfx::Animation* animation) override { + current_value_ = animation_->CurrentValueBetween(0, 255); + SchedulePaint(); + } + + void AnimationCanceled(const gfx::Animation* animation) override { + item_window_ = nullptr; + initial_color_ = target_color_; + current_value_ = 255; + SchedulePaint(); + } + + // ui::LayerAnimationObserver: + void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override { + if (0 != (sequence->properties() & + ui::LayerAnimationElement::AnimatableProperty::OPACITY)) { + if (item_) + item_->HideHeader(); + StopObservingLayerAnimations(); + AnimateColor(gfx::Tween::EASE_IN, kSelectorColorSlideMilliseconds); + } + } + + void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override { + if (0 != (sequence->properties() & + ui::LayerAnimationElement::AnimatableProperty::OPACITY)) { + StopObservingLayerAnimations(); + } + } + + void OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) override {} + + WindowSelectorItem* item_; + WmWindow* item_window_; + int corner_radius_; + SkColor initial_color_; + SkColor target_color_; + int current_value_; + ui::Layer* layer_; + std::unique_ptr<gfx::SlideAnimation> animation_; + + DISALLOW_COPY_AND_ASSIGN(RoundedContainerView); +}; + +// A Container View that has a ShieldButton to listen to events. The +// ShieldButton covers most of the View except for the transparent gap between +// the windows and is visually transparent. The ShieldButton owns a background +// non-transparent view positioned at the ShieldButton top. The background view +// in its turn owns an item text label and a close button. +// The text label does not receive events, however the close button is higher in +// Z-order than its parent and receives events forwarding them to the same +// |listener| (i.e. WindowSelectorItem::ButtonPressed()). +class WindowSelectorItem::CaptionContainerView : public views::View { + public: + CaptionContainerView(ButtonListener* listener, + views::Label* label, + views::ImageButton* close_button, + WindowSelectorItem::RoundedContainerView* background) + : listener_button_(new ShieldButton(listener, label->text())), + background_(background), + label_(label), + close_button_(close_button) { + background_->AddChildView(label_); + background_->AddChildView(close_button_); + listener_button_->AddChildView(background_); + AddChildView(listener_button_); + } + + ShieldButton* listener_button() { return listener_button_; } + + protected: + // views::View: + void Layout() override { + // Position close button in the top right corner sized to its icon size and + // the label in the top left corner as tall as the button and extending to + // the button's left edge. + // The rest of this container view serves as a shield to prevent input + // events from reaching the transformed window in overview. + gfx::Rect bounds(GetLocalBounds()); + bounds.Inset(kWindowSelectorMargin, kWindowSelectorMargin); + listener_button_->SetBoundsRect(bounds); + + const int visible_height = close_button_->GetPreferredSize().height(); + gfx::Rect background_bounds(gfx::Rect(bounds.size())); + background_bounds.set_height(visible_height); + background_->SetBoundsRect(background_bounds); + + bounds = background_bounds; + bounds.Inset(kHorizontalLabelPadding, 0, + kHorizontalLabelPadding + visible_height, 0); + label_->SetBoundsRect(bounds); + + bounds = background_bounds; + bounds.set_x(bounds.width() - visible_height); + bounds.set_width(visible_height); + close_button_->SetBoundsRect(bounds); + } + + const char* GetClassName() const override { return "CaptionContainerView"; } + + private: + ShieldButton* listener_button_; + WindowSelectorItem::RoundedContainerView* background_; + views::Label* label_; + views::ImageButton* close_button_; + + DISALLOW_COPY_AND_ASSIGN(CaptionContainerView); +}; + +WindowSelectorItem::WindowSelectorItem(WmWindow* window, + WindowSelector* window_selector) + : dimmed_(false), + root_window_(window->GetRootWindow()), + transform_window_(window), + in_bounds_update_(false), + selected_(false), + caption_container_view_(nullptr), + label_view_(nullptr), + close_button_(new OverviewCloseButton(this)), + window_selector_(window_selector), + background_view_(nullptr) { + CreateWindowLabel(window->GetTitle()); + GetWindow()->aura_window()->AddObserver(this); +} + +WindowSelectorItem::~WindowSelectorItem() { + GetWindow()->aura_window()->RemoveObserver(this); +} + +WmWindow* WindowSelectorItem::GetWindow() { + return transform_window_.window(); +} + +void WindowSelectorItem::RestoreWindow() { + caption_container_view_->listener_button()->ResetListener(); + close_button_->ResetListener(); + transform_window_.RestoreWindow(); + if (background_view_) { + background_view_->OnItemRestored(); + background_view_ = nullptr; + } + UpdateHeaderLayout( + HeaderFadeInMode::EXIT, + OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS); +} + +void WindowSelectorItem::EnsureVisible() { + transform_window_.EnsureVisible(); +} + +void WindowSelectorItem::Shutdown() { + if (transform_window_.GetTopInset()) { + // Activating a window (even when it is the window that was active before + // overview) results in stacking it at the top. Maintain the label window + // stacking position above the item to make the header transformation more + // gradual upon exiting the overview mode. + WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); + + // |widget_window| was originally created in the same container as the + // |transform_window_| but when closing overview the |transform_window_| + // could have been reparented if a drag was active. Only change stacking + // if the windows still belong to the same container. + if (widget_window->GetParent() == transform_window_.window()->GetParent()) { + widget_window->GetParent()->StackChildAbove(widget_window, + transform_window_.window()); + } + } + if (background_view_) { + background_view_->OnItemRestored(); + background_view_ = nullptr; + } + FadeOut(std::move(item_widget_)); +} + +void WindowSelectorItem::PrepareForOverview() { + transform_window_.PrepareForOverview(); + UpdateHeaderLayout(HeaderFadeInMode::ENTER, + OverviewAnimationType::OVERVIEW_ANIMATION_NONE); +} + +bool WindowSelectorItem::Contains(const WmWindow* target) const { + return transform_window_.Contains(target); +} + +void WindowSelectorItem::SetBounds(const gfx::Rect& target_bounds, + OverviewAnimationType animation_type) { + if (in_bounds_update_) + return; + base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true); + target_bounds_ = target_bounds; + + gfx::Rect inset_bounds(target_bounds); + inset_bounds.Inset(kWindowMargin, kWindowMargin); + SetItemBounds(inset_bounds, animation_type); + + // SetItemBounds is called before UpdateHeaderLayout so the header can + // properly use the updated windows bounds. + UpdateHeaderLayout(HeaderFadeInMode::UPDATE, animation_type); +} + +void WindowSelectorItem::SetSelected(bool selected) { + selected_ = selected; + background_view_->AnimateBackgroundOpacity(selected ? 0.f : kHeaderOpacity); +} + +void WindowSelectorItem::SendAccessibleSelectionEvent() { + caption_container_view_->listener_button()->NotifyAccessibilityEvent( + ui::AX_EVENT_SELECTION, true); +} + +void WindowSelectorItem::CloseWindow() { + gfx::Rect inset_bounds(target_bounds_); + inset_bounds.Inset(target_bounds_.width() * kPreCloseScale, + target_bounds_.height() * kPreCloseScale); + OverviewAnimationType animation_type = + OverviewAnimationType::OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM; + // Scale down both the window and label. + SetBounds(inset_bounds, animation_type); + // First animate opacity to an intermediate value concurrently with the + // scaling animation. + AnimateOpacity(kClosingItemOpacity, animation_type); + + // Fade out the window and the label, effectively hiding them. + AnimateOpacity(0.0, + OverviewAnimationType::OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM); + transform_window_.Close(); +} + +void WindowSelectorItem::HideHeader() { + transform_window_.HideHeader(); +} + +void WindowSelectorItem::OnMinimizedStateChanged() { + transform_window_.UpdateMirrorWindowForMinimizedState(); +} + +void WindowSelectorItem::SetDimmed(bool dimmed) { + dimmed_ = dimmed; + SetOpacity(dimmed ? kDimmedItemOpacity : 1.0f); +} + +void WindowSelectorItem::ButtonPressed(views::Button* sender, + const ui::Event& event) { + if (sender == close_button_) { + WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_CLOSE_BUTTON); + CloseWindow(); + return; + } + CHECK(sender == caption_container_view_->listener_button()); + window_selector_->SelectWindow(this); +} + +void WindowSelectorItem::OnWindowDestroying(aura::Window* window) { + window->RemoveObserver(this); + transform_window_.OnWindowDestroyed(); +} + +void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) { + // TODO(flackr): Maybe add the new title to a vector of titles so that we can + // filter any of the titles the window had while in the overview session. + label_view_->SetText(window->GetTitle()); + UpdateAccessibilityName(); +} + +float WindowSelectorItem::GetItemScale(const gfx::Size& size) { + gfx::Size inset_size(size.width(), size.height() - 2 * kWindowMargin); + return ScopedTransformOverviewWindow::GetItemScale( + transform_window_.GetTargetBoundsInScreen().size(), inset_size, + transform_window_.GetTopInset(), + close_button_->GetPreferredSize().height()); +} + +gfx::Rect WindowSelectorItem::GetTargetBoundsInScreen() const { + return transform_window_.GetTargetBoundsInScreen(); +} + +void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds, + OverviewAnimationType animation_type) { + DCHECK(root_window_ == GetWindow()->GetRootWindow()); + gfx::Rect screen_rect = transform_window_.GetTargetBoundsInScreen(); + + // Avoid division by zero by ensuring screen bounds is not empty. + gfx::Size screen_size(screen_rect.size()); + screen_size.SetToMax(gfx::Size(1, 1)); + screen_rect.set_size(screen_size); + + const int top_view_inset = transform_window_.GetTopInset(); + const int title_height = close_button_->GetPreferredSize().height(); + gfx::Rect selector_item_bounds = + ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio( + screen_rect, target_bounds, top_view_inset, title_height); + gfx::Transform transform = ScopedTransformOverviewWindow::GetTransformForRect( + screen_rect, selector_item_bounds); + ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; + transform_window_.BeginScopedAnimation(animation_type, &animation_settings); + transform_window_.SetTransform(root_window_, transform); +} + +void WindowSelectorItem::SetOpacity(float opacity) { + item_widget_->SetOpacity(opacity); + if (background_view_) { + background_view_->AnimateBackgroundOpacity( + selected_ ? 0.f : kHeaderOpacity * opacity); + } + transform_window_.SetOpacity(opacity); +} + +void WindowSelectorItem::CreateWindowLabel(const base::string16& title) { + background_view_ = new RoundedContainerView(this, transform_window_.window(), + kLabelBackgroundRadius, + transform_window_.GetTopColor()); + // |background_view_| will get added as a child to CaptionContainerView. + views::Widget::InitParams params_label; + params_label.type = views::Widget::InitParams::TYPE_POPUP; + params_label.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params_label.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params_label.visible_on_all_workspaces = true; + params_label.layer_type = ui::LAYER_NOT_DRAWN; + params_label.name = "OverviewModeLabel"; + params_label.activatable = + views::Widget::InitParams::Activatable::ACTIVATABLE_DEFAULT; + params_label.accept_events = true; + item_widget_.reset(new views::Widget); + root_window_->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + item_widget_.get(), + transform_window_.window()->GetParent()->GetShellWindowId(), + ¶ms_label); + item_widget_->set_focus_on_creation(false); + item_widget_->Init(params_label); + WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); + if (transform_window_.GetTopInset()) { + // For windows with headers the overview header fades in above the + // original window header. + widget_window->GetParent()->StackChildAbove(widget_window, + transform_window_.window()); + } else { + // For tabbed windows the overview header slides from behind. The stacking + // is then corrected when the animation completes. + widget_window->GetParent()->StackChildBelow(widget_window, + transform_window_.window()); + } + label_view_ = new views::Label(title); + label_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label_view_->SetAutoColorReadabilityEnabled(false); + label_view_->SetEnabledColor(kLabelColor); + // Tell the label what color it will be drawn onto. It will use whether the + // background color is opaque or transparent to decide whether to use + // subpixel rendering. Does not actually set the label's background color. + label_view_->SetBackgroundColor(kLabelBackgroundColor); + + caption_container_view_ = new CaptionContainerView( + this, label_view_, close_button_, background_view_); + item_widget_->SetContentsView(caption_container_view_); + label_view_->SetVisible(false); + item_widget_->SetOpacity(0); + item_widget_->Show(); + item_widget_->GetLayer()->SetMasksToBounds(false); +} + +void WindowSelectorItem::UpdateHeaderLayout( + HeaderFadeInMode mode, + OverviewAnimationType animation_type) { + gfx::Rect transformed_window_bounds = root_window_->ConvertRectFromScreen( + transform_window_.GetTransformedBounds()); + + gfx::Rect label_rect(close_button_->GetPreferredSize()); + label_rect.set_width(transformed_window_bounds.width()); + // For tabbed windows the initial bounds of the caption are set such that it + // appears to be "growing" up from the window content area. + label_rect.set_y( + (mode != HeaderFadeInMode::ENTER || transform_window_.GetTopInset()) + ? -label_rect.height() + : 0); + if (background_view_) { + if (mode == HeaderFadeInMode::ENTER) { + background_view_->ObserveLayerAnimations(item_widget_->GetLayer()); + background_view_->set_color(kLabelBackgroundColor); + // The color will be animated only once the label widget is faded in. + } else if (mode == HeaderFadeInMode::EXIT) { + // Normally the observer is disconnected when the fade-in animations + // complete but some tests invoke animations with |NON_ZERO_DURATION| + // without waiting for completion so do it here. + background_view_->StopObservingLayerAnimations(); + // Make the header visible above the window. It will be faded out when + // the Shutdown() is called. + background_view_->AnimateColor(gfx::Tween::EASE_OUT, + kExitFadeInMilliseconds); + background_view_->set_color(kLabelExitColor); + } + } + if (!label_view_->visible()) { + label_view_->SetVisible(true); + SetupFadeInAfterLayout(item_widget_.get()); + } + WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); + std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings = + ScopedOverviewAnimationSettingsFactory::Get() + ->CreateOverviewAnimationSettings(animation_type, widget_window); + // |widget_window| covers both the transformed window and the header + // as well as the gap between the windows to prevent events from reaching + // the window including its sizing borders. + if (mode != HeaderFadeInMode::ENTER) { + label_rect.set_height(close_button_->GetPreferredSize().height() + + transformed_window_bounds.height()); + } + label_rect.Inset(-kWindowSelectorMargin, -kWindowSelectorMargin); + widget_window->SetBounds(label_rect); + gfx::Transform label_transform; + label_transform.Translate(transformed_window_bounds.x(), + transformed_window_bounds.y()); + widget_window->SetTransform(label_transform); +} + +void WindowSelectorItem::AnimateOpacity(float opacity, + OverviewAnimationType animation_type) { + DCHECK_GE(opacity, 0.f); + DCHECK_LE(opacity, 1.f); + ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; + transform_window_.BeginScopedAnimation(animation_type, &animation_settings); + transform_window_.SetOpacity(opacity); + + const float header_opacity = selected_ ? 0.f : kHeaderOpacity * opacity; + WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); + std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings_label = + ScopedOverviewAnimationSettingsFactory::Get() + ->CreateOverviewAnimationSettings(animation_type, widget_window); + widget_window->SetOpacity(header_opacity); +} + +void WindowSelectorItem::UpdateAccessibilityName() { + caption_container_view_->listener_button()->SetAccessibleName( + GetWindow()->GetTitle()); +} + +void WindowSelectorItem::FadeOut(std::unique_ptr<views::Widget> widget) { + widget->SetOpacity(1.f); + + // Fade out the widget. This animation continues past the lifetime of |this|. + WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); + std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings = + ScopedOverviewAnimationSettingsFactory::Get() + ->CreateOverviewAnimationSettings( + OverviewAnimationType:: + OVERVIEW_ANIMATION_EXIT_OVERVIEW_MODE_FADE_OUT, + widget_window); + // CleanupAnimationObserver will delete itself (and the widget) when the + // opacity animation is complete. + // Ownership over the observer is passed to the window_selector_->delegate() + // which has longer lifetime so that animations can continue even after the + // overview mode is shut down. + views::Widget* widget_ptr = widget.get(); + std::unique_ptr<CleanupAnimationObserver> observer( + new CleanupAnimationObserver(std::move(widget))); + animation_settings->AddObserver(observer.get()); + window_selector_->delegate()->AddDelayedAnimationObserver( + std::move(observer)); + widget_ptr->SetOpacity(0.f); +} + +gfx::SlideAnimation* WindowSelectorItem::GetBackgroundViewAnimation() { + return background_view_ ? background_view_->animation() : nullptr; +} + +WmWindow* WindowSelectorItem::GetOverviewWindowForMinimizedStateForTest() { + return transform_window_.GetOverviewWindowForMinimizedState(); +} + +} // namespace ash
diff --git a/ash/common/wm/overview/window_selector_item.h b/ash/common/wm/overview/window_selector_item.h new file mode 100644 index 0000000..097cc8b4 --- /dev/null +++ b/ash/common/wm/overview/window_selector_item.h
@@ -0,0 +1,224 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ +#define ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/overview/scoped_transform_overview_window.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/label.h" +#include "ui/views/widget/widget.h" + +namespace gfx { +class SlideAnimation; +} + +namespace views { +class ImageButton; +} + +namespace ash { + +class WindowSelector; +class WmWindow; + +// This class represents an item in overview mode. +class ASH_EXPORT WindowSelectorItem : public views::ButtonListener, + public aura::WindowObserver { + public: + // An image button with a close window icon. + class OverviewCloseButton : public views::ImageButton { + public: + explicit OverviewCloseButton(views::ButtonListener* listener); + ~OverviewCloseButton() override; + + // Resets the listener so that the listener can go out of scope. + void ResetListener() { listener_ = nullptr; } + + private: + DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton); + }; + + WindowSelectorItem(WmWindow* window, WindowSelector* window_selector); + ~WindowSelectorItem() override; + + WmWindow* GetWindow(); + + // Returns the root window on which this item is shown. + WmWindow* root_window() { return root_window_; } + + // Returns true if |target| is contained in this WindowSelectorItem. + bool Contains(const WmWindow* target) const; + + // Restores and animates the managed window to its non overview mode state. + void RestoreWindow(); + + // Ensures that a possibly minimized window becomes visible after restore. + void EnsureVisible(); + + // Restores stacking of window captions above the windows, then fades out. + void Shutdown(); + + // Dispatched before beginning window overview. This will do any necessary + // one time actions such as restoring minimized windows. + void PrepareForOverview(); + + // Calculates and returns an optimal scale ratio. With MD this is only + // taking into account |size.height()| as the width can vary. Without MD this + // returns the scale that allows the item to fully fit within |size|. + float GetItemScale(const gfx::Size& size); + + // Returns the union of the original target bounds of all transformed windows + // managed by |this| item, i.e. all regular (normal or panel transient + // descendants of the window returned by GetWindow()). + gfx::Rect GetTargetBoundsInScreen() const; + + // Sets the bounds of this window selector item to |target_bounds| in the + // |root_window_| root window. The bounds change will be animated as specified + // by |animation_type|. + void SetBounds(const gfx::Rect& target_bounds, + OverviewAnimationType animation_type); + + // Activates or deactivates selection depending on |selected|. + // In selected state the item's caption is shown transparent and blends with + // the selection widget. + void SetSelected(bool selected); + + // Sends an accessibility event indicating that this window became selected + // so that it's highlighted and announced if accessibility features are + // enabled. + void SendAccessibleSelectionEvent(); + + // Closes |transform_window_|. + void CloseWindow(); + + // Hides the original window header. + void HideHeader(); + + // Called when the window is minimized or unminimized. + void OnMinimizedStateChanged(); + + // Sets if the item is dimmed in the overview. Changing the value will also + // change the visibility of the transform windows. + void SetDimmed(bool dimmed); + bool dimmed() const { return dimmed_; } + + const gfx::Rect& target_bounds() const { return target_bounds_; } + + // views::ButtonListener: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; + + // aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + void OnWindowTitleChanged(aura::Window* window) override; + + private: + class CaptionContainerView; + class RoundedContainerView; + friend class WindowSelectorTest; + + enum class HeaderFadeInMode { + ENTER, + UPDATE, + EXIT, + }; + + // Sets the bounds of this selector's items to |target_bounds| in + // |root_window_|. The bounds change will be animated as specified + // by |animation_type|. + void SetItemBounds(const gfx::Rect& target_bounds, + OverviewAnimationType animation_type); + + // Changes the opacity of all the windows the item owns. + void SetOpacity(float opacity); + + // Creates the window label. + void CreateWindowLabel(const base::string16& title); + + // Updates the close button's and title label's bounds. Any change in bounds + // will be animated from the current bounds to the new bounds as per the + // |animation_type|. |mode| allows distinguishing the first time update which + // allows setting the initial bounds properly or exiting overview to fade out + // gradually. + void UpdateHeaderLayout(HeaderFadeInMode mode, + OverviewAnimationType animation_type); + + // Animates opacity of the |transform_window_| and its caption to |opacity| + // using |animation_type|. + void AnimateOpacity(float opacity, OverviewAnimationType animation_type); + + // Updates the accessibility name to match the window title. + void UpdateAccessibilityName(); + + // Fades out a window caption when exiting overview mode. + void FadeOut(std::unique_ptr<views::Widget> widget); + + // Allows a test to directly set animation state. + gfx::SlideAnimation* GetBackgroundViewAnimation(); + + WmWindow* GetOverviewWindowForMinimizedStateForTest(); + + // True if the item is being shown in the overview, false if it's being + // filtered. + bool dimmed_; + + // The root window this item is being displayed on. + WmWindow* root_window_; + + // The contained Window's wrapper. + ScopedTransformOverviewWindow transform_window_; + + // The target bounds this selector item is fit within. + gfx::Rect target_bounds_; + + // True if running SetItemBounds. This prevents recursive calls resulting from + // the bounds update when calling ::wm::RecreateWindowLayers to copy + // a window layer for display on another monitor. + bool in_bounds_update_; + + // True when |this| item is visually selected. Item header is made transparent + // when the item is selected. + bool selected_; + + // A widget that covers the |transform_window_|. The widget has + // |caption_container_view_| as its contents view. The widget is backed by a + // NOT_DRAWN layer since most of its surface is transparent. + std::unique_ptr<views::Widget> item_widget_; + + // Container view that owns a Button view covering the |transform_window_|. + // That button serves as an event shield to receive all events such as clicks + // targeting the |transform_window_| or the overview header above the window. + // The shield button owns |background_view_| which owns |label_view_| + // and |close_button_|. + CaptionContainerView* caption_container_view_; + + // A View for the text label above the window owned by the |background_view_|. + views::Label* label_view_; + + // A close button for the window in this item owned by the |background_view_|. + OverviewCloseButton* close_button_; + + // Pointer to the WindowSelector that owns the WindowGrid containing |this|. + // Guaranteed to be non-null for the lifetime of |this|. + WindowSelector* window_selector_; + + // Pointer to a view that covers the original header and has rounded top + // corners. This view can have its color and opacity animated. It has a layer + // which is the only textured layer used by the |item_widget_|. + RoundedContainerView* background_view_; + + DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_
diff --git a/ash/common/wm/panels/OWNERS b/ash/common/wm/panels/OWNERS new file mode 100644 index 0000000..aa215c7 --- /dev/null +++ b/ash/common/wm/panels/OWNERS
@@ -0,0 +1 @@ +stevenjb@chromium.org
diff --git a/ash/common/wm/panels/panel_frame_view.cc b/ash/common/wm/panels/panel_frame_view.cc new file mode 100644 index 0000000..67ef90c --- /dev/null +++ b/ash/common/wm/panels/panel_frame_view.cc
@@ -0,0 +1,160 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/panels/panel_frame_view.h" + +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/default_header_painter.h" +#include "ash/common/frame/frame_border_hit_test.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/canvas.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { + +// static +const char PanelFrameView::kViewClassName[] = "PanelFrameView"; + +PanelFrameView::PanelFrameView(views::Widget* frame, FrameType frame_type) + : frame_(frame), caption_button_container_(nullptr), window_icon_(nullptr) { + GetWidgetWindow()->InstallResizeHandleWindowTargeter(nullptr); + DCHECK(!frame_->widget_delegate()->CanMaximize()); + if (frame_type != FRAME_NONE) + InitHeaderPainter(); + WmShell::Get()->AddShellObserver(this); +} + +PanelFrameView::~PanelFrameView() { + WmShell::Get()->RemoveShellObserver(this); +} + +void PanelFrameView::SetFrameColors(SkColor active_frame_color, + SkColor inactive_frame_color) { + header_painter_->SetFrameColors(active_frame_color, inactive_frame_color); + GetWidgetWindow()->aura_window()->SetProperty( + aura::client::kTopViewColor, header_painter_->GetInactiveFrameColor()); +} + +const char* PanelFrameView::GetClassName() const { + return kViewClassName; +} + +void PanelFrameView::InitHeaderPainter() { + header_painter_.reset(new DefaultHeaderPainter); + GetWidgetWindow()->aura_window()->SetProperty( + aura::client::kTopViewColor, header_painter_->GetInactiveFrameColor()); + + caption_button_container_ = new FrameCaptionButtonContainerView(frame_); + AddChildView(caption_button_container_); + + header_painter_->Init(frame_, this, caption_button_container_); + + if (frame_->widget_delegate()->ShouldShowWindowIcon()) { + window_icon_ = new views::ImageView(); + AddChildView(window_icon_); + header_painter_->UpdateLeftHeaderView(window_icon_); + } +} + +WmWindow* PanelFrameView::GetWidgetWindow() { + return WmWindow::Get(frame_->GetNativeWindow()); +} + +int PanelFrameView::NonClientTopBorderHeight() const { + if (!header_painter_) + return 0; + return header_painter_->GetHeaderHeightForPainting(); +} + +gfx::Size PanelFrameView::GetMinimumSize() const { + if (!header_painter_) + return gfx::Size(); + gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize()); + return gfx::Size(std::max(header_painter_->GetMinimumHeaderWidth(), + min_client_view_size.width()), + NonClientTopBorderHeight() + min_client_view_size.height()); +} + +void PanelFrameView::Layout() { + if (!header_painter_) + return; + header_painter_->LayoutHeader(); + GetWidgetWindow()->aura_window()->SetProperty(aura::client::kTopViewInset, + NonClientTopBorderHeight()); +} + +void PanelFrameView::GetWindowMask(const gfx::Size&, gfx::Path*) { + // Nothing. +} + +void PanelFrameView::ResetWindowControls() { + NOTIMPLEMENTED(); +} + +void PanelFrameView::UpdateWindowIcon() { + if (!window_icon_) + return; + views::WidgetDelegate* delegate = frame_->widget_delegate(); + if (delegate) + window_icon_->SetImage(delegate->GetWindowIcon()); + window_icon_->SchedulePaint(); +} + +void PanelFrameView::UpdateWindowTitle() { + if (!header_painter_) + return; + header_painter_->SchedulePaintForTitle(); +} + +void PanelFrameView::SizeConstraintsChanged() {} + +gfx::Rect PanelFrameView::GetBoundsForClientView() const { + gfx::Rect client_bounds = bounds(); + client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); + return client_bounds; +} + +gfx::Rect PanelFrameView::GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const { + gfx::Rect window_bounds = client_bounds; + window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); + return window_bounds; +} + +int PanelFrameView::NonClientHitTest(const gfx::Point& point) { + if (!header_painter_) + return HTNOWHERE; + return FrameBorderNonClientHitTest(this, caption_button_container_, point); +} + +void PanelFrameView::OnPaint(gfx::Canvas* canvas) { + if (!header_painter_) + return; + bool paint_as_active = ShouldPaintAsActive(); + caption_button_container_->SetPaintAsActive(paint_as_active); + + HeaderPainter::Mode header_mode = paint_as_active + ? HeaderPainter::MODE_ACTIVE + : HeaderPainter::MODE_INACTIVE; + header_painter_->PaintHeader(canvas, header_mode); +} + +/////////////////////////////////////////////////////////////////////////////// +// PanelFrameView, ShellObserver overrides: + +void PanelFrameView::OnOverviewModeStarting() { + caption_button_container_->SetVisible(false); +} + +void PanelFrameView::OnOverviewModeEnded() { + caption_button_container_->SetVisible(true); +} + +} // namespace ash
diff --git a/ash/common/wm/panels/panel_frame_view.h b/ash/common/wm/panels/panel_frame_view.h new file mode 100644 index 0000000..6a1f2758 --- /dev/null +++ b/ash/common/wm/panels/panel_frame_view.h
@@ -0,0 +1,83 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_PANELS_PANEL_FRAME_VIEW_H_ +#define ASH_COMMON_WM_PANELS_PANEL_FRAME_VIEW_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "base/macros.h" +#include "ui/views/window/non_client_view.h" + +namespace views { +class ImageView; +} + +namespace ash { +class DefaultHeaderPainter; +class FrameCaptionButtonContainerView; + +class ASH_EXPORT PanelFrameView : public views::NonClientFrameView, + public ShellObserver { + public: + // Internal class name. + static const char kViewClassName[]; + + enum FrameType { FRAME_NONE, FRAME_ASH }; + + PanelFrameView(views::Widget* frame, FrameType frame_type); + ~PanelFrameView() override; + + // Sets the active and inactive frame colors. Note the inactive frame color + // will have some transparency added when the frame is drawn. + void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); + + // views::View: + const char* GetClassName() const override; + + private: + void InitHeaderPainter(); + + WmWindow* GetWidgetWindow(); + + // Height from top of window to top of client area. + int NonClientTopBorderHeight() const; + + // views::NonClientFrameView: + gfx::Rect GetBoundsForClientView() const override; + gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const override; + int NonClientHitTest(const gfx::Point& point) override; + void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override; + void ResetWindowControls() override; + void UpdateWindowIcon() override; + void UpdateWindowTitle() override; + void SizeConstraintsChanged() override; + + // views::View: + gfx::Size GetMinimumSize() const override; + void Layout() override; + void OnPaint(gfx::Canvas* canvas) override; + + // ShellObserver: + void OnOverviewModeStarting() override; + void OnOverviewModeEnded() override; + + // Child View class describing the panel's title bar behavior + // and buttons, owned by the view hierarchy + views::Widget* frame_; + FrameCaptionButtonContainerView* caption_button_container_; + views::ImageView* window_icon_; + gfx::Rect client_view_bounds_; + + // Helper class for painting the header. + std::unique_ptr<DefaultHeaderPainter> header_painter_; + + DISALLOW_COPY_AND_ASSIGN(PanelFrameView); +}; +} + +#endif // ASH_COMMON_WM_PANELS_PANEL_FRAME_VIEW_H_
diff --git a/ash/common/wm/panels/panel_layout_manager.cc b/ash/common/wm/panels/panel_layout_manager.cc new file mode 100644 index 0000000..eb8dd67 --- /dev/null +++ b/ash/common/wm/panels/panel_layout_manager.cc
@@ -0,0 +1,929 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/panels/panel_layout_manager.h" + +#include <algorithm> +#include <map> +#include <utility> + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_util.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/window_parenting_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_properties.h" +#include "base/auto_reset.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkPath.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d.h" +#include "ui/views/background.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +const int kPanelIdealSpacing = 4; + +const float kMaxHeightFactor = .80f; +const float kMaxWidthFactor = .50f; + +// Duration for panel animations. +const int kPanelSlideDurationMilliseconds = 50; +const int kCalloutFadeDurationMilliseconds = 50; + +// Offset used when sliding panel in/out of the shelf. Used for minimizing, +// restoring and the initial showing of a panel. +const int kPanelSlideInOffset = 20; + +// Callout arrow dimensions. +const int kArrowWidth = 18; +const int kArrowHeight = 9; + +class CalloutWidgetBackground : public views::Background { + public: + CalloutWidgetBackground() : alignment_(SHELF_ALIGNMENT_BOTTOM) {} + + void Paint(gfx::Canvas* canvas, views::View* view) const override { + SkPath path; + switch (alignment_) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + path.moveTo(SkIntToScalar(0), SkIntToScalar(0)); + path.lineTo(SkIntToScalar(kArrowWidth / 2), + SkIntToScalar(kArrowHeight)); + path.lineTo(SkIntToScalar(kArrowWidth), SkIntToScalar(0)); + break; + case SHELF_ALIGNMENT_LEFT: + path.moveTo(SkIntToScalar(kArrowHeight), SkIntToScalar(kArrowWidth)); + path.lineTo(SkIntToScalar(0), SkIntToScalar(kArrowWidth / 2)); + path.lineTo(SkIntToScalar(kArrowHeight), SkIntToScalar(0)); + break; + case SHELF_ALIGNMENT_RIGHT: + path.moveTo(SkIntToScalar(0), SkIntToScalar(0)); + path.lineTo(SkIntToScalar(kArrowHeight), + SkIntToScalar(kArrowWidth / 2)); + path.lineTo(SkIntToScalar(0), SkIntToScalar(kArrowWidth)); + break; + } + // Hard code the arrow color for now. + cc::PaintFlags flags; + flags.setStyle(cc::PaintFlags::kFill_Style); + flags.setColor(SkColorSetARGB(0xff, 0xe5, 0xe5, 0xe5)); + canvas->DrawPath(path, flags); + } + + ShelfAlignment alignment() { return alignment_; } + + void set_alignment(ShelfAlignment alignment) { alignment_ = alignment; } + + private: + ShelfAlignment alignment_; + + DISALLOW_COPY_AND_ASSIGN(CalloutWidgetBackground); +}; + +struct VisiblePanelPositionInfo { + VisiblePanelPositionInfo() + : min_major(0), + max_major(0), + major_pos(0), + major_length(0), + window(NULL), + slide_in(false) {} + + int min_major; + int max_major; + int major_pos; + int major_length; + WmWindow* window; + bool slide_in; +}; + +bool CompareWindowMajor(const VisiblePanelPositionInfo& win1, + const VisiblePanelPositionInfo& win2) { + return win1.major_pos < win2.major_pos; +} + +void FanOutPanels(std::vector<VisiblePanelPositionInfo>::iterator first, + std::vector<VisiblePanelPositionInfo>::iterator last) { + int num_panels = last - first; + if (num_panels == 1) { + (*first).major_pos = std::max( + (*first).min_major, std::min((*first).max_major, (*first).major_pos)); + } + if (num_panels <= 1) + return; + + if (num_panels == 2) { + // If there are two adjacent overlapping windows, separate them by the + // minimum major_length necessary. + std::vector<VisiblePanelPositionInfo>::iterator second = first + 1; + int separation = (*first).major_length / 2 + (*second).major_length / 2 + + kPanelIdealSpacing; + int overlap = (*first).major_pos + separation - (*second).major_pos; + (*first).major_pos = + std::max((*first).min_major, (*first).major_pos - overlap / 2); + (*second).major_pos = + std::min((*second).max_major, (*first).major_pos + separation); + // Recalculate the first panel position in case the second one was + // constrained on the right. + (*first).major_pos = + std::max((*first).min_major, (*second).major_pos - separation); + return; + } + + // If there are more than two overlapping windows, fan them out from minimum + // position to maximum position equally spaced. + int delta = ((*(last - 1)).max_major - (*first).min_major) / (num_panels - 1); + int major_pos = (*first).min_major; + for (std::vector<VisiblePanelPositionInfo>::iterator iter = first; + iter != last; ++iter) { + (*iter).major_pos = + std::max((*iter).min_major, std::min((*iter).max_major, major_pos)); + major_pos += delta; + } +} + +bool BoundsAdjacent(const gfx::Rect& bounds1, const gfx::Rect& bounds2) { + return bounds1.x() == bounds2.right() || bounds1.y() == bounds2.bottom() || + bounds1.right() == bounds2.x() || bounds1.bottom() == bounds2.y(); +} + +gfx::Vector2d GetSlideInAnimationOffset(ShelfAlignment alignment) { + gfx::Vector2d offset; + if (alignment == SHELF_ALIGNMENT_LEFT) + offset.set_x(-kPanelSlideInOffset); + else if (alignment == SHELF_ALIGNMENT_RIGHT) + offset.set_x(kPanelSlideInOffset); + else + offset.set_y(kPanelSlideInOffset); + return offset; +} + +} // namespace + +class PanelCalloutWidget : public views::Widget { + public: + explicit PanelCalloutWidget(WmWindow* container) : background_(nullptr) { + InitWidget(container); + } + + void SetAlignment(ShelfAlignment alignment) { + WmWindow* window = WmWindow::Get(this->GetNativeWindow()); + gfx::Rect callout_bounds = window->GetBounds(); + if (IsHorizontalAlignment(alignment)) { + callout_bounds.set_width(kArrowWidth); + callout_bounds.set_height(kArrowHeight); + } else { + callout_bounds.set_width(kArrowHeight); + callout_bounds.set_height(kArrowWidth); + } + WmWindow* parent = window->GetParent(); + // It's important this go through WmWindow and not Widget. Going through + // Widget means it may move do a different screen, we don't want that. + window->SetBounds(callout_bounds); + // Setting the bounds should not trigger changing the parent. + DCHECK_EQ(parent, window->GetParent()); + if (background_->alignment() != alignment) { + background_->set_alignment(alignment); + SchedulePaintInRect(gfx::Rect(callout_bounds.size())); + } + } + + private: + void InitWidget(WmWindow* parent) { + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.keep_on_top = true; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.bounds = parent->ConvertRectToScreen(gfx::Rect()); + params.bounds.set_width(kArrowWidth); + params.bounds.set_height(kArrowHeight); + params.accept_events = false; + parent->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + this, parent->GetShellWindowId(), ¶ms); + set_focus_on_creation(false); + Init(params); + WmWindow* widget_window = WmWindow::Get(this->GetNativeWindow()); + DCHECK_EQ(widget_window->GetRootWindow(), parent->GetRootWindow()); + views::View* content_view = new views::View; + background_ = new CalloutWidgetBackground; + content_view->set_background(background_); + SetContentsView(content_view); + widget_window->GetLayer()->SetOpacity(0); + } + + // Weak pointer owned by this widget's content view. + CalloutWidgetBackground* background_; + + DISALLOW_COPY_AND_ASSIGN(PanelCalloutWidget); +}; + +views::Widget* PanelLayoutManager::PanelInfo::CalloutWidget() { + return callout_widget; +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager public implementation: +PanelLayoutManager::PanelLayoutManager(WmWindow* panel_container) + : panel_container_(panel_container), + root_window_controller_(panel_container->GetRootWindowController()), + in_add_window_(false), + in_layout_(false), + show_callout_widgets_(true), + dragged_panel_(NULL), + shelf_(nullptr), + last_active_panel_(NULL), + weak_factory_(this) { + DCHECK(panel_container); + WmShell* shell = panel_container->GetShell(); + shell->AddActivationObserver(this); + shell->AddDisplayObserver(this); + shell->AddShellObserver(this); +} + +PanelLayoutManager::~PanelLayoutManager() { + Shutdown(); +} + +// static +PanelLayoutManager* PanelLayoutManager::Get(WmWindow* window) { + if (!window) + return nullptr; + + return static_cast<PanelLayoutManager*>( + window->GetRootWindow() + ->GetChildByShellWindowId(kShellWindowId_PanelContainer) + ->GetLayoutManager()); +} + +void PanelLayoutManager::Shutdown() { + if (shelf_) { + shelf_->RemoveObserver(this); + shelf_ = nullptr; + } + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end(); ++iter) { + delete iter->callout_widget; + } + panel_windows_.clear(); + WmShell* shell = panel_container_->GetShell(); + shell->RemoveActivationObserver(this); + shell->RemoveDisplayObserver(this); + shell->RemoveShellObserver(this); +} + +void PanelLayoutManager::StartDragging(WmWindow* panel) { + DCHECK(!dragged_panel_); + dragged_panel_ = panel; + Relayout(); +} + +void PanelLayoutManager::FinishDragging() { + dragged_panel_ = NULL; + Relayout(); +} + +void PanelLayoutManager::SetShelf(WmShelf* shelf) { + DCHECK(!shelf_); + shelf_ = shelf; + shelf_->AddObserver(this); + WillChangeVisibilityState(shelf_->GetVisibilityState()); +} + +void PanelLayoutManager::ToggleMinimize(WmWindow* panel) { + DCHECK(panel->GetParent() == panel_container_); + wm::WindowState* window_state = panel->GetWindowState(); + if (window_state->IsMinimized()) + window_state->Restore(); + else + window_state->Minimize(); +} + +void PanelLayoutManager::SetShowCalloutWidgets(bool show) { + if (show_callout_widgets_ == show) + return; + show_callout_widgets_ = show; + UpdateCallouts(); +} + +views::Widget* PanelLayoutManager::GetCalloutWidgetForPanel(WmWindow* panel) { + DCHECK(panel->GetParent() == panel_container_); + PanelList::iterator found = + std::find(panel_windows_.begin(), panel_windows_.end(), panel); + DCHECK(found != panel_windows_.end()); + return found->callout_widget; +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, WmLayoutManager implementation: +void PanelLayoutManager::OnWindowResized() { + Relayout(); +} + +void PanelLayoutManager::OnWindowAddedToLayout(WmWindow* child) { + if (child->GetType() == ui::wm::WINDOW_TYPE_POPUP) + return; + if (in_add_window_) + return; + base::AutoReset<bool> auto_reset_in_add_window(&in_add_window_, true); + if (!child->aura_window()->GetProperty(kPanelAttachedKey)) { + // This should only happen when a window is added to panel container as a + // result of bounds change from within the application during a drag. + // If so we have already stopped the drag and should reparent the panel + // back to appropriate container and ignore it. + // TODO(varkha): Updating bounds during a drag can cause problems and a more + // general solution is needed. See http://crbug.com/251813 . + WmWindow* old_parent = child->GetParent(); + child->SetParentUsingContext(child, + child->GetRootWindow()->GetBoundsInScreen()); + wm::ReparentTransientChildrenOfChild(child, old_parent, child->GetParent()); + DCHECK(child->GetParent()->GetShellWindowId() != + kShellWindowId_PanelContainer); + return; + } + PanelInfo panel_info; + panel_info.window = child; + panel_info.callout_widget = new PanelCalloutWidget(panel_container_); + panel_info.slide_in = child != dragged_panel_; + panel_windows_.push_back(panel_info); + child->aura_window()->AddObserver(this); + child->GetWindowState()->AddObserver(this); + Relayout(); +} + +void PanelLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) {} + +void PanelLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) { + if (child->GetType() == ui::wm::WINDOW_TYPE_POPUP) + return; + + PanelList::iterator found = + std::find(panel_windows_.begin(), panel_windows_.end(), child); + if (found != panel_windows_.end()) { + delete found->callout_widget; + panel_windows_.erase(found); + } + if (restore_windows_on_shelf_visible_) + restore_windows_on_shelf_visible_->Remove(child->aura_window()); + child->aura_window()->RemoveObserver(this); + child->GetWindowState()->RemoveObserver(this); + + if (dragged_panel_ == child) + dragged_panel_ = NULL; + + if (last_active_panel_ == child) + last_active_panel_ = NULL; + + Relayout(); +} + +void PanelLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) { + if (visible) + child->GetWindowState()->Restore(); + Relayout(); +} + +void PanelLayoutManager::SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) { + gfx::Rect bounds(requested_bounds); + const gfx::Rect& max_bounds = panel_container_->GetRootWindow()->GetBounds(); + const int max_width = max_bounds.width() * kMaxWidthFactor; + const int max_height = max_bounds.height() * kMaxHeightFactor; + if (bounds.width() > max_width) + bounds.set_width(max_width); + if (bounds.height() > max_height) + bounds.set_height(max_height); + + // Reposition dragged panel in the panel order. + if (dragged_panel_ == child) { + PanelList::iterator dragged_panel_iter = + std::find(panel_windows_.begin(), panel_windows_.end(), dragged_panel_); + DCHECK(dragged_panel_iter != panel_windows_.end()); + PanelList::iterator new_position; + for (new_position = panel_windows_.begin(); + new_position != panel_windows_.end(); ++new_position) { + const gfx::Rect& bounds = (*new_position).window->GetBounds(); + if (bounds.x() + bounds.width() / 2 <= requested_bounds.x()) + break; + } + if (new_position != dragged_panel_iter) { + PanelInfo dragged_panel_info = *dragged_panel_iter; + panel_windows_.erase(dragged_panel_iter); + panel_windows_.insert(new_position, dragged_panel_info); + } + } + // Respect the minimum size of the window. + if (child->HasNonClientArea()) { + const gfx::Size min_size = child->GetMinimumSize(); + bounds.set_width(std::max(min_size.width(), bounds.width())); + bounds.set_height(std::max(min_size.height(), bounds.height())); + } + + child->SetBoundsDirect(bounds); + Relayout(); +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, ShellObserver implementation: + +void PanelLayoutManager::OnOverviewModeEnded() { + Relayout(); +} + +void PanelLayoutManager::OnShelfAlignmentChanged(WmWindow* root_window) { + if (root_window_controller_->GetWindow() == root_window) + Relayout(); +} + +///////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, WindowObserver implementation: + +void PanelLayoutManager::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + // Trigger a relayout to position the panels whenever the panel icon is set + // or changes. + if (key == kShelfIDKey) + Relayout(); +} + +///////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, WindowStateObserver implementation: + +void PanelLayoutManager::OnPostWindowStateTypeChange( + wm::WindowState* window_state, + wm::WindowStateType old_type) { + // If the shelf is currently hidden then windows will not actually be shown + // but the set to restore when the shelf becomes visible is updated. + if (restore_windows_on_shelf_visible_) { + if (window_state->IsMinimized()) { + MinimizePanel(window_state->window()); + restore_windows_on_shelf_visible_->Remove( + window_state->window()->aura_window()); + } else { + restore_windows_on_shelf_visible_->Add( + window_state->window()->aura_window()); + } + return; + } + + if (window_state->IsMinimized()) + MinimizePanel(window_state->window()); + else + RestorePanel(window_state->window()); +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, WmActivationObserver implementation: + +void PanelLayoutManager::OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) { + // Ignore if the panel that is not managed by this was activated. + if (gained_active && gained_active->GetType() == ui::wm::WINDOW_TYPE_PANEL && + gained_active->GetParent() == panel_container_) { + UpdateStacking(gained_active); + UpdateCallouts(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, WmDisplayObserver::Observer implementation: + +void PanelLayoutManager::OnDisplayConfigurationChanged() { + Relayout(); +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager, ShelfLayoutManagerObserver implementation: + +void PanelLayoutManager::WillChangeVisibilityState( + ShelfVisibilityState new_state) { + // On entering / leaving full screen mode the shelf visibility state is + // changed to / from SHELF_HIDDEN. In this state, panel windows should hide + // to allow the full-screen application to use the full screen. + bool shelf_hidden = new_state == ash::SHELF_HIDDEN; + if (!shelf_hidden) { + if (restore_windows_on_shelf_visible_) { + std::unique_ptr<aura::WindowTracker> restore_windows( + std::move(restore_windows_on_shelf_visible_)); + for (aura::Window* window : restore_windows->windows()) + RestorePanel(WmWindow::Get(window)); + } + return; + } + + if (restore_windows_on_shelf_visible_) + return; + std::unique_ptr<aura::WindowTracker> minimized_windows( + new aura::WindowTracker); + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end();) { + WmWindow* window = iter->window; + // Minimizing a panel window may remove it from the panel_windows_ list. + // Advance the iterator before minimizing it: http://crbug.com/393047. + ++iter; + if (window != dragged_panel_ && window->IsVisible()) { + minimized_windows->Add(window->aura_window()); + window->GetWindowState()->Minimize(); + } + } + restore_windows_on_shelf_visible_ = std::move(minimized_windows); +} + +void PanelLayoutManager::OnShelfIconPositionsChanged() { + // TODO: As this is called for every animation step now. Relayout needs to be + // updated to use current icon position instead of use the ideal bounds so + // that the panels slide with their icons instead of jumping. + Relayout(); +} + +//////////////////////////////////////////////////////////////////////////////// +// PanelLayoutManager private implementation: + +void PanelLayoutManager::MinimizePanel(WmWindow* panel) { + // Clusterfuzz can trigger panel accelerators before the shelf is created. + // TODO(jamescook): Revert this after http://crbug.com/648964 is fixed. + if (!shelf_) + return; + + panel->SetVisibilityAnimationType( + wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); + ui::Layer* layer = panel->GetLayer(); + ui::ScopedLayerAnimationSettings panel_slide_settings(layer->GetAnimator()); + panel_slide_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + panel_slide_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kPanelSlideDurationMilliseconds)); + gfx::Rect bounds(panel->GetBounds()); + bounds.Offset(GetSlideInAnimationOffset(shelf_->GetAlignment())); + panel->SetBoundsDirect(bounds); + panel->Hide(); + layer->SetOpacity(0); + if (panel->IsActive()) + panel->Deactivate(); + Relayout(); +} + +void PanelLayoutManager::RestorePanel(WmWindow* panel) { + PanelList::iterator found = + std::find(panel_windows_.begin(), panel_windows_.end(), panel); + DCHECK(found != panel_windows_.end()); + found->slide_in = true; + Relayout(); +} + +void PanelLayoutManager::Relayout() { + if (!shelf_ || !shelf_->GetWindow()) + return; + + // Suppress layouts during overview mode because changing window bounds + // interfered with overview mode animations. However, layouts need to be done + // when the WindowSelectorController is restoring minimized windows so that + // they actually become visible. + WindowSelectorController* window_selector_controller = + WmShell::Get()->window_selector_controller(); + if (in_layout_ || + (window_selector_controller->IsSelecting() && + !window_selector_controller->IsRestoringMinimizedWindows())) { + return; + } + + base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); + + const ShelfAlignment alignment = shelf_->GetAlignment(); + const bool horizontal = shelf_->IsHorizontalAlignment(); + gfx::Rect shelf_bounds = panel_container_->ConvertRectFromScreen( + shelf_->GetWindow()->GetBoundsInScreen()); + int panel_start_bounds = kPanelIdealSpacing; + int panel_end_bounds = + horizontal ? panel_container_->GetBounds().width() - kPanelIdealSpacing + : panel_container_->GetBounds().height() - kPanelIdealSpacing; + WmWindow* active_panel = nullptr; + std::vector<VisiblePanelPositionInfo> visible_panels; + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end(); ++iter) { + WmWindow* panel = iter->window; + iter->callout_widget->SetAlignment(alignment); + + // Consider the dragged panel as part of the layout as long as it is + // touching the shelf. + if ((!panel->IsVisible() && !iter->slide_in) || + (panel == dragged_panel_ && + !BoundsAdjacent(panel->GetBounds(), shelf_bounds))) { + continue; + } + + // If the shelf is currently hidden (full-screen mode), minimize panel until + // full-screen mode is exited. When a panel is dragged from another display + // the shelf state does not update before the panel is added so we exclude + // the dragged panel. + if (panel != dragged_panel_ && restore_windows_on_shelf_visible_) { + panel->GetWindowState()->Minimize(); + restore_windows_on_shelf_visible_->Add(panel->aura_window()); + continue; + } + + gfx::Rect icon_bounds = shelf_->GetScreenBoundsOfItemIconForWindow(panel); + + // If both the icon width and height are 0 then there is no icon in the + // shelf. If the shelf is hidden, one of the height or width will be + // 0 but the position in the shelf and major dimension is still reported + // correctly and the panel can be aligned above where the hidden icon is. + if (icon_bounds.width() == 0 && icon_bounds.height() == 0) + continue; + + if (panel->IsFocused() || + panel->Contains(panel->GetShell()->GetFocusedWindow())) { + DCHECK(!active_panel); + active_panel = panel; + } + icon_bounds = panel_container_->ConvertRectFromScreen(icon_bounds); + gfx::Point icon_origin = icon_bounds.origin(); + VisiblePanelPositionInfo position_info; + int icon_start = horizontal ? icon_origin.x() : icon_origin.y(); + int icon_end = + icon_start + (horizontal ? icon_bounds.width() : icon_bounds.height()); + position_info.major_length = + horizontal ? panel->GetBounds().width() : panel->GetBounds().height(); + position_info.min_major = + std::max(panel_start_bounds + position_info.major_length / 2, + icon_end - position_info.major_length / 2); + position_info.max_major = + std::min(icon_start + position_info.major_length / 2, + panel_end_bounds - position_info.major_length / 2); + position_info.major_pos = (icon_start + icon_end) / 2; + position_info.window = panel; + position_info.slide_in = iter->slide_in; + iter->slide_in = false; + visible_panels.push_back(position_info); + } + + // Sort panels by their X positions and fan out groups of overlapping panels. + // The fan out method may result in new overlapping panels however given that + // the panels start at least a full panel width apart this overlap will + // never completely obscure a panel. + // TODO(flackr): Rearrange panels if new overlaps are introduced. + std::sort(visible_panels.begin(), visible_panels.end(), CompareWindowMajor); + size_t first_overlapping_panel = 0; + for (size_t i = 1; i < visible_panels.size(); ++i) { + if (visible_panels[i - 1].major_pos + + visible_panels[i - 1].major_length / 2 < + visible_panels[i].major_pos - visible_panels[i].major_length / 2) { + FanOutPanels(visible_panels.begin() + first_overlapping_panel, + visible_panels.begin() + i); + first_overlapping_panel = i; + } + } + FanOutPanels(visible_panels.begin() + first_overlapping_panel, + visible_panels.end()); + + for (size_t i = 0; i < visible_panels.size(); ++i) { + if (visible_panels[i].window == dragged_panel_) + continue; + bool slide_in = visible_panels[i].slide_in; + gfx::Rect bounds = visible_panels[i].window->GetTargetBounds(); + if (alignment == SHELF_ALIGNMENT_LEFT) + bounds.set_x(shelf_bounds.right()); + else if (alignment == SHELF_ALIGNMENT_RIGHT) + bounds.set_x(shelf_bounds.x() - bounds.width()); + else + bounds.set_y(shelf_bounds.y() - bounds.height()); + bool on_shelf = visible_panels[i].window->GetTargetBounds() == bounds; + + if (horizontal) { + bounds.set_x(visible_panels[i].major_pos - + visible_panels[i].major_length / 2); + } else { + bounds.set_y(visible_panels[i].major_pos - + visible_panels[i].major_length / 2); + } + + ui::Layer* layer = visible_panels[i].window->GetLayer(); + if (slide_in) { + // New windows shift up from the shelf into position and fade in. + layer->SetOpacity(0); + gfx::Rect initial_bounds(bounds); + initial_bounds.Offset(GetSlideInAnimationOffset(alignment)); + visible_panels[i].window->SetBoundsDirect(initial_bounds); + // Set on shelf so that the panel animates into its target position. + on_shelf = true; + } + + if (on_shelf) { + ui::ScopedLayerAnimationSettings panel_slide_settings( + layer->GetAnimator()); + panel_slide_settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + panel_slide_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kPanelSlideDurationMilliseconds)); + visible_panels[i].window->SetBoundsDirect(bounds); + if (slide_in) { + layer->SetOpacity(1); + visible_panels[i].window->Show(); + } + } else { + // If the shelf moved don't animate, move immediately to the new + // target location. + visible_panels[i].window->SetBoundsDirect(bounds); + } + } + + UpdateStacking(active_panel); + UpdateCallouts(); +} + +void PanelLayoutManager::UpdateStacking(WmWindow* active_panel) { + // Clusterfuzz can trigger panel accelerators before the shelf is created. + // TODO(jamescook): Revert this after http://crbug.com/648964 is fixed. + if (!shelf_) + return; + + if (!active_panel) { + if (!last_active_panel_) + return; + active_panel = last_active_panel_; + } + + // We want to to stack the panels like a deck of cards: + // ,--,--,--,-------.--.--. + // | | | | | | | + // | | | | | | | + // + // We use the middle of each panel to figure out how to stack the panels. This + // allows us to update the stacking when a panel is being dragged around by + // the titlebar--even though it doesn't update the shelf icon positions, we + // still want the visual effect. + std::map<int, WmWindow*> window_ordering; + const bool horizontal = shelf_->IsHorizontalAlignment(); + for (PanelList::const_iterator it = panel_windows_.begin(); + it != panel_windows_.end(); ++it) { + gfx::Rect bounds = it->window->GetBounds(); + window_ordering.insert( + std::make_pair(horizontal ? bounds.x() + bounds.width() / 2 + : bounds.y() + bounds.height() / 2, + it->window)); + } + + WmWindow* previous_panel = nullptr; + for (std::map<int, WmWindow*>::const_iterator it = window_ordering.begin(); + it != window_ordering.end() && it->second != active_panel; ++it) { + if (previous_panel) + panel_container_->StackChildAbove(it->second, previous_panel); + previous_panel = it->second; + } + + previous_panel = NULL; + for (std::map<int, WmWindow*>::const_reverse_iterator it = + window_ordering.rbegin(); + it != window_ordering.rend() && it->second != active_panel; ++it) { + if (previous_panel) + panel_container_->StackChildAbove(it->second, previous_panel); + previous_panel = it->second; + } + + panel_container_->StackChildAtTop(active_panel); + if (dragged_panel_ && dragged_panel_->GetParent() == panel_container_) + panel_container_->StackChildAtTop(dragged_panel_); + last_active_panel_ = active_panel; +} + +void PanelLayoutManager::UpdateCallouts() { + // Clusterfuzz can trigger panel accelerators before the shelf is created. + // TODO(jamescook): Revert this after http://crbug.com/648964 is fixed. + if (!shelf_) + return; + + const bool horizontal = shelf_->IsHorizontalAlignment(); + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end(); ++iter) { + WmWindow* panel = iter->window; + views::Widget* callout_widget = iter->callout_widget; + WmWindow* callout_widget_window = + WmWindow::Get(callout_widget->GetNativeWindow()); + + gfx::Rect current_bounds = panel->GetBoundsInScreen(); + gfx::Rect bounds = + panel->GetParent()->ConvertRectToScreen(panel->GetTargetBounds()); + gfx::Rect icon_bounds = shelf_->GetScreenBoundsOfItemIconForWindow(panel); + if (icon_bounds.IsEmpty() || !panel->GetLayer()->GetTargetVisibility() || + panel == dragged_panel_ || !show_callout_widgets_) { + callout_widget->Hide(); + callout_widget_window->GetLayer()->SetOpacity(0); + continue; + } + + gfx::Rect callout_bounds = callout_widget->GetWindowBoundsInScreen(); + gfx::Vector2d slide_vector = bounds.origin() - current_bounds.origin(); + int slide_distance = horizontal ? slide_vector.x() : slide_vector.y(); + int distance_until_over_panel = 0; + if (horizontal) { + callout_bounds.set_x(icon_bounds.x() + + (icon_bounds.width() - callout_bounds.width()) / 2); + distance_until_over_panel = + std::max(current_bounds.x() - callout_bounds.x(), + callout_bounds.right() - current_bounds.right()); + } else { + callout_bounds.set_y(icon_bounds.y() + + (icon_bounds.height() - callout_bounds.height()) / + 2); + distance_until_over_panel = + std::max(current_bounds.y() - callout_bounds.y(), + callout_bounds.bottom() - current_bounds.bottom()); + } + if (shelf_->GetAlignment() == SHELF_ALIGNMENT_LEFT) + callout_bounds.set_x(bounds.x() - callout_bounds.width()); + else if (shelf_->GetAlignment() == SHELF_ALIGNMENT_RIGHT) + callout_bounds.set_x(bounds.right()); + else + callout_bounds.set_y(bounds.bottom()); + callout_bounds = callout_widget_window->GetParent()->ConvertRectFromScreen( + callout_bounds); + + callout_widget_window->SetBoundsDirect(callout_bounds); + DCHECK_EQ(panel_container_, callout_widget_window->GetParent()); + DCHECK_EQ(panel_container_, panel->GetParent()); + panel_container_->StackChildAbove(callout_widget_window, panel); + + ui::Layer* layer = callout_widget_window->GetLayer(); + // If the panel is not over the callout position or has just become visible + // then fade in the callout. + if ((distance_until_over_panel > 0 || layer->GetTargetOpacity() < 1)) { + if (distance_until_over_panel > 0 && + slide_distance >= distance_until_over_panel) { + // If the panel is not yet over the callout, then delay fading in + // the callout until after the panel should be over it. + int delay = kPanelSlideDurationMilliseconds * + distance_until_over_panel / slide_distance; + layer->SetOpacity(0); + layer->GetAnimator()->StopAnimating(); + layer->GetAnimator()->SchedulePauseForProperties( + base::TimeDelta::FromMilliseconds(delay), + ui::LayerAnimationElement::OPACITY); + } + ui::ScopedLayerAnimationSettings callout_settings(layer->GetAnimator()); + callout_settings.SetPreemptionStrategy( + ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); + callout_settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kCalloutFadeDurationMilliseconds)); + layer->SetOpacity(1); + } + + // Show after changing the opacity animation. This way we don't have a + // state where the widget is visible but the opacity is 0. + callout_widget->Show(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// keyboard::KeyboardControllerObserver implementation: + +void PanelLayoutManager::OnKeyboardBoundsChanging( + const gfx::Rect& keyboard_bounds) { + gfx::Rect parent_bounds = panel_container_->GetBounds(); + int available_space = parent_bounds.height() - keyboard_bounds.height(); + for (PanelList::iterator iter = panel_windows_.begin(); + iter != panel_windows_.end(); ++iter) { + WmWindow* panel = iter->window; + wm::WindowState* panel_state = panel->GetWindowState(); + if (keyboard_bounds.height() > 0) { + // Save existing bounds, so that we can restore them when the keyboard + // hides. + panel_state->SaveCurrentBoundsForRestore(); + + gfx::Rect panel_bounds = + panel->GetParent()->ConvertRectToScreen(panel->GetTargetBounds()); + int delta = panel_bounds.height() - available_space; + // Ensure panels are not pushed above the parent boundaries, shrink any + // panels that violate this constraint. + if (delta > 0) { + panel->SetBoundsDirect( + gfx::Rect(panel_bounds.x(), panel_bounds.y() + delta, + panel_bounds.width(), panel_bounds.height() - delta)); + } + } else if (panel_state->HasRestoreBounds()) { + // Keyboard hidden, restore original bounds if they exist. + panel->SetBoundsDirect(panel_state->GetRestoreBoundsInScreen()); + } + } + // This bounds change will have caused a change to the Shelf which does not + // propogate automatically to this class, so manually recalculate bounds. + OnWindowResized(); +} + +void PanelLayoutManager::OnKeyboardClosed() {} + +} // namespace ash
diff --git a/ash/common/wm/panels/panel_layout_manager.h b/ash/common/wm/panels/panel_layout_manager.h new file mode 100644 index 0000000..ff1047e --- /dev/null +++ b/ash/common/wm/panels/panel_layout_manager.h
@@ -0,0 +1,205 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_PANELS_PANEL_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_PANELS_PANEL_LAYOUT_MANAGER_H_ + +#include <list> +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm_activation_observer.h" +#include "ash/common/wm_display_observer.h" +#include "ash/common/wm_layout_manager.h" +#include "ash/root_window_controller.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "ui/aura/window_observer.h" +#include "ui/aura/window_tracker.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace gfx { +class Rect; +} + +namespace views { +class Widget; +} + +namespace ash { +class PanelCalloutWidget; +class WmShelf; + +namespace wm { +class RootWindowController; +} + +// PanelLayoutManager is responsible for organizing panels within the +// workspace. It is associated with a specific container window (i.e. +// kShellWindowId_PanelContainer) and controls the layout of any windows +// added to that container. +// +// The constructor takes a |panel_container| argument which is expected to set +// its layout manager to this instance, e.g.: +// panel_container->SetLayoutManager(new PanelLayoutManager(panel_container)); + +class ASH_EXPORT PanelLayoutManager + : public WmLayoutManager, + public wm::WindowStateObserver, + public WmActivationObserver, + public WmDisplayObserver, + public ShellObserver, + public aura::WindowObserver, + public keyboard::KeyboardControllerObserver, + public WmShelfObserver { + public: + explicit PanelLayoutManager(WmWindow* panel_container); + ~PanelLayoutManager() override; + + // Returns the PanelLayoutManager in the specified hierarchy. This searches + // from the root of |window|. + static PanelLayoutManager* Get(WmWindow* window); + + // Call Shutdown() before deleting children of panel_container. + void Shutdown(); + + void StartDragging(WmWindow* panel); + void FinishDragging(); + + void ToggleMinimize(WmWindow* panel); + + // Hide / Show the panel callout widgets. + void SetShowCalloutWidgets(bool show); + + // Returns the callout widget (arrow) for |panel|. + views::Widget* GetCalloutWidgetForPanel(WmWindow* panel); + + WmShelf* shelf() { return shelf_; } + void SetShelf(WmShelf* shelf); + + // Overridden from WmLayoutManager + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override; + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + // Overridden from ShellObserver: + void OnOverviewModeEnded() override; + void OnShelfAlignmentChanged(WmWindow* root_window) override; + + // Overridden from aura::WindowObserver + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + + // Overridden from wm::WindowStateObserver + void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) override; + + // Overridden from WmActivationObserver + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override; + + // Overridden from WindowTreeHostManager::Observer + void OnDisplayConfigurationChanged() override; + + // Overridden from WmShelfObserver + void WillChangeVisibilityState(ShelfVisibilityState new_state) override; + void OnShelfIconPositionsChanged() override; + + private: + friend class PanelLayoutManagerTest; + friend class PanelWindowResizerTest; + friend class DockedWindowResizerTest; + friend class DockedWindowLayoutManagerTest; + friend class WorkspaceControllerTest; + friend class AcceleratorControllerTest; + + views::Widget* CreateCalloutWidget(); + + struct ASH_EXPORT PanelInfo { + PanelInfo() : window(NULL), callout_widget(NULL), slide_in(false) {} + + bool operator==(const WmWindow* other_window) const { + return window == other_window; + } + + // Returns |callout_widget| as a widget. Used by tests. + views::Widget* CalloutWidget(); + + // A weak pointer to the panel window. + WmWindow* window; + + // The callout widget for this panel. This pointer must be managed + // manually as this structure is used in a std::list. See + // http://www.chromium.org/developers/smart-pointer-guidelines + PanelCalloutWidget* callout_widget; + + // True on new and restored panel windows until the panel has been + // positioned. The first time Relayout is called the panel will be shown, + // and slide into position and this will be set to false. + bool slide_in; + }; + + typedef std::list<PanelInfo> PanelList; + + void MinimizePanel(WmWindow* panel); + void RestorePanel(WmWindow* panel); + + // Called whenever the panel layout might change. + void Relayout(); + + // Called whenever the panel stacking order needs to be updated (e.g. focus + // changes or a panel is moved). + void UpdateStacking(WmWindow* active_panel); + + // Update the callout arrows for all managed panels. + void UpdateCallouts(); + + // Overridden from keyboard::KeyboardControllerObserver: + void OnKeyboardBoundsChanging(const gfx::Rect& keyboard_bounds) override; + void OnKeyboardClosed() override; + + // Parent window associated with this layout manager. + WmWindow* panel_container_; + + RootWindowController* root_window_controller_; + + // Protect against recursive calls to OnWindowAddedToLayout(). + bool in_add_window_; + // Protect against recursive calls to Relayout(). + bool in_layout_; + // Indicates if the panel callout widget should be created. + bool show_callout_widgets_; + // Ordered list of unowned pointers to panel windows. + PanelList panel_windows_; + // The panel being dragged. + WmWindow* dragged_panel_; + // The shelf we are observing for shelf icon changes. + WmShelf* shelf_; + + // When not NULL, the shelf is hidden (i.e. full screen) and this tracks the + // set of panel windows which have been temporarily hidden and need to be + // restored when the shelf becomes visible again. + std::unique_ptr<aura::WindowTracker> restore_windows_on_shelf_visible_; + + // The last active panel. Used to maintain stacking order even if no panels + // are currently focused. + WmWindow* last_active_panel_; + base::WeakPtrFactory<PanelLayoutManager> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(PanelLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_PANELS_PANEL_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/panels/panel_window_resizer.cc b/ash/common/wm/panels/panel_window_resizer.cc new file mode 100644 index 0000000..e4047eb8 --- /dev/null +++ b/ash/common/wm/panels/panel_window_resizer.cc
@@ -0,0 +1,207 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/panels/panel_window_resizer.h" + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/window_parenting_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/public/cpp/window_properties.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ui/base/hit_test.h" +#include "ui/base/ui_base_types.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" + +namespace ash { + +namespace { + +const int kPanelSnapToLauncherDistance = 30; + +} // namespace + +PanelWindowResizer::~PanelWindowResizer() {} + +// static +PanelWindowResizer* PanelWindowResizer::Create( + WindowResizer* next_window_resizer, + wm::WindowState* window_state) { + return new PanelWindowResizer(next_window_resizer, window_state); +} + +void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) { + last_location_ = GetTarget()->GetParent()->ConvertPointToScreen(location); + if (!did_move_or_resize_) { + did_move_or_resize_ = true; + StartedDragging(); + } + + // Check if the destination has changed displays. + display::Screen* screen = display::Screen::GetScreen(); + const display::Display dst_display = + screen->GetDisplayNearestPoint(last_location_); + if (dst_display.id() != + panel_container_->GetRootWindow()->GetDisplayNearestWindow().id()) { + // The panel is being dragged to a new display. If the previous container is + // the current parent of the panel it will be informed of the end of drag + // when the panel is reparented, otherwise let the previous container know + // the drag is complete. If we told the panel's parent that the drag was + // complete it would begin positioning the panel. + if (GetTarget()->GetParent() != panel_container_) + PanelLayoutManager::Get(panel_container_)->FinishDragging(); + WmWindow* dst_root = + Shell::GetRootWindowControllerWithDisplayId(dst_display.id()) + ->GetWindow(); + panel_container_ = + dst_root->GetChildByShellWindowId(kShellWindowId_PanelContainer); + + // The panel's parent already knows that the drag is in progress for this + // panel. + if (panel_container_ && GetTarget()->GetParent() != panel_container_) + PanelLayoutManager::Get(panel_container_)->StartDragging(GetTarget()); + } + gfx::Point offset; + gfx::Rect bounds(CalculateBoundsForDrag(location)); + if (!(details().bounds_change & WindowResizer::kBoundsChange_Resizes)) { + window_state_->drag_details()->should_attach_to_shelf = + AttachToLauncher(bounds, &offset); + } + gfx::Point modified_location(location.x() + offset.x(), + location.y() + offset.y()); + + base::WeakPtr<PanelWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr()); + next_window_resizer_->Drag(modified_location, event_flags); + if (!resizer) + return; + + if (details().should_attach_to_shelf && + !(details().bounds_change & WindowResizer::kBoundsChange_Resizes)) { + UpdateLauncherPosition(); + } +} + +void PanelWindowResizer::CompleteDrag() { + // The root window can change when dragging into a different screen. + next_window_resizer_->CompleteDrag(); + FinishDragging(); +} + +void PanelWindowResizer::RevertDrag() { + next_window_resizer_->RevertDrag(); + window_state_->drag_details()->should_attach_to_shelf = was_attached_; + FinishDragging(); +} + +PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer, + wm::WindowState* window_state) + : WindowResizer(window_state), + next_window_resizer_(next_window_resizer), + panel_container_(NULL), + initial_panel_container_(NULL), + did_move_or_resize_(false), + was_attached_(GetTarget()->aura_window()->GetProperty(kPanelAttachedKey)), + weak_ptr_factory_(this) { + DCHECK(details().is_resizable); + panel_container_ = GetTarget()->GetRootWindow()->GetChildByShellWindowId( + kShellWindowId_PanelContainer); + initial_panel_container_ = panel_container_; +} + +bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds, + gfx::Point* offset) { + bool should_attach = false; + if (panel_container_) { + PanelLayoutManager* panel_layout_manager = + PanelLayoutManager::Get(panel_container_); + gfx::Rect launcher_bounds = GetTarget()->GetParent()->ConvertRectFromScreen( + panel_layout_manager->shelf()->GetWindow()->GetBoundsInScreen()); + switch (panel_layout_manager->shelf()->GetAlignment()) { + case SHELF_ALIGNMENT_BOTTOM: + case SHELF_ALIGNMENT_BOTTOM_LOCKED: + if (bounds.bottom() >= + (launcher_bounds.y() - kPanelSnapToLauncherDistance)) { + should_attach = true; + offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y()); + } + break; + case SHELF_ALIGNMENT_LEFT: + if (bounds.x() <= + (launcher_bounds.right() + kPanelSnapToLauncherDistance)) { + should_attach = true; + offset->set_x(launcher_bounds.right() - bounds.x()); + } + break; + case SHELF_ALIGNMENT_RIGHT: + if (bounds.right() >= + (launcher_bounds.x() - kPanelSnapToLauncherDistance)) { + should_attach = true; + offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x()); + } + break; + } + } + return should_attach; +} + +void PanelWindowResizer::StartedDragging() { + // Tell the panel layout manager that we are dragging this panel before + // attaching it so that it does not get repositioned. + if (panel_container_) + PanelLayoutManager::Get(panel_container_)->StartDragging(GetTarget()); + if (!was_attached_) { + // Attach the panel while dragging, placing it in front of other panels. + WmWindow* target = GetTarget(); + target->aura_window()->SetProperty(kPanelAttachedKey, true); + // We use root window coordinates to ensure that during the drag the panel + // is reparented to a container in the root window that has that window. + WmWindow* target_root = target->GetRootWindow(); + WmWindow* old_parent = target->GetParent(); + target->SetParentUsingContext(target_root, + target_root->GetBoundsInScreen()); + wm::ReparentTransientChildrenOfChild(target, old_parent, + target->GetParent()); + } +} + +void PanelWindowResizer::FinishDragging() { + if (!did_move_or_resize_) + return; + if (GetTarget()->aura_window()->GetProperty(kPanelAttachedKey) != + details().should_attach_to_shelf) { + GetTarget()->aura_window()->SetProperty(kPanelAttachedKey, + details().should_attach_to_shelf); + // We use last known location to ensure that after the drag the panel + // is reparented to a container in the root window that has that location. + WmWindow* target = GetTarget(); + WmWindow* target_root = target->GetRootWindow(); + WmWindow* old_parent = target->GetParent(); + target->SetParentUsingContext(target_root, + gfx::Rect(last_location_, gfx::Size())); + wm::ReparentTransientChildrenOfChild(target, old_parent, + target->GetParent()); + } + + // If we started the drag in one root window and moved into another root + // but then canceled the drag we may need to inform the original layout + // manager that the drag is finished. + if (initial_panel_container_ != panel_container_) + PanelLayoutManager::Get(initial_panel_container_)->FinishDragging(); + if (panel_container_) + PanelLayoutManager::Get(panel_container_)->FinishDragging(); +} + +void PanelWindowResizer::UpdateLauncherPosition() { + if (panel_container_) { + PanelLayoutManager::Get(panel_container_) + ->shelf() + ->UpdateIconPositionForPanel(GetTarget()); + } +} + +} // namespace ash
diff --git a/ash/common/wm/panels/panel_window_resizer.h b/ash/common/wm/panels/panel_window_resizer.h new file mode 100644 index 0000000..dd8deed --- /dev/null +++ b/ash/common/wm/panels/panel_window_resizer.h
@@ -0,0 +1,87 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_PANELS_PANEL_WINDOW_RESIZER_H_ +#define ASH_COMMON_WM_PANELS_PANEL_WINDOW_RESIZER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/window_resizer.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" + +namespace gfx { +class Rect; +class Point; +} + +namespace ash { + +// PanelWindowResizer is used by ToplevelWindowEventFilter to handle dragging, +// moving or resizing panel window. These can be attached and detached from the +// launcher. +class ASH_EXPORT PanelWindowResizer : public WindowResizer { + public: + ~PanelWindowResizer() override; + + // Creates a new PanelWindowResizer. The caller takes ownership of the + // returned object. The ownership of |next_window_resizer| is taken by the + // returned object. Returns NULL if not resizable. + static PanelWindowResizer* Create(WindowResizer* next_window_resizer, + wm::WindowState* window_state); + + // WindowResizer: + void Drag(const gfx::Point& location, int event_flags) override; + void CompleteDrag() override; + void RevertDrag() override; + + private: + // Creates PanelWindowResizer that adds the ability to attach / detach panel + // windows as well as reparenting them to the panel layer while dragging to + // |next_window_resizer|. This object takes ownership of + // |next_window_resizer|. + PanelWindowResizer(WindowResizer* next_window_resizer, + wm::WindowState* window_state); + + // Checks if the provided window bounds should attach to the launcher. If true + // the offset gives the necessary adjustment to snap to the launcher. + bool AttachToLauncher(const gfx::Rect& bounds, gfx::Point* offset); + + // Tracks the panel's initial position and attachment at the start of a drag + // and informs the PanelLayoutManager that a drag has started if necessary. + void StartedDragging(); + + // Informs the PanelLayoutManager that the drag is complete if it was informed + // of the drag start. + void FinishDragging(); + + // Updates the dragged panel's index in the launcher. + void UpdateLauncherPosition(); + + // Last pointer location in screen coordinates. + gfx::Point last_location_; + + // Wraps a window resizer and adds panel detaching / reattaching and snapping + // to launcher behavior during drags. + std::unique_ptr<WindowResizer> next_window_resizer_; + + // Panel container window. + WmWindow* panel_container_; + WmWindow* initial_panel_container_; + + // Set to true once Drag() is invoked and the bounds of the window change. + bool did_move_or_resize_; + + // True if the window started attached to the launcher. + const bool was_attached_; + + base::WeakPtrFactory<PanelWindowResizer> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(PanelWindowResizer); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_PANELS_PANEL_WINDOW_RESIZER_H_
diff --git a/ash/common/wm/root_window_finder.cc b/ash/common/wm/root_window_finder.cc new file mode 100644 index 0000000..87c2da3 --- /dev/null +++ b/ash/common/wm/root_window_finder.cc
@@ -0,0 +1,36 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/root_window_finder.h" + +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { +namespace wm { + +WmWindow* GetRootWindowAt(const gfx::Point& point) { + const display::Display& display = + display::Screen::GetScreen()->GetDisplayNearestPoint(point); + DCHECK(display.is_valid()); + RootWindowController* root_window_controller = + Shell::GetRootWindowControllerWithDisplayId(display.id()); + return root_window_controller ? root_window_controller->GetWindow() : nullptr; +} + +WmWindow* GetRootWindowMatching(const gfx::Rect& rect) { + const display::Display& display = + display::Screen::GetScreen()->GetDisplayMatching(rect); + RootWindowController* root_window_controller = + Shell::GetRootWindowControllerWithDisplayId(display.id()); + return root_window_controller ? root_window_controller->GetWindow() : nullptr; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/root_window_finder.h b/ash/common/wm/root_window_finder.h new file mode 100644 index 0000000..bfda8c9 --- /dev/null +++ b/ash/common/wm/root_window_finder.h
@@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_ROOT_WINDOW_FINDER_H_ +#define ASH_COMMON_WM_ROOT_WINDOW_FINDER_H_ + +#include "ash/ash_export.h" + +namespace gfx { +class Point; +class Rect; +} // namespace gfx + +namespace ash { + +class WmWindow; + +namespace wm { + +// Returns the RootWindow at |point| in the virtual screen coordinates. +// Returns NULL if the root window does not exist at the given +// point. +ASH_EXPORT WmWindow* GetRootWindowAt(const gfx::Point& point); + +// Returns the RootWindow that shares the most area with |rect| in +// the virtual scren coordinates. +ASH_EXPORT WmWindow* GetRootWindowMatching(const gfx::Rect& rect); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_ROOT_WINDOW_FINDER_H_
diff --git a/ash/common/wm/root_window_layout_manager.cc b/ash/common/wm/root_window_layout_manager.cc new file mode 100644 index 0000000..15ec3fbf --- /dev/null +++ b/ash/common/wm/root_window_layout_manager.cc
@@ -0,0 +1,64 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/root_window_layout_manager.h" + +#include "ash/common/wm_window.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tracker.h" + +namespace ash { +namespace wm { + +//////////////////////////////////////////////////////////////////////////////// +// RootWindowLayoutManager, public: + +RootWindowLayoutManager::RootWindowLayoutManager(WmWindow* owner) + : owner_(owner) {} + +RootWindowLayoutManager::~RootWindowLayoutManager() {} + +//////////////////////////////////////////////////////////////////////////////// +// RootWindowLayoutManager, aura::LayoutManager implementation: + +void RootWindowLayoutManager::OnWindowResized() { + const gfx::Rect fullscreen_bounds = gfx::Rect(owner_->GetBounds().size()); + + // Resize both our immediate children (the containers-of-containers animated + // by PowerButtonController) and their children (the actual containers). + aura::WindowTracker children_tracker(owner_->aura_window()->children()); + while (!children_tracker.windows().empty()) { + aura::Window* child = children_tracker.Pop(); + // Skip descendants of top-level windows, i.e. only resize containers and + // other windows without a delegate, such as ScreenDimmer windows. + if (child->GetToplevelWindow()) + continue; + + child->SetBounds(fullscreen_bounds); + aura::WindowTracker grandchildren_tracker(child->children()); + while (!grandchildren_tracker.windows().empty()) { + child = grandchildren_tracker.Pop(); + if (!child->GetToplevelWindow()) + child->SetBounds(fullscreen_bounds); + } + } +} + +void RootWindowLayoutManager::OnWindowAddedToLayout(WmWindow* child) {} + +void RootWindowLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) {} + +void RootWindowLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {} + +void RootWindowLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) {} + +void RootWindowLayoutManager::SetChildBounds( + WmWindow* child, + const gfx::Rect& requested_bounds) { + child->SetBoundsDirect(requested_bounds); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/root_window_layout_manager.h b/ash/common/wm/root_window_layout_manager.h new file mode 100644 index 0000000..677dfc8 --- /dev/null +++ b/ash/common/wm/root_window_layout_manager.h
@@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_ROOT_WINDOW_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_ROOT_WINDOW_LAYOUT_MANAGER_H_ + +#include "ash/common/wm_layout_manager.h" +#include "base/macros.h" + +namespace ash { +namespace wm { + +// A layout manager for the root window. +// Resizes all of its immediate children and their descendants to fill the +// bounds of the associated window. +class RootWindowLayoutManager : public WmLayoutManager { + public: + explicit RootWindowLayoutManager(WmWindow* owner); + ~RootWindowLayoutManager() override; + + // Overridden from aura::LayoutManager: + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override; + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + private: + WmWindow* owner_; + + DISALLOW_COPY_AND_ASSIGN(RootWindowLayoutManager); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_ROOT_WINDOW_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/screen_dimmer.cc b/ash/common/wm/screen_dimmer.cc new file mode 100644 index 0000000..2b697fa --- /dev/null +++ b/ash/common/wm/screen_dimmer.cc
@@ -0,0 +1,82 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/screen_dimmer.h" + +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/window_dimmer.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/common/wm_window_user_data.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "base/memory/ptr_util.h" + +namespace ash { +namespace { + +// Opacity when it's dimming the entire screen. +const float kDimmingLayerOpacityForRoot = 0.4f; + +// Opacity for lock screen. +const float kDimmingLayerOpacityForLockScreen = 0.5f; + +} // namespace + +ScreenDimmer::ScreenDimmer(Container container) + : container_(container), + is_dimming_(false), + at_bottom_(false), + window_dimmers_(base::MakeUnique<WmWindowUserData<WindowDimmer>>()) { + WmShell::Get()->AddShellObserver(this); +} + +ScreenDimmer::~ScreenDimmer() { + // Usage in chrome results in ScreenDimmer outliving the shell. + if (WmShell::HasInstance()) + WmShell::Get()->RemoveShellObserver(this); +} + +void ScreenDimmer::SetDimming(bool should_dim) { + if (should_dim == is_dimming_) + return; + is_dimming_ = should_dim; + + Update(should_dim); +} + +std::vector<WmWindow*> ScreenDimmer::GetAllContainers() { + return container_ == Container::ROOT + ? WmShell::Get()->GetAllRootWindows() + : wm::GetContainersFromAllRootWindows( + ash::kShellWindowId_LockScreenContainersContainer); +} + +void ScreenDimmer::OnRootWindowAdded(WmWindow* root_window) { + Update(is_dimming_); +} + +void ScreenDimmer::Update(bool should_dim) { + for (WmWindow* container : GetAllContainers()) { + WindowDimmer* window_dimmer = window_dimmers_->Get(container); + if (should_dim) { + if (!window_dimmer) { + window_dimmers_->Set(container, + base::MakeUnique<WindowDimmer>(container)); + window_dimmer = window_dimmers_->Get(container); + window_dimmer->SetDimOpacity(container_ == Container::ROOT + ? kDimmingLayerOpacityForRoot + : kDimmingLayerOpacityForLockScreen); + } + if (at_bottom_) + container->StackChildAtBottom(window_dimmer->window()); + else + container->StackChildAtTop(window_dimmer->window()); + window_dimmer->window()->Show(); + } else if (window_dimmer) { + window_dimmers_->Set(container, nullptr); + } + } +} + +} // namespace ash
diff --git a/ash/common/wm/screen_dimmer.h b/ash/common/wm/screen_dimmer.h new file mode 100644 index 0000000..1667b05 --- /dev/null +++ b/ash/common/wm/screen_dimmer.h
@@ -0,0 +1,80 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_SCREEN_DIMMER_H_ +#define ASH_COMMON_WM_SCREEN_DIMMER_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "base/macros.h" + +namespace ash { +namespace test { +class ScreenDimmerTest; +} + +class WindowDimmer; + +template <typename UserData> +class WmWindowUserData; + +// ScreenDimmer displays a partially-opaque layer above everything +// else in the given container window to darken the display. It shouldn't be +// used for long-term brightness adjustments due to performance +// considerations -- it's only intended for cases where we want to +// briefly dim the screen (e.g. to indicate to the user that we're +// about to suspend a machine that lacks an internal backlight that +// can be adjusted). +class ASH_EXPORT ScreenDimmer : public ShellObserver { + public: + // Indicates the container ScreenDimmer operates on. + enum class Container { + ROOT, + LOCK_SCREEN, + }; + + explicit ScreenDimmer(Container container); + ~ScreenDimmer() override; + + // Dim or undim the layers. + void SetDimming(bool should_dim); + + void set_at_bottom(bool at_bottom) { at_bottom_ = at_bottom; } + + bool is_dimming() const { return is_dimming_; } + + // Find a ScreenDimmer in the container, or nullptr if it does not exist. + static ScreenDimmer* FindForTest(int container_id); + + private: + friend class test::ScreenDimmerTest; + + // Returns the WmWindows (one per display) that correspond to |container_|. + std::vector<WmWindow*> GetAllContainers(); + + // ShellObserver: + void OnRootWindowAdded(WmWindow* root_window) override; + + // Update the dimming state. This will also create a new DimWindow + // if necessary. (Used when a new display is connected) + void Update(bool should_dim); + + const Container container_; + + // Are we currently dimming the screen? + bool is_dimming_; + bool at_bottom_; + + // Owns the WindowDimmers. + std::unique_ptr<WmWindowUserData<WindowDimmer>> window_dimmers_; + + DISALLOW_COPY_AND_ASSIGN(ScreenDimmer); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_SCREEN_DIMMER_H_
diff --git a/ash/common/wm/switchable_windows.cc b/ash/common/wm/switchable_windows.cc new file mode 100644 index 0000000..efa1a9a --- /dev/null +++ b/ash/common/wm/switchable_windows.cc
@@ -0,0 +1,33 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/switchable_windows.h" + +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" + +namespace ash { +namespace wm { + +const int kSwitchableWindowContainerIds[] = { + kShellWindowId_DefaultContainer, kShellWindowId_AlwaysOnTopContainer, + kShellWindowId_DockedContainer, kShellWindowId_PanelContainer, + kShellWindowId_AppListContainer}; + +const size_t kSwitchableWindowContainerIdsLength = + arraysize(kSwitchableWindowContainerIds); + +bool IsSwitchableContainer(const WmWindow* window) { + if (!window) + return false; + const int shell_window_id = window->GetShellWindowId(); + for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { + if (shell_window_id == kSwitchableWindowContainerIds[i]) + return true; + } + return false; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/switchable_windows.h b/ash/common/wm/switchable_windows.h new file mode 100644 index 0000000..e960a2f --- /dev/null +++ b/ash/common/wm/switchable_windows.h
@@ -0,0 +1,31 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_SWITCHABLE_WINDOWS_H_ +#define ASH_COMMON_WM_SWITCHABLE_WINDOWS_H_ + +#include <stddef.h> + +#include "ash/ash_export.h" +#include "base/macros.h" + +namespace ash { + +class WmWindow; + +namespace wm { + +// List of containers which contain windows that can be switched via Alt+Tab to. +ASH_EXPORT extern const int kSwitchableWindowContainerIds[]; + +// The number of elements in kSwitchableWindowContainerIds. +ASH_EXPORT extern const size_t kSwitchableWindowContainerIdsLength; + +// Returns true if |window| is a container for windows which can be switched to. +ASH_EXPORT bool IsSwitchableContainer(const WmWindow* window); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_SWITCHABLE_WINDOWS_H_
diff --git a/ash/common/wm/system_modal_container_layout_manager.cc b/ash/common/wm/system_modal_container_layout_manager.cc new file mode 100644 index 0000000..d6d8d040 --- /dev/null +++ b/ash/common/wm/system_modal_container_layout_manager.cc
@@ -0,0 +1,280 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/system_modal_container_layout_manager.h" + +#include <cmath> + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm/window_dimmer.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "base/memory/ptr_util.h" +#include "base/stl_util.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" +#include "ui/keyboard/keyboard_controller.h" + +namespace ash { +namespace { + +// The center point of the window can diverge this much from the center point +// of the container to be kept centered upon resizing operations. +const int kCenterPixelDelta = 32; + +ui::ModalType GetModalType(WmWindow* window) { + return static_cast<ui::ModalType>( + window->aura_window()->GetProperty(aura::client::kModalKey)); +} + +bool HasTransientAncestor(const WmWindow* window, const WmWindow* ancestor) { + const WmWindow* transient_parent = window->GetTransientParent(); + if (transient_parent == ancestor) + return true; + return transient_parent ? HasTransientAncestor(transient_parent, ancestor) + : false; +} +} + +//////////////////////////////////////////////////////////////////////////////// +// SystemModalContainerLayoutManager, public: + +SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( + WmWindow* container) + : container_(container) {} + +SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { + if (keyboard::KeyboardController::GetInstance()) + keyboard::KeyboardController::GetInstance()->RemoveObserver(this); +} + +//////////////////////////////////////////////////////////////////////////////// +// SystemModalContainerLayoutManager, WmLayoutManager implementation: + +void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged( + WmWindow* window, + bool visible) { + if (GetModalType(window) != ui::MODAL_TYPE_SYSTEM) + return; + + if (window->IsVisible()) { + DCHECK(!base::ContainsValue(modal_windows_, window)); + AddModalWindow(window); + } else { + if (RemoveModalWindow(window)) + WmShell::Get()->OnModalWindowRemoved(window); + } +} + +void SystemModalContainerLayoutManager::OnWindowResized() { + PositionDialogsAfterWorkAreaResize(); +} + +void SystemModalContainerLayoutManager::OnWindowAddedToLayout(WmWindow* child) { + DCHECK(child->GetType() == ui::wm::WINDOW_TYPE_NORMAL || + child->GetType() == ui::wm::WINDOW_TYPE_POPUP); + // TODO(mash): IsUserSessionBlocked() depends on knowing the login state. We + // need a non-stub version of SessionStateDelegate. crbug.com/648964 + if (!WmShell::Get()->IsRunningInMash()) { + DCHECK(container_->GetShellWindowId() != + kShellWindowId_LockSystemModalContainer || + WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked()); + } + // Since this is for SystemModal, there is no good reason to add windows + // other than MODAL_TYPE_NONE or MODAL_TYPE_SYSTEM. DCHECK to avoid simple + // mistake. + DCHECK_NE(GetModalType(child), ui::MODAL_TYPE_CHILD); + DCHECK_NE(GetModalType(child), ui::MODAL_TYPE_WINDOW); + + child->aura_window()->AddObserver(this); + if (GetModalType(child) == ui::MODAL_TYPE_SYSTEM && child->IsVisible()) + AddModalWindow(child); +} + +void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout( + WmWindow* child) { + child->aura_window()->RemoveObserver(this); + windows_to_center_.erase(child); + if (GetModalType(child) == ui::MODAL_TYPE_SYSTEM) + RemoveModalWindow(child); +} + +void SystemModalContainerLayoutManager::SetChildBounds( + WmWindow* child, + const gfx::Rect& requested_bounds) { + WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); + if (IsBoundsCentered(requested_bounds)) + windows_to_center_.insert(child); + else + windows_to_center_.erase(child); +} + +//////////////////////////////////////////////////////////////////////////////// +// SystemModalContainerLayoutManager, aura::WindowObserver implementation: + +void SystemModalContainerLayoutManager::OnWindowPropertyChanged( + aura::Window* window, + const void* key, + intptr_t old) { + if (key != aura::client::kModalKey || !window->IsVisible()) + return; + + WmWindow* wm_window = WmWindow::Get(window); + if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM) { + if (base::ContainsValue(modal_windows_, wm_window)) + return; + AddModalWindow(wm_window); + } else { + if (RemoveModalWindow(wm_window)) + WmShell::Get()->OnModalWindowRemoved(wm_window); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver +// implementation: + +void SystemModalContainerLayoutManager::OnKeyboardBoundsChanging( + const gfx::Rect& new_bounds) { + PositionDialogsAfterWorkAreaResize(); +} + +void SystemModalContainerLayoutManager::OnKeyboardClosed() {} + +bool SystemModalContainerLayoutManager::IsPartOfActiveModalWindow( + WmWindow* window) { + return modal_window() && + (modal_window()->Contains(window) || + HasTransientAncestor(window->GetToplevelWindowForFocus(), + modal_window())); +} + +bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { + if (modal_windows_.empty()) + return false; + modal_window()->Activate(); + return true; +} + +void SystemModalContainerLayoutManager::CreateModalBackground() { + if (!window_dimmer_) { + window_dimmer_ = base::MakeUnique<WindowDimmer>(container_); + window_dimmer_->window()->SetName( + "SystemModalContainerLayoutManager.ModalBackground"); + // There isn't always a keyboard controller. + if (keyboard::KeyboardController::GetInstance()) + keyboard::KeyboardController::GetInstance()->AddObserver(this); + } + window_dimmer_->window()->Show(); +} + +void SystemModalContainerLayoutManager::DestroyModalBackground() { + if (!window_dimmer_) + return; + + if (keyboard::KeyboardController::GetInstance()) + keyboard::KeyboardController::GetInstance()->RemoveObserver(this); + window_dimmer_.reset(); +} + +// static +bool SystemModalContainerLayoutManager::IsModalBackground(WmWindow* window) { + int id = window->GetParent()->GetShellWindowId(); + if (id != kShellWindowId_SystemModalContainer && + id != kShellWindowId_LockSystemModalContainer) + return false; + SystemModalContainerLayoutManager* layout_manager = + static_cast<SystemModalContainerLayoutManager*>( + window->GetParent()->GetLayoutManager()); + return layout_manager->window_dimmer_ && + layout_manager->window_dimmer_->window() == window; +} + +//////////////////////////////////////////////////////////////////////////////// +// SystemModalContainerLayoutManager, private: + +void SystemModalContainerLayoutManager::AddModalWindow(WmWindow* window) { + if (modal_windows_.empty()) { + WmWindow* capture_window = WmShell::Get()->GetCaptureWindow(); + if (capture_window) + capture_window->ReleaseCapture(); + } + DCHECK(window->IsVisible()); + DCHECK(!base::ContainsValue(modal_windows_, window)); + + modal_windows_.push_back(window); + WmShell::Get()->CreateModalBackground(window); + window->GetParent()->StackChildAtTop(window); + + gfx::Rect target_bounds = window->GetBounds(); + target_bounds.AdjustToFit(GetUsableDialogArea()); + window->SetBounds(target_bounds); +} + +bool SystemModalContainerLayoutManager::RemoveModalWindow(WmWindow* window) { + auto it = std::find(modal_windows_.begin(), modal_windows_.end(), window); + if (it == modal_windows_.end()) + return false; + modal_windows_.erase(it); + return true; +} + +void SystemModalContainerLayoutManager::PositionDialogsAfterWorkAreaResize() { + if (modal_windows_.empty()) + return; + + for (WmWindow* window : modal_windows_) + window->SetBounds(GetCenteredAndOrFittedBounds(window)); +} + +gfx::Rect SystemModalContainerLayoutManager::GetUsableDialogArea() const { + // Instead of resizing the system modal container, we move only the modal + // windows. This way we avoid flashing lines upon resize animation and if the + // keyboard will not fill left to right, the background is still covered. + gfx::Rect valid_bounds = container_->GetBounds(); + keyboard::KeyboardController* keyboard_controller = + keyboard::KeyboardController::GetInstance(); + if (keyboard_controller) { + gfx::Rect bounds = keyboard_controller->current_keyboard_bounds(); + if (!bounds.IsEmpty()) { + valid_bounds.set_height( + std::max(0, valid_bounds.height() - bounds.height())); + } + } + return valid_bounds; +} + +gfx::Rect SystemModalContainerLayoutManager::GetCenteredAndOrFittedBounds( + const WmWindow* window) { + gfx::Rect target_bounds; + gfx::Rect usable_area = GetUsableDialogArea(); + if (windows_to_center_.count(window) > 0) { + // Keep the dialog centered if it was centered before. + target_bounds = usable_area; + target_bounds.ClampToCenteredSize(window->GetBounds().size()); + } else { + // Keep the dialog within the usable area. + target_bounds = window->GetBounds(); + target_bounds.AdjustToFit(usable_area); + } + if (usable_area != container_->GetBounds()) { + // Don't clamp the dialog for the keyboard. Keep the size as it is but make + // sure that the top remains visible. + // TODO(skuhne): M37 should add over scroll functionality to address this. + target_bounds.set_size(window->GetBounds().size()); + } + return target_bounds; +} + +bool SystemModalContainerLayoutManager::IsBoundsCentered( + const gfx::Rect& bounds) const { + gfx::Point window_center = bounds.CenterPoint(); + gfx::Point container_center = GetUsableDialogArea().CenterPoint(); + return std::abs(window_center.x() - container_center.x()) < + kCenterPixelDelta && + std::abs(window_center.y() - container_center.y()) < kCenterPixelDelta; +} + +} // namespace ash
diff --git a/ash/common/wm/system_modal_container_layout_manager.h b/ash/common/wm/system_modal_container_layout_manager.h new file mode 100644 index 0000000..171b0f46 --- /dev/null +++ b/ash/common/wm/system_modal_container_layout_manager.h
@@ -0,0 +1,116 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_SYSTEM_MODAL_CONTAINER_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_SYSTEM_MODAL_CONTAINER_LAYOUT_MANAGER_H_ + +#include <memory> +#include <set> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace gfx { +class Rect; +} + +namespace ash { +class WindowDimmer; + +// LayoutManager for the modal window container. +// System modal windows which are centered on the screen will be kept centered +// when the container size changes. +class ASH_EXPORT SystemModalContainerLayoutManager + : public wm::WmSnapToPixelLayoutManager, + public aura::WindowObserver, + public keyboard::KeyboardControllerObserver { + public: + explicit SystemModalContainerLayoutManager(WmWindow* container); + ~SystemModalContainerLayoutManager() override; + + bool has_window_dimmer() const { return window_dimmer_ != nullptr; } + + // Overridden from WmSnapToPixelLayoutManager: + void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override; + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + // Overridden from aura::WindowObserver: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + + // Overridden from keyboard::KeyboardControllerObserver: + void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; + void OnKeyboardClosed() override; + + // True if the window is either contained by the top most modal window, + // or contained by its transient children. + bool IsPartOfActiveModalWindow(WmWindow* window); + + // Activates next modal window if any. Returns false if there + // are no more modal windows in this layout manager. + bool ActivateNextModalWindow(); + + // Creates modal background window, which is a partially-opaque + // fullscreen window. If there is already a modal background window, + // it will bring it the top. + void CreateModalBackground(); + + void DestroyModalBackground(); + + // Is the |window| modal background? + static bool IsModalBackground(WmWindow* window); + + private: + void AddModalWindow(WmWindow* window); + + // Removes |window| from |modal_windows_|. Returns true if |window| was in + // |modal_windows_|. + bool RemoveModalWindow(WmWindow* window); + + // Reposition the dialogs to become visible after the work area changes. + void PositionDialogsAfterWorkAreaResize(); + + // Get the usable bounds rectangle for enclosed dialogs. + gfx::Rect GetUsableDialogArea() const; + + // Gets the new bounds for a |window| to use which are either centered (if the + // window was previously centered) or fitted to the screen. + gfx::Rect GetCenteredAndOrFittedBounds(const WmWindow* window); + + // Returns true if |bounds| is considered centered. + bool IsBoundsCentered(const gfx::Rect& window_bounds) const; + + WmWindow* modal_window() { + return !modal_windows_.empty() ? modal_windows_.back() : nullptr; + } + + // The container that owns the layout manager. + WmWindow* container_; + + // WindowDimmer used to dim windows behind the modal window(s) being shown in + // |container_|. + std::unique_ptr<WindowDimmer> window_dimmer_; + + // A stack of modal windows. Only the topmost can receive events. + std::vector<WmWindow*> modal_windows_; + + // Windows contained in this set are centered. Windows are automatically + // added to this based on IsBoundsCentered(). + std::set<const WmWindow*> windows_to_center_; + + DISALLOW_COPY_AND_ASSIGN(SystemModalContainerLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_SYSTEM_MODAL_CONTAINER_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/window_animation_types.h b/ash/common/wm/window_animation_types.h new file mode 100644 index 0000000..4ea91c4 --- /dev/null +++ b/ash/common/wm/window_animation_types.h
@@ -0,0 +1,26 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_ANIMATION_TYPES_H_ +#define ASH_COMMON_WM_WINDOW_ANIMATION_TYPES_H_ + +#include "ui/wm/core/window_animations.h" + +namespace ash { +namespace wm { + +// An extension of the window animations provided by CoreWm. These are +// Ash-specific only. +enum WindowVisibilityAnimationType { + // Window scale/rotates down to its launcher icon. + WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE = + ::wm::WINDOW_VISIBILITY_ANIMATION_MAX, + // Fade in/out using brightness and grayscale web filters. + WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_ANIMATION_TYPES_H_
diff --git a/ash/common/wm/window_cycle_controller.cc b/ash/common/wm/window_cycle_controller.cc new file mode 100644 index 0000000..686290e5 --- /dev/null +++ b/ash/common/wm/window_cycle_controller.cc
@@ -0,0 +1,126 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_cycle_controller.h" + +#include "ash/common/metrics/task_switch_source.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_cycle_event_filter.h" +#include "ash/common/wm/window_cycle_list.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "base/metrics/histogram_macros.h" + +namespace ash { + +namespace { + +// Returns the most recently active window from the |window_list| or nullptr +// if the list is empty. +WmWindow* GetActiveWindow(const MruWindowTracker::WindowList& window_list) { + return window_list.empty() ? nullptr : window_list[0]; +} + +} // namespace + +////////////////////////////////////////////////////////////////////////////// +// WindowCycleController, public: + +WindowCycleController::WindowCycleController() {} + +WindowCycleController::~WindowCycleController() {} + +// static +bool WindowCycleController::CanCycle() { + // Prevent window cycling if the screen is locked or a modal dialog is open. + WmShell* wm_shell = WmShell::Get(); + return !wm_shell->GetSessionStateDelegate()->IsScreenLocked() && + !wm_shell->IsSystemModalWindowOpen() && !wm_shell->IsPinned(); +} + +void WindowCycleController::HandleCycleWindow(Direction direction) { + if (!CanCycle()) + return; + + if (!IsCycling()) + StartCycling(); + + Step(direction); +} + +void WindowCycleController::StartCycling() { + MruWindowTracker::WindowList window_list = + WmShell::Get()->mru_window_tracker()->BuildMruWindowList(); + // Exclude windows: + // - non user positionable windows, such as extension popups. + // - windows being dragged + // - the AppList window, which will hide as soon as cycling starts + // anyway. It doesn't make sense to count it as a "switchable" window, yet + // a lot of code relies on the MRU list returning the app window. If we + // don't manually remove it, the window cycling UI won't crash or misbehave, + // but there will be a flicker as the target window changes. Also exclude + // unselectable windows such as extension popups. + auto window_is_ineligible = [](WmWindow* window) { + wm::WindowState* state = window->GetWindowState(); + return !state->IsUserPositionable() || state->is_dragged() || + window->GetRootWindow() + ->GetChildByShellWindowId(kShellWindowId_AppListContainer) + ->Contains(window); + }; + window_list.erase(std::remove_if(window_list.begin(), window_list.end(), + window_is_ineligible), + window_list.end()); + + active_window_before_window_cycle_ = GetActiveWindow(window_list); + + window_cycle_list_.reset(new WindowCycleList(window_list)); + event_filter_ = WmShell::Get()->CreateWindowCycleEventFilter(); + cycle_start_time_ = base::Time::Now(); + WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_CYCLE); + UMA_HISTOGRAM_COUNTS_100("Ash.WindowCycleController.Items", + window_list.size()); +} + +void WindowCycleController::CompleteCycling() { + window_cycle_list_->set_user_did_accept(true); + StopCycling(); +} + +void WindowCycleController::CancelCycling() { + StopCycling(); +} + +////////////////////////////////////////////////////////////////////////////// +// WindowCycleController, private: + +void WindowCycleController::Step(Direction direction) { + DCHECK(window_cycle_list_.get()); + window_cycle_list_->Step(direction); +} + +void WindowCycleController::StopCycling() { + UMA_HISTOGRAM_COUNTS_100("Ash.WindowCycleController.SelectionDepth", + window_cycle_list_->current_index() + 1); + window_cycle_list_.reset(); + + WmWindow* active_window_after_window_cycle = GetActiveWindow( + WmShell::Get()->mru_window_tracker()->BuildMruWindowList()); + + // Remove our key event filter. + event_filter_.reset(); + UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowCycleController.CycleTime", + base::Time::Now() - cycle_start_time_); + + if (active_window_after_window_cycle != nullptr && + active_window_before_window_cycle_ != active_window_after_window_cycle) { + WmShell::Get()->RecordTaskSwitchMetric( + TaskSwitchSource::WINDOW_CYCLE_CONTROLLER); + } + active_window_before_window_cycle_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/wm/window_cycle_controller.h b/ash/common/wm/window_cycle_controller.h new file mode 100644 index 0000000..87eedd9 --- /dev/null +++ b/ash/common/wm/window_cycle_controller.h
@@ -0,0 +1,82 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_CYCLE_CONTROLLER_H_ +#define ASH_COMMON_WM_WINDOW_CYCLE_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/time/time.h" + +namespace ash { + +class WindowCycleEventFilter; +class WindowCycleList; +class WmWindow; + +// Controls cycling through windows with the keyboard via alt-tab. +// Windows are sorted primarily by most recently used, and then by screen order. +// We activate windows as you cycle through them, so the order on the screen +// may change during the gesture, but the most recently used list isn't updated +// until the cycling ends. Thus we maintain the state of the windows +// at the beginning of the gesture so you can cycle through in a consistent +// order. +class ASH_EXPORT WindowCycleController { + public: + enum Direction { FORWARD, BACKWARD }; + + WindowCycleController(); + virtual ~WindowCycleController(); + + // Returns true if cycling through windows is enabled. This is false at + // certain times, such as when the lock screen is visible. + static bool CanCycle(); + + // Cycles between windows in the given |direction|. + void HandleCycleWindow(Direction direction); + + // Returns true if we are in the middle of a window cycling gesture. + bool IsCycling() const { return window_cycle_list_.get() != NULL; } + + // Call to start cycling windows. This funtion adds a pre-target handler to + // listen to the alt key release. + void StartCycling(); + + // Both of these functions stop the current window cycle and removes the event + // filter. The former indicates success (i.e. the new window should be + // activated) and the latter indicates that the interaction was cancelled (and + // the originally active window should remain active). + void CompleteCycling(); + void CancelCycling(); + + // Returns the WindowCycleList. + const WindowCycleList* window_cycle_list() const { + return window_cycle_list_.get(); + } + + private: + // Cycles to the next or previous window based on |direction|. + void Step(Direction direction); + + void StopCycling(); + + std::unique_ptr<WindowCycleList> window_cycle_list_; + + // Tracks what Window was active when starting to cycle and used to determine + // if the active Window changed in when ending cycling. + WmWindow* active_window_before_window_cycle_ = nullptr; + + // Non-null while actively cycling. + std::unique_ptr<WindowCycleEventFilter> event_filter_; + + base::Time cycle_start_time_; + + DISALLOW_COPY_AND_ASSIGN(WindowCycleController); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_CYCLE_CONTROLLER_H_
diff --git a/ash/common/wm/window_cycle_event_filter.h b/ash/common/wm/window_cycle_event_filter.h new file mode 100644 index 0000000..119179f --- /dev/null +++ b/ash/common/wm/window_cycle_event_filter.h
@@ -0,0 +1,21 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_CYCLE_EVENT_FILTER_H_ +#define ASH_COMMON_WM_WINDOW_CYCLE_EVENT_FILTER_H_ + +#include "ash/ash_export.h" + +namespace ash { + +// Created by WindowCycleController when cycling through windows. Eats all key +// events and stops cycling when the necessary key sequence is encountered. +class ASH_EXPORT WindowCycleEventFilter { + public: + virtual ~WindowCycleEventFilter() {} +}; + +} // namepsace ash + +#endif // ASH_COMMON_WM_WINDOW_CYCLE_EVENT_FILTER_H_
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc new file mode 100644 index 0000000..78c7a77 --- /dev/null +++ b/ash/common/wm/window_cycle_list.cc
@@ -0,0 +1,551 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_cycle_list.h" + +#include <list> +#include <map> + +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/command_line.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/canvas.h" +#include "ui/views/background.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/painter.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/wm/core/visibility_controller.h" + +namespace ash { + +namespace { + +bool g_disable_initial_delay = false; + +// Used for the highlight view and the shield (black background). +constexpr float kBackgroundCornerRadius = 4.f; + +// This background paints a |Painter| but fills the view's layer's size rather +// than the view's size. +class LayerFillBackgroundPainter : public views::Background { + public: + explicit LayerFillBackgroundPainter(std::unique_ptr<views::Painter> painter) + : painter_(std::move(painter)) {} + + ~LayerFillBackgroundPainter() override {} + + void Paint(gfx::Canvas* canvas, views::View* view) const override { + views::Painter::PaintPainterAt(canvas, painter_.get(), + gfx::Rect(view->layer()->size())); + } + + private: + std::unique_ptr<views::Painter> painter_; + + DISALLOW_COPY_AND_ASSIGN(LayerFillBackgroundPainter); +}; + +} // namespace + +// This view represents a single WmWindow by displaying a title and a thumbnail +// of the window's contents. +class WindowPreviewView : public views::View, public aura::WindowObserver { + public: + explicit WindowPreviewView(WmWindow* window) + : window_title_(new views::Label), + preview_background_(new views::View), + mirror_view_(window->CreateViewWithRecreatedLayers().release()), + window_observer_(this) { + window_observer_.Add(window->aura_window()); + window_title_->SetText(window->GetTitle()); + window_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + window_title_->SetEnabledColor(SK_ColorWHITE); + window_title_->SetAutoColorReadabilityEnabled(false); + // Background is not fully opaque, so subpixel rendering won't look good. + window_title_->SetSubpixelRenderingEnabled(false); + // The base font is 12pt (for English) so this comes out to 14pt. + const int kLabelSizeDelta = 2; + window_title_->SetFontList( + window_title_->font_list().DeriveWithSizeDelta(kLabelSizeDelta)); + const int kAboveLabelPadding = 5; + const int kBelowLabelPadding = 10; + window_title_->SetBorder( + views::CreateEmptyBorder(kAboveLabelPadding, 0, kBelowLabelPadding, 0)); + AddChildView(window_title_); + + // Preview padding is black at 50% opacity. + preview_background_->set_background( + views::Background::CreateSolidBackground( + SkColorSetA(SK_ColorBLACK, 0xFF / 2))); + AddChildView(preview_background_); + + AddChildView(mirror_view_); + + SetFocusBehavior(FocusBehavior::ALWAYS); + } + ~WindowPreviewView() override {} + + // views::View: + gfx::Size GetPreferredSize() const override { + gfx::Size size = GetSizeForPreviewArea(); + size.Enlarge(0, window_title_->GetPreferredSize().height()); + return size; + } + + void Layout() override { + const gfx::Size preview_area_size = GetSizeForPreviewArea(); + // The window title is positioned above the preview area. + window_title_->SetBounds(0, 0, width(), + height() - preview_area_size.height()); + + gfx::Rect preview_area_bounds(preview_area_size); + preview_area_bounds.set_y(height() - preview_area_size.height()); + mirror_view_->SetSize(GetMirrorViewScaledSize()); + if (mirror_view_->size() == preview_area_size) { + // Padding is not needed, hide the background and set the mirror view + // to take up the entire preview area. + mirror_view_->SetPosition(preview_area_bounds.origin()); + preview_background_->SetVisible(false); + return; + } + + // Padding is needed, so show the background and set the mirror view to be + // centered within it. + preview_background_->SetBoundsRect(preview_area_bounds); + preview_background_->SetVisible(true); + preview_area_bounds.ClampToCenteredSize(mirror_view_->size()); + mirror_view_->SetPosition(preview_area_bounds.origin()); + } + + void GetAccessibleNodeData(ui::AXNodeData* node_data) override { + node_data->role = ui::AX_ROLE_WINDOW; + node_data->SetName(window_title_->text()); + } + + // aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override { + window_observer_.Remove(window); + } + + void OnWindowTitleChanged(aura::Window* window) override { + window_title_->SetText(window->GetTitle()); + } + + private: + // The maximum width of a window preview. + static const int kMaxPreviewWidth = 512; + // All previews are the same height (this is achieved via a combination of + // scaling and padding). + static const int kFixedPreviewHeight = 256; + + // Returns the size for the mirror view, scaled to fit within the max bounds. + // Scaling is always 1:1 and we only scale down, never up. + gfx::Size GetMirrorViewScaledSize() const { + gfx::Size mirror_pref_size = mirror_view_->GetPreferredSize(); + + if (mirror_pref_size.width() > kMaxPreviewWidth || + mirror_pref_size.height() > kFixedPreviewHeight) { + float scale = std::min( + kMaxPreviewWidth / static_cast<float>(mirror_pref_size.width()), + kFixedPreviewHeight / static_cast<float>(mirror_pref_size.height())); + mirror_pref_size = + gfx::ScaleToFlooredSize(mirror_pref_size, scale, scale); + } + + return mirror_pref_size; + } + + // Returns the size for the entire preview area (mirror view and additional + // padding). All previews will be the same height, so if the mirror view isn't + // tall enough we will add top and bottom padding. Previews can range in width + // from kMaxPreviewWidth down to half that value. Again, padding will be added + // to the sides to achieve this if the preview is too narrow. + gfx::Size GetSizeForPreviewArea() const { + gfx::Size mirror_size = GetMirrorViewScaledSize(); + float aspect_ratio = + static_cast<float>(mirror_size.width()) / mirror_size.height(); + gfx::Size preview_size = mirror_size; + // Very narrow windows get vertical bars of padding on the sides. + if (aspect_ratio < 0.5f) + preview_size.set_width(mirror_size.height() / 2); + + // All previews are the same height (this may add padding on top and + // bottom). + preview_size.set_height(kFixedPreviewHeight); + // Previews should never be narrower than half their max width (128dip). + preview_size.set_width( + std::max(preview_size.width(), kMaxPreviewWidth / 2)); + + return preview_size; + } + + // Displays the title of the window above the preview. + views::Label* window_title_; + // When visible, shows a darkened background area behind |mirror_view_| + // (effectively padding the preview to fit the desired bounds). + views::View* preview_background_; + // The view that actually renders a thumbnail version of the window. + views::View* mirror_view_; + + ScopedObserver<aura::Window, aura::WindowObserver> window_observer_; + + DISALLOW_COPY_AND_ASSIGN(WindowPreviewView); +}; + +// A view that shows a collection of windows the user can tab through. +class WindowCycleView : public views::WidgetDelegateView { + public: + explicit WindowCycleView(const WindowCycleList::WindowList& windows) + : mirror_container_(new views::View()), + highlight_view_(new views::View()), + target_window_(nullptr) { + DCHECK(!windows.empty()); + SetPaintToLayer(); + layer()->SetFillsBoundsOpaquely(false); + layer()->SetMasksToBounds(true); + layer()->SetOpacity(0.0); + { + ui::ScopedLayerAnimationSettings animate_fade(layer()->GetAnimator()); + animate_fade.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(100)); + layer()->SetOpacity(1.0); + } + + const int kInsideBorderPaddingDip = 64; + const int kBetweenChildPaddingDip = 10; + views::BoxLayout* layout = new views::BoxLayout( + views::BoxLayout::kHorizontal, kInsideBorderPaddingDip, + kInsideBorderPaddingDip, kBetweenChildPaddingDip); + layout->set_cross_axis_alignment( + views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); + mirror_container_->SetLayoutManager(layout); + mirror_container_->SetPaintToLayer(); + mirror_container_->layer()->SetFillsBoundsOpaquely(false); + + for (WmWindow* window : windows) { + // |mirror_container_| owns |view|. + views::View* view = new WindowPreviewView(window); + window_view_map_[window] = view; + mirror_container_->AddChildView(view); + } + + // The background needs to be painted to fill the layer, not the View, + // because the layer animates bounds changes but the View's bounds change + // immediately. + highlight_view_->set_background(new LayerFillBackgroundPainter( + views::Painter::CreateRoundRectWith1PxBorderPainter( + SkColorSetA(SK_ColorWHITE, 0x4D), SkColorSetA(SK_ColorWHITE, 0x33), + kBackgroundCornerRadius))); + highlight_view_->SetPaintToLayer(); + + highlight_view_->layer()->SetFillsBoundsOpaquely(false); + + AddChildView(highlight_view_); + AddChildView(mirror_container_); + } + + ~WindowCycleView() override {} + + void SetTargetWindow(WmWindow* target) { + target_window_ = target; + if (GetWidget()) { + Layout(); + if (target_window_) + window_view_map_[target_window_]->RequestFocus(); + } + } + + void HandleWindowDestruction(WmWindow* destroying_window, + WmWindow* new_target) { + auto view_iter = window_view_map_.find(destroying_window); + views::View* preview = view_iter->second; + views::View* parent = preview->parent(); + DCHECK_EQ(mirror_container_, parent); + window_view_map_.erase(view_iter); + delete preview; + // With one of its children now gone, we must re-layout |mirror_container_|. + // This must happen before SetTargetWindow() to make sure our own Layout() + // works correctly when it's calculating highlight bounds. + parent->Layout(); + SetTargetWindow(new_target); + } + + void DestroyContents() { + window_view_map_.clear(); + RemoveAllChildViews(true); + } + + // views::WidgetDelegateView overrides: + gfx::Size GetPreferredSize() const override { + return mirror_container_->GetPreferredSize(); + } + + void Layout() override { + if (!target_window_ || bounds().IsEmpty()) + return; + + bool first_layout = mirror_container_->bounds().IsEmpty(); + // If |mirror_container_| has not yet been laid out, we must lay it and its + // descendants out so that the calculations based on |target_view| work + // properly. + if (first_layout) + mirror_container_->SizeToPreferredSize(); + + views::View* target_view = window_view_map_[target_window_]; + gfx::RectF target_bounds(target_view->GetLocalBounds()); + views::View::ConvertRectToTarget(target_view, mirror_container_, + &target_bounds); + gfx::Rect container_bounds(mirror_container_->GetPreferredSize()); + // Case one: the container is narrower than the screen. Center the + // container. + int x_offset = (width() - container_bounds.width()) / 2; + if (x_offset < 0) { + // Case two: the container is wider than the screen. Center the target + // view by moving the list just enough to ensure the target view is in the + // center. + x_offset = width() / 2 - + mirror_container_->GetMirroredXInView( + target_bounds.CenterPoint().x()); + + // However, the container must span the screen, i.e. the maximum x is 0 + // and the minimum for its right boundary is the width of the screen. + x_offset = std::min(x_offset, 0); + x_offset = std::max(x_offset, width() - container_bounds.width()); + } + container_bounds.set_x(x_offset); + mirror_container_->SetBoundsRect(container_bounds); + + // Calculate the target preview's bounds relative to |this|. + views::View::ConvertRectToTarget(mirror_container_, this, &target_bounds); + const int kHighlightPaddingDip = 5; + target_bounds.Inset(gfx::InsetsF(-kHighlightPaddingDip)); + target_bounds.set_x( + GetMirroredXWithWidthInView(target_bounds.x(), target_bounds.width())); + highlight_view_->SetBoundsRect(gfx::ToEnclosingRect(target_bounds)); + + // Enable animations only after the first Layout() pass. + if (first_layout) { + // The preview list animates bounds changes (other animatable properties + // never change). + mirror_container_->layer()->SetAnimator( + ui::LayerAnimator::CreateImplicitAnimator()); + // The selection highlight also animates all bounds changes and never + // changes other animatable properties. + highlight_view_->layer()->SetAnimator( + ui::LayerAnimator::CreateImplicitAnimator()); + } + } + + void OnPaintBackground(gfx::Canvas* canvas) override { + // We can't set a bg on the mirror container itself because the highlight + // view needs to be on top of the bg but behind the target windows. + const gfx::RectF shield_bounds(mirror_container_->bounds()); + cc::PaintFlags flags; + flags.setColor(SkColorSetA(SK_ColorBLACK, 0xE6)); + flags.setStyle(cc::PaintFlags::kFill_Style); + float corner_radius = 0.f; + if (shield_bounds.width() < width()) { + flags.setAntiAlias(true); + corner_radius = kBackgroundCornerRadius; + } + canvas->DrawRoundRect(shield_bounds, corner_radius, flags); + } + + View* GetInitiallyFocusedView() override { + return window_view_map_[target_window_]; + } + + WmWindow* target_window() { return target_window_; } + + private: + std::map<WmWindow*, views::View*> window_view_map_; + views::View* mirror_container_; + views::View* highlight_view_; + WmWindow* target_window_; + + DISALLOW_COPY_AND_ASSIGN(WindowCycleView); +}; + +WindowCycleList::WindowCycleList(const WindowList& windows) + : windows_(windows), + screen_observer_(this) { + if (!ShouldShowUi()) + WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(true); + + for (WmWindow* window : windows_) + window->aura_window()->AddObserver(this); + + if (ShouldShowUi()) { + if (g_disable_initial_delay) { + InitWindowCycleView(); + } else { + show_ui_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), + this, &WindowCycleList::InitWindowCycleView); + } + } +} + +WindowCycleList::~WindowCycleList() { + if (!ShouldShowUi()) + WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(false); + + for (WmWindow* window : windows_) + window->aura_window()->RemoveObserver(this); + + if (!windows_.empty() && user_did_accept_) { + WmWindow* target_window = windows_[current_index_]; + target_window->Show(); + target_window->GetWindowState()->Activate(); + } + + if (cycle_ui_widget_) + cycle_ui_widget_->Close(); + + // |this| is responsible for notifying |cycle_view_| when windows are + // destroyed. Since |this| is going away, clobber |cycle_view_|. Otherwise + // there will be a race where a window closes after now but before the + // Widget::Close() call above actually destroys |cycle_view_|. See + // crbug.com/681207 + if (cycle_view_) + cycle_view_->DestroyContents(); +} + +void WindowCycleList::Step(WindowCycleController::Direction direction) { + if (windows_.empty()) + return; + + // When there is only one window, we should give feedback to the user. If the + // window is minimized, we should also show it. + if (windows_.size() == 1) { + windows_[0]->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); + windows_[0]->Show(); + windows_[0]->GetWindowState()->Activate(); + return; + } + + DCHECK(static_cast<size_t>(current_index_) < windows_.size()); + + if (!cycle_view_ && current_index_ == 0) { + // Special case the situation where we're cycling forward but the MRU window + // is not active. This occurs when all windows are minimized. The starting + // window should be the first one rather than the second. + if (direction == WindowCycleController::FORWARD && !windows_[0]->IsActive()) + current_index_ = -1; + } + + // We're in a valid cycle, so step forward or backward. + current_index_ += direction == WindowCycleController::FORWARD ? 1 : -1; + + // Wrap to window list size. + current_index_ = (current_index_ + windows_.size()) % windows_.size(); + DCHECK(windows_[current_index_]); + + if (ShouldShowUi()) { + if (current_index_ > 1) + InitWindowCycleView(); + + if (cycle_view_) + cycle_view_->SetTargetWindow(windows_[current_index_]); + } +} + +// static +void WindowCycleList::DisableInitialDelayForTesting() { + g_disable_initial_delay = true; +} + +void WindowCycleList::OnWindowDestroying(aura::Window* window) { + window->RemoveObserver(this); + + WindowList::iterator i = + std::find(windows_.begin(), windows_.end(), WmWindow::Get(window)); + // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed. + CHECK(i != windows_.end()); + int removed_index = static_cast<int>(i - windows_.begin()); + windows_.erase(i); + if (current_index_ > removed_index || + current_index_ == static_cast<int>(windows_.size())) { + current_index_--; + } + + if (cycle_view_) { + WmWindow* new_target_window = + windows_.empty() ? nullptr : windows_[current_index_]; + cycle_view_->HandleWindowDestruction(WmWindow::Get(window), + new_target_window); + if (windows_.empty()) { + // This deletes us. + WmShell::Get()->window_cycle_controller()->CancelCycling(); + return; + } + } +} + +void WindowCycleList::OnDisplayAdded(const display::Display& new_display) {} + +void WindowCycleList::OnDisplayRemoved(const display::Display& old_display) {} + +void WindowCycleList::OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) { + if (cycle_ui_widget_ && + display.id() == + display::Screen::GetScreen() + ->GetDisplayNearestWindow(cycle_ui_widget_->GetNativeView()) + .id() && + (changed_metrics & (DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_ROTATION))) { + WmShell::Get()->window_cycle_controller()->CancelCycling(); + // |this| is deleted. + return; + } +} + +bool WindowCycleList::ShouldShowUi() { + return windows_.size() > 1; +} + +void WindowCycleList::InitWindowCycleView() { + if (cycle_view_) + return; + + cycle_view_ = new WindowCycleView(windows_); + cycle_view_->SetTargetWindow(windows_[current_index_]); + + views::Widget* widget = new views::Widget; + views::Widget::InitParams params; + params.delegate = cycle_view_; + params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.accept_events = true; + params.name = "WindowCycleList (Alt+Tab)"; + // TODO(estade): make sure nothing untoward happens when the lock screen + // or a system modal dialog is shown. + WmWindow* root_window = WmShell::Get()->GetRootWindowForNewWindows(); + root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + widget, kShellWindowId_OverlayContainer, ¶ms); + gfx::Rect widget_rect = root_window->GetDisplayNearestWindow().bounds(); + const int widget_height = cycle_view_->GetPreferredSize().height(); + widget_rect.set_y(widget_rect.y() + + (widget_rect.height() - widget_height) / 2); + widget_rect.set_height(widget_height); + params.bounds = widget_rect; + widget->Init(params); + + screen_observer_.Add(display::Screen::GetScreen()); + widget->Show(); + cycle_ui_widget_ = widget; +} + +} // namespace ash
diff --git a/ash/common/wm/window_cycle_list.h b/ash/common/wm/window_cycle_list.h new file mode 100644 index 0000000..36e89409 --- /dev/null +++ b/ash/common/wm/window_cycle_list.h
@@ -0,0 +1,110 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_CYCLE_LIST_H_ +#define ASH_COMMON_WM_WINDOW_CYCLE_LIST_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/common/wm/window_cycle_controller.h" +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "base/timer/timer.h" +#include "ui/aura/window_observer.h" +#include "ui/display/display_observer.h" + +namespace display { +class Screen; +} + +namespace views { +class Widget; +} + +namespace ash { + +class WindowCycleView; + +// Tracks a set of Windows that can be stepped through. This class is used by +// the WindowCycleController. +class ASH_EXPORT WindowCycleList : public aura::WindowObserver, + public display::DisplayObserver { + public: + using WindowList = std::vector<WmWindow*>; + + explicit WindowCycleList(const WindowList& windows); + ~WindowCycleList() override; + + bool empty() const { return windows_.empty(); } + + // Cycles to the next or previous window based on |direction|. + void Step(WindowCycleController::Direction direction); + + int current_index() const { return current_index_; } + + void set_user_did_accept(bool user_did_accept) { + user_did_accept_ = user_did_accept; + } + + private: + friend class WindowCycleControllerTest; + + static void DisableInitialDelayForTesting(); + const views::Widget* widget() const { return cycle_ui_widget_; } + + const WindowList& windows() const { return windows_; } + + // aura::WindowObserver overrides: + // There is a chance a window is destroyed, for example by JS code. We need to + // take care of that even if it is not intended for the user to close a window + // while window cycling. + void OnWindowDestroying(aura::Window* window) override; + + // display::DisplayObserver overrides: + void OnDisplayAdded(const display::Display& new_display) override; + void OnDisplayRemoved(const display::Display& old_display) override; + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) override; + + // Returns true if the window list overlay should be shown. + bool ShouldShowUi(); + + // Initializes and shows |cycle_view_|. + void InitWindowCycleView(); + + // List of weak pointers to windows to use while cycling with the keyboard. + // List is built when the user initiates the gesture (i.e. hits alt-tab the + // first time) and is emptied when the gesture is complete (i.e. releases the + // alt key). + WindowList windows_; + + // Current position in the |windows_|. Can be used to query selection depth, + // i.e., the position of an active window in a global MRU ordering. + int current_index_ = 0; + + // True if the user accepted the window switch (as opposed to cancelling or + // interrupting the interaction). + bool user_did_accept_ = false; + + // The top level View for the window cycle UI. May be null if the UI is not + // showing. + WindowCycleView* cycle_view_ = nullptr; + + // The widget that hosts the window cycle UI. + views::Widget* cycle_ui_widget_ = nullptr; + + // The window list will dismiss if the display metrics change. + ScopedObserver<display::Screen, display::DisplayObserver> screen_observer_; + + // A timer to delay showing the UI. Quick Alt+Tab should not flash a UI. + base::OneShotTimer show_ui_timer_; + + DISALLOW_COPY_AND_ASSIGN(WindowCycleList); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_CYCLE_LIST_H_
diff --git a/ash/common/wm/window_dimmer.cc b/ash/common/wm/window_dimmer.cc new file mode 100644 index 0000000..c90d806 --- /dev/null +++ b/ash/common/wm/window_dimmer.cc
@@ -0,0 +1,88 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_dimmer.h" + +#include <memory> + +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "base/time/time.h" +#include "ui/aura/window.h" +#include "ui/compositor/layer.h" +#include "ui/wm/core/window_animations.h" + +namespace ash { +namespace { + +const int kDefaultDimAnimationDurationMs = 200; + +const float kDefaultDimOpacity = 0.5f; + +} // namespace + +WindowDimmer::WindowDimmer(WmWindow* parent) + : parent_(parent), + window_(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_SOLID_COLOR)) { + window_->SetVisibilityChangesAnimated(); + window_->SetVisibilityAnimationType( + ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); + window_->SetVisibilityAnimationDuration( + base::TimeDelta::FromMilliseconds(kDefaultDimAnimationDurationMs)); + window_->aura_window()->AddObserver(this); + + SetDimOpacity(kDefaultDimOpacity); + + parent->AddChild(window_); + parent->aura_window()->AddObserver(this); + parent->StackChildAtTop(window_); + + window_->SetBounds(gfx::Rect(parent_->GetBounds().size())); +} + +WindowDimmer::~WindowDimmer() { + if (parent_) + parent_->aura_window()->RemoveObserver(this); + if (window_) { + window_->aura_window()->RemoveObserver(this); + window_->Destroy(); + } +} + +void WindowDimmer::SetDimOpacity(float target_opacity) { + DCHECK(window_); + window_->GetLayer()->SetColor( + SkColorSetA(SK_ColorBLACK, 255 * target_opacity)); +} + +void WindowDimmer::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (WmWindow::Get(window) == parent_) + window_->SetBounds(gfx::Rect(new_bounds.size())); +} + +void WindowDimmer::OnWindowDestroying(aura::Window* window) { + if (WmWindow::Get(window) == parent_) { + parent_->aura_window()->RemoveObserver(this); + parent_ = nullptr; + } else { + DCHECK_EQ(window_, WmWindow::Get(window)); + window_->aura_window()->RemoveObserver(this); + window_ = nullptr; + } +} + +void WindowDimmer::OnWindowHierarchyChanging( + const HierarchyChangeParams& params) { + if (WmWindow::Get(params.receiver) == window_ && + params.target == params.receiver) { + // This may happen on a display change or some unexpected condition. Hide + // the window to ensure it isn't obscuring the wrong thing. + window_->Hide(); + } +} + +} // namespace ash
diff --git a/ash/wm/window_dimmer.h b/ash/common/wm/window_dimmer.h similarity index 100% rename from ash/wm/window_dimmer.h rename to ash/common/wm/window_dimmer.h
diff --git a/ash/common/wm/window_parenting_utils.cc b/ash/common/wm/window_parenting_utils.cc new file mode 100644 index 0000000..8a868a22 --- /dev/null +++ b/ash/common/wm/window_parenting_utils.cc
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_parenting_utils.h" + +#include "ash/common/wm_window.h" + +namespace ash { +namespace wm { + +void ReparentChildWithTransientChildren(WmWindow* child, + WmWindow* old_parent, + WmWindow* new_parent) { + if (child->GetParent() == old_parent) + new_parent->AddChild(child); + ReparentTransientChildrenOfChild(child, old_parent, new_parent); +} + +void ReparentTransientChildrenOfChild(WmWindow* child, + WmWindow* old_parent, + WmWindow* new_parent) { + for (WmWindow* transient_child : child->GetTransientChildren()) + ReparentChildWithTransientChildren(transient_child, old_parent, new_parent); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/window_parenting_utils.h b/ash/common/wm/window_parenting_utils.h new file mode 100644 index 0000000..864e0aa1 --- /dev/null +++ b/ash/common/wm/window_parenting_utils.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_PARENTING_UTILS_H_ +#define ASH_COMMON_WM_WINDOW_PARENTING_UTILS_H_ + +namespace ash { + +class WmWindow; + +namespace wm { + +// Changes the parent of a |child| and all its transient children that are +// themselves children of |old_parent| to |new_parent|. +void ReparentChildWithTransientChildren(WmWindow* child, + WmWindow* old_parent, + WmWindow* new_parent); + +// Changes the parent of all transient children of a |child| to |new_parent|. +// Does not change parent of the transient children that are not themselves +// children of |old_parent|. +void ReparentTransientChildrenOfChild(WmWindow* child, + WmWindow* old_parent, + WmWindow* new_parent); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_PARENTING_UTILS_H_
diff --git a/ash/common/wm/window_positioner.cc b/ash/common/wm/window_positioner.cc new file mode 100644 index 0000000..dcea7bf --- /dev/null +++ b/ash/common/wm/window_positioner.cc
@@ -0,0 +1,564 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_positioner.h" + +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/compositor/layer.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/insets.h" + +namespace ash { + +const int WindowPositioner::kMinimumWindowOffset = 32; + +// The number of pixels which are kept free top, left and right when a window +// gets positioned to its default location. +// static +const int WindowPositioner::kDesktopBorderSize = 16; + +// Maximum width of a window even if there is more room on the desktop. +// static +const int WindowPositioner::kMaximumWindowWidth = 1100; + +namespace { + +// When a window gets opened in default mode and the screen is less than or +// equal to this width, the window will get opened in maximized mode. This value +// can be reduced to a "tame" number if the feature is disabled. +const int kForceMaximizeWidthLimit = 1366; + +// The time in milliseconds which should be used to visually move a window +// through an automatic "intelligent" window management option. +const int kWindowAutoMoveDurationMS = 125; + +// If set to true all window repositioning actions will be ignored. Set through +// WindowPositioner::SetIgnoreActivations(). +static bool disable_auto_positioning = false; + +// If set to true, by default the first window in ASH will be maximized. +static bool maximize_first_window = false; + +// Check if any management should be performed (with a given |window|). +bool UseAutoWindowManager(const WmWindow* window) { + if (disable_auto_positioning) + return false; + const wm::WindowState* window_state = window->GetWindowState(); + return !window_state->is_dragged() && window_state->window_position_managed(); +} + +// Check if a given |window| can be managed. This includes that its +// state is not minimized/maximized/fullscreen/the user has changed +// its size by hand already. It furthermore checks for the +// WindowIsManaged status. +bool WindowPositionCanBeManaged(const WmWindow* window) { + if (disable_auto_positioning) + return false; + const wm::WindowState* window_state = window->GetWindowState(); + return window_state->window_position_managed() && + !window_state->IsMinimized() && !window_state->IsMaximized() && + !window_state->IsFullscreen() && !window_state->IsPinned() && + !window_state->bounds_changed_by_user(); +} + +// Move the given |bounds| on the available |work_area| in the direction +// indicated by |move_right|. If |move_right| is true, the rectangle gets moved +// to the right edge, otherwise to the left one. +bool MoveRectToOneSide(const gfx::Rect& work_area, + bool move_right, + gfx::Rect* bounds) { + if (move_right) { + if (work_area.right() > bounds->right()) { + bounds->set_x(work_area.right() - bounds->width()); + return true; + } + } else { + if (work_area.x() < bounds->x()) { + bounds->set_x(work_area.x()); + return true; + } + } + return false; +} + +// Move a |window| to new |bounds|. Animate if desired by user. +// Moves the transient children of the |window| as well by the same |offset| as +// the parent |window|. +void SetBoundsAndOffsetTransientChildren(WmWindow* window, + const gfx::Rect& bounds, + const gfx::Rect& work_area, + const gfx::Vector2d& offset) { + std::vector<WmWindow*> transient_children = window->GetTransientChildren(); + for (WmWindow* transient_child : transient_children) { + gfx::Rect child_bounds = transient_child->GetBounds(); + gfx::Rect new_child_bounds = child_bounds + offset; + if ((child_bounds.x() <= work_area.x() && + new_child_bounds.x() <= work_area.x()) || + (child_bounds.right() >= work_area.right() && + new_child_bounds.right() >= work_area.right())) { + continue; + } + if (new_child_bounds.right() > work_area.right()) + new_child_bounds.set_x(work_area.right() - bounds.width()); + else if (new_child_bounds.x() < work_area.x()) + new_child_bounds.set_x(work_area.x()); + SetBoundsAndOffsetTransientChildren(transient_child, new_child_bounds, + work_area, offset); + } + + window->SetBoundsWithTransitionDelay( + bounds, base::TimeDelta::FromMilliseconds(kWindowAutoMoveDurationMS)); +} + +// Move a |window| to new |bounds|. Animate if desired by user. +// Note: The function will do nothing if the bounds did not change. +void SetBoundsAnimated(WmWindow* window, + const gfx::Rect& bounds, + const gfx::Rect& work_area) { + gfx::Rect old_bounds = window->GetTargetBounds(); + if (bounds == old_bounds) + return; + gfx::Vector2d offset(bounds.origin() - old_bounds.origin()); + SetBoundsAndOffsetTransientChildren(window, bounds, work_area, offset); +} + +// Move |window| into the center of the screen - or restore it to the previous +// position. +void AutoPlaceSingleWindow(WmWindow* window, bool animated) { + gfx::Rect work_area = wm::GetDisplayWorkAreaBoundsInParent(window); + gfx::Rect bounds = window->GetBounds(); + const gfx::Rect* user_defined_area = + window->GetWindowState()->pre_auto_manage_window_bounds(); + if (user_defined_area) { + bounds = *user_defined_area; + wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area, &bounds); + } else { + // Center the window (only in x). + bounds.set_x(work_area.x() + (work_area.width() - bounds.width()) / 2); + } + + if (animated) + SetBoundsAnimated(window, bounds, work_area); + else + window->SetBounds(bounds); +} + +// Get the first open (non minimized) window which is on the screen defined. +WmWindow* GetReferenceWindow(const WmWindow* root_window, + const WmWindow* exclude, + bool* single_window) { + if (single_window) + *single_window = true; + // Get the active window. + WmWindow* active = root_window->GetShell()->GetActiveWindow(); + if (active && active->GetRootWindow() != root_window) + active = NULL; + + // Get a list of all windows. + const std::vector<WmWindow*> windows = root_window->GetShell() + ->mru_window_tracker() + ->BuildWindowListIgnoreModal(); + + if (windows.empty()) + return nullptr; + + int index = 0; + // Find the index of the current active window. + if (active) + index = std::find(windows.begin(), windows.end(), active) - windows.begin(); + + // Scan the cycle list backwards to see which is the second topmost window + // (and so on). Note that we might cycle a few indices twice if there is no + // suitable window. However - since the list is fairly small this should be + // very fast anyways. + WmWindow* found = nullptr; + for (int i = index + windows.size(); i >= 0; i--) { + WmWindow* window = windows[i % windows.size()]; + while (window->GetTransientParent()) + window = window->GetTransientParent(); + if (window != exclude && window->GetType() == ui::wm::WINDOW_TYPE_NORMAL && + window->GetRootWindow() == root_window && + window->GetTargetVisibility() && + window->GetWindowState()->window_position_managed()) { + if (found && found != window) { + // no need to check !single_window because the function must have + // been already returned in the "if (!single_window)" below. + *single_window = false; + return found; + } + found = window; + // If there is no need to check single window, return now. + if (!single_window) + return found; + } + } + return found; +} + +} // namespace + +// static +int WindowPositioner::GetForceMaximizedWidthLimit() { + return kForceMaximizeWidthLimit; +} + +// static +void WindowPositioner::GetBoundsAndShowStateForNewWindow( + const WmWindow* new_window, + bool is_saved_bounds, + ui::WindowShowState show_state_in, + gfx::Rect* bounds_in_out, + ui::WindowShowState* show_state_out) { + // Always open new window in the target display. + WmWindow* target = WmShell::Get()->GetRootWindowForNewWindows(); + + WmWindow* top_window = GetReferenceWindow(target, nullptr, nullptr); + // Our window should not have any impact if we are already on top. + if (top_window == new_window) + top_window = nullptr; + + // If there is no valid other window we take and adjust the passed coordinates + // and show state. + if (!top_window) { + gfx::Rect work_area = target->GetDisplayNearestWindow().work_area(); + + bounds_in_out->AdjustToFit(work_area); + // Use adjusted saved bounds, if there is one. + if (is_saved_bounds) + return; + + if (show_state_in == ui::SHOW_STATE_DEFAULT) { + const bool maximize_first_window_on_first_run = + target->GetShell()->IsForceMaximizeOnFirstRun(); + // We want to always open maximized on "small screens" or when policy + // tells us to. + const bool set_maximized = + maximize_first_window || + ((work_area.width() <= GetForceMaximizedWidthLimit() || + maximize_first_window_on_first_run) && + (!new_window || !new_window->GetWindowState()->IsFullscreen())); + + if (set_maximized) + *show_state_out = ui::SHOW_STATE_MAXIMIZED; + } + return; + } + + wm::WindowState* top_window_state = top_window->GetWindowState(); + bool maximized = top_window_state->IsMaximized(); + // We ignore the saved show state, but look instead for the top level + // window's show state. + if (show_state_in == ui::SHOW_STATE_DEFAULT) { + *show_state_out = + maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_DEFAULT; + } + + if (maximized || top_window_state->IsFullscreen()) { + bool has_restore_bounds = top_window_state->HasRestoreBounds(); + if (has_restore_bounds) { + // For a maximized/fullscreen window ignore the real bounds of + // the top level window and use its restore bounds + // instead. Offset the bounds to prevent the windows from + // overlapping exactly when restored. + *bounds_in_out = + top_window_state->GetRestoreBoundsInScreen() + + gfx::Vector2d(kMinimumWindowOffset, kMinimumWindowOffset); + } + if (is_saved_bounds || has_restore_bounds) { + gfx::Rect work_area = target->GetDisplayNearestWindow().work_area(); + bounds_in_out->AdjustToFit(work_area); + // Use adjusted saved bounds or restore bounds, if there is one. + return; + } + } + + // Use the size of the other window. The window's bound will be rearranged + // in ash::WorkspaceLayoutManager using this location. + *bounds_in_out = top_window->GetBoundsInScreen(); +} + +// static +void WindowPositioner::RearrangeVisibleWindowOnHideOrRemove( + const WmWindow* removed_window) { + if (!UseAutoWindowManager(removed_window)) + return; + // Find a single open browser window. + bool single_window; + WmWindow* other_shown_window = GetReferenceWindow( + removed_window->GetRootWindow(), removed_window, &single_window); + if (!other_shown_window || !single_window || + !WindowPositionCanBeManaged(other_shown_window)) + return; + AutoPlaceSingleWindow(other_shown_window, true); +} + +// static +bool WindowPositioner::DisableAutoPositioning(bool ignore) { + bool old_state = disable_auto_positioning; + disable_auto_positioning = ignore; + return old_state; +} + +// static +void WindowPositioner::RearrangeVisibleWindowOnShow(WmWindow* added_window) { + wm::WindowState* added_window_state = added_window->GetWindowState(); + if (!added_window->GetTargetVisibility()) + return; + + if (!UseAutoWindowManager(added_window) || + added_window_state->bounds_changed_by_user()) { + if (added_window_state->minimum_visibility()) { + // Guarantee minimum visibility within the work area. + gfx::Rect work_area = wm::GetDisplayWorkAreaBoundsInParent(added_window); + gfx::Rect bounds = added_window->GetBounds(); + gfx::Rect new_bounds = bounds; + wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area, &new_bounds); + if (new_bounds != bounds) + added_window->SetBounds(new_bounds); + } + return; + } + // Find a single open managed window. + bool single_window; + WmWindow* other_shown_window = GetReferenceWindow( + added_window->GetRootWindow(), added_window, &single_window); + + if (!other_shown_window) { + // It could be that this window is the first window joining the workspace. + if (!WindowPositionCanBeManaged(added_window) || other_shown_window) + return; + // Since we might be going from 0 to 1 window, we have to arrange the new + // window to a good default. + AutoPlaceSingleWindow(added_window, false); + return; + } + + gfx::Rect other_bounds = other_shown_window->GetBounds(); + gfx::Rect work_area = wm::GetDisplayWorkAreaBoundsInParent(added_window); + bool move_other_right = + other_bounds.CenterPoint().x() > work_area.x() + work_area.width() / 2; + + // Push the other window to the size only if there are two windows left. + if (single_window) { + // When going from one to two windows both windows loose their + // "positioned by user" flags. + added_window_state->set_bounds_changed_by_user(false); + wm::WindowState* other_window_state = other_shown_window->GetWindowState(); + other_window_state->set_bounds_changed_by_user(false); + + if (WindowPositionCanBeManaged(other_shown_window)) { + // Don't override pre auto managed bounds as the current bounds + // may not be original. + if (!other_window_state->pre_auto_manage_window_bounds()) + other_window_state->SetPreAutoManageWindowBounds(other_bounds); + + // Push away the other window after remembering its current position. + if (MoveRectToOneSide(work_area, move_other_right, &other_bounds)) + SetBoundsAnimated(other_shown_window, other_bounds, work_area); + } + } + + // Remember the current location of the window if it's new and push + // it also to the opposite location if needed. Since it is just + // being shown, we do not need to animate it. + gfx::Rect added_bounds = added_window->GetBounds(); + if (!added_window_state->pre_auto_manage_window_bounds()) + added_window_state->SetPreAutoManageWindowBounds(added_bounds); + if (MoveRectToOneSide(work_area, !move_other_right, &added_bounds)) + added_window->SetBounds(added_bounds); +} + +WindowPositioner::WindowPositioner(WmShell* shell) + : shell_(shell), + pop_position_offset_increment_x(0), + pop_position_offset_increment_y(0), + popup_position_offset_from_screen_corner_x(0), + popup_position_offset_from_screen_corner_y(0), + last_popup_position_x_(0), + last_popup_position_y_(0) {} + +WindowPositioner::~WindowPositioner() {} + +gfx::Rect WindowPositioner::GetDefaultWindowBounds( + const display::Display& display) { + const gfx::Rect work_area = display.work_area(); + // There should be a 'desktop' border around the window at the left and right + // side. + int default_width = work_area.width() - 2 * kDesktopBorderSize; + // There should also be a 'desktop' border around the window at the top. + // Since the workspace excludes the tray area we only need one border size. + int default_height = work_area.height() - kDesktopBorderSize; + int offset_x = kDesktopBorderSize; + if (default_width > kMaximumWindowWidth) { + // The window should get centered on the screen and not follow the grid. + offset_x = (work_area.width() - kMaximumWindowWidth) / 2; + default_width = kMaximumWindowWidth; + } + return gfx::Rect(work_area.x() + offset_x, work_area.y() + kDesktopBorderSize, + default_width, default_height); +} + +gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Rect& old_pos) { + int grid = kMinimumWindowOffset; + popup_position_offset_from_screen_corner_x = grid; + popup_position_offset_from_screen_corner_y = grid; + if (!pop_position_offset_increment_x) { + // When the popup position increment is 0, the last popup position + // was not yet initialized. + last_popup_position_x_ = popup_position_offset_from_screen_corner_x; + last_popup_position_y_ = popup_position_offset_from_screen_corner_y; + } + pop_position_offset_increment_x = grid; + pop_position_offset_increment_y = grid; + // We handle the Multi monitor support by retrieving the active window's + // work area. + WmWindow* window = shell_->GetActiveWindow(); + const gfx::Rect work_area = + window && window->IsVisible() + ? window->GetDisplayNearestWindow().work_area() + : display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); + // Only try to reposition the popup when it is not spanning the entire + // screen. + if ((old_pos.width() + popup_position_offset_from_screen_corner_x >= + work_area.width()) || + (old_pos.height() + popup_position_offset_from_screen_corner_y >= + work_area.height())) + return AlignPopupPosition(old_pos, work_area, grid); + const gfx::Rect result = SmartPopupPosition(old_pos, work_area, grid); + if (!result.IsEmpty()) + return AlignPopupPosition(result, work_area, grid); + return NormalPopupPosition(old_pos, work_area); +} + +// static +void WindowPositioner::SetMaximizeFirstWindow(bool maximize) { + maximize_first_window = maximize; +} + +gfx::Rect WindowPositioner::NormalPopupPosition(const gfx::Rect& old_pos, + const gfx::Rect& work_area) { + int w = old_pos.width(); + int h = old_pos.height(); + // Note: The 'last_popup_position' is checked and kept relative to the + // screen size. The offsetting will be done in the last step when the + // target rectangle gets returned. + bool reset = false; + if (last_popup_position_y_ + h > work_area.height() || + last_popup_position_x_ + w > work_area.width()) { + // Popup does not fit on screen. Reset to next diagonal row. + last_popup_position_x_ -= last_popup_position_y_ - + popup_position_offset_from_screen_corner_x - + pop_position_offset_increment_x; + last_popup_position_y_ = popup_position_offset_from_screen_corner_y; + reset = true; + } + if (last_popup_position_x_ + w > work_area.width()) { + // Start again over. + last_popup_position_x_ = popup_position_offset_from_screen_corner_x; + last_popup_position_y_ = popup_position_offset_from_screen_corner_y; + reset = true; + } + int x = last_popup_position_x_; + int y = last_popup_position_y_; + if (!reset) { + last_popup_position_x_ += pop_position_offset_increment_x; + last_popup_position_y_ += pop_position_offset_increment_y; + } + return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); +} + +gfx::Rect WindowPositioner::SmartPopupPosition(const gfx::Rect& old_pos, + const gfx::Rect& work_area, + int grid) { + const std::vector<WmWindow*> windows = + shell_->mru_window_tracker()->BuildWindowListIgnoreModal(); + + std::vector<const gfx::Rect*> regions; + // Process the window list and check if we can bail immediately. + for (size_t i = 0; i < windows.size(); i++) { + // We only include opaque and visible windows. + if (windows[i] && windows[i]->IsVisible() && windows[i]->GetLayer() && + (windows[i]->GetLayer()->fills_bounds_opaquely() || + windows[i]->GetLayer()->GetTargetOpacity() == 1.0)) { + wm::WindowState* window_state = windows[i]->GetWindowState(); + // When any window is maximized we cannot find any free space. + if (window_state->IsMaximizedOrFullscreenOrPinned()) + return gfx::Rect(0, 0, 0, 0); + if (window_state->IsNormalOrSnapped()) + regions.push_back(&windows[i]->GetBounds()); + } + } + + if (regions.empty()) + return gfx::Rect(0, 0, 0, 0); + + int w = old_pos.width(); + int h = old_pos.height(); + int x_end = work_area.width() / 2; + int x, x_increment; + // We parse for a proper location on the screen. We do this in two runs: + // The first run will start from the left, parsing down, skipping any + // overlapping windows it will encounter until the popup's height can not + // be served anymore. Then the next grid position to the right will be + // taken, and the same cycle starts again. This will be repeated until we + // hit the middle of the screen (or we find a suitable location). + // In the second run we parse beginning from the right corner downwards and + // then to the left. + // When no location was found, an empty rectangle will be returned. + for (int run = 0; run < 2; run++) { + if (run == 0) { // First run: Start left, parse right till mid screen. + x = 0; + x_increment = pop_position_offset_increment_x; + } else { // Second run: Start right, parse left till mid screen. + x = work_area.width() - w; + x_increment = -pop_position_offset_increment_x; + } + // Note: The passing (x,y,w,h) window is always relative to the work area's + // origin. + for (; x_increment > 0 ? (x < x_end) : (x > x_end); x += x_increment) { + int y = 0; + while (y + h <= work_area.height()) { + size_t i; + for (i = 0; i < regions.size(); i++) { + if (regions[i]->Intersects( + gfx::Rect(x + work_area.x(), y + work_area.y(), w, h))) { + y = regions[i]->bottom() - work_area.y(); + break; + } + } + if (i >= regions.size()) + return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); + } + } + } + return gfx::Rect(0, 0, 0, 0); +} + +gfx::Rect WindowPositioner::AlignPopupPosition(const gfx::Rect& pos, + const gfx::Rect& work_area, + int grid) { + if (grid <= 1) + return pos; + + int x = pos.x() - (pos.x() - work_area.x()) % grid; + int y = pos.y() - (pos.y() - work_area.y()) % grid; + int w = pos.width(); + int h = pos.height(); + + // If the alignment was pushing the window out of the screen, we ignore the + // alignment for that call. + if (abs(pos.right() - work_area.right()) < grid) + x = work_area.right() - w; + if (abs(pos.bottom() - work_area.bottom()) < grid) + y = work_area.bottom() - h; + return gfx::Rect(x, y, w, h); +} + +} // namespace ash
diff --git a/ash/common/wm/window_positioner.h b/ash/common/wm/window_positioner.h new file mode 100644 index 0000000..85cdfd614 --- /dev/null +++ b/ash/common/wm/window_positioner.h
@@ -0,0 +1,131 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_POSITIONER_H_ +#define ASH_COMMON_WM_WINDOW_POSITIONER_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/base/ui_base_types.h" + +namespace display { +class Display; +} + +namespace gfx { +class Rect; +} + +namespace ash { + +class WmShell; +class WmWindow; + +namespace test { +class WindowPositionerTest; +} + +// WindowPositioner is used by the browser to move new popups automatically to +// a usable position on the closest work area (of the active window). +class ASH_EXPORT WindowPositioner { + public: + // When the screen resolution width is smaller then this size, The algorithm + // will default to maximized. + static int GetForceMaximizedWidthLimit(); + + // The number of pixels which are kept free top, left and right when a window + // gets positioned to its default location. + static const int kDesktopBorderSize; + + // Maximum width of a window even if there is more room on the desktop. + static const int kMaximumWindowWidth; + + // Computes and returns the bounds and show state for new window + // based on the parameter passed AND existing windows. |window| is + // the one this function will generate a bounds for and used to + // exclude the self window in making decision how to position the + // window. |window| can be (and in most case) NULL. + // |is_saved_bounds| indicates the |bounds_in_out| is the saved + // bounds. + static void GetBoundsAndShowStateForNewWindow( + const WmWindow* new_window, + bool is_saved_bounds, + ui::WindowShowState show_state_in, + gfx::Rect* bounds_in_out, + ui::WindowShowState* show_state_out); + + // Returns the default bounds for a window to be created in the |display|. + static gfx::Rect GetDefaultWindowBounds(const display::Display& display); + + // Check if after removal or hide of the given |removed_window| an + // automated desktop location management can be performed and + // rearrange accordingly. + static void RearrangeVisibleWindowOnHideOrRemove( + const WmWindow* removed_window); + + // Turn the automatic positioning logic temporarily off. Returns the previous + // state. + static bool DisableAutoPositioning(bool ignore); + + // Check if after insertion or showing of the given |added_window| + // an automated desktop location management can be performed and + // rearrange accordingly. + static void RearrangeVisibleWindowOnShow(WmWindow* added_window); + + explicit WindowPositioner(WmShell* shell); + ~WindowPositioner(); + + // Find a suitable screen position for a popup window and return it. The + // passed input position is only used to retrieve the width and height. + // The position is determined on the left / right / top / bottom first. If + // no smart space is found, the position will follow the standard what other + // operating systems do (default cascading style). + gfx::Rect GetPopupPosition(const gfx::Rect& old_pos); + + // Accessor to set a flag indicating whether the first window in ASH should + // be maximized. + static void SetMaximizeFirstWindow(bool maximize); + + protected: + friend class test::WindowPositionerTest; + + // Find a smart way to position the popup window. If there is no space this + // function will return an empty rectangle. + gfx::Rect SmartPopupPosition(const gfx::Rect& old_pos, + const gfx::Rect& work_area, + int grid); + + // Find the next available cascading popup position (on the given screen). + gfx::Rect NormalPopupPosition(const gfx::Rect& old_pos, + const gfx::Rect& work_area); + + // Align the location to the grid / snap to the right / bottom corner. + gfx::Rect AlignPopupPosition(const gfx::Rect& pos, + const gfx::Rect& work_area, + int grid); + + // Constant exposed for unittest. + static const int kMinimumWindowOffset; + + WmShell* shell_; + + // The offset in X and Y for the next popup which opens. + int pop_position_offset_increment_x; + int pop_position_offset_increment_y; + + // The position on the screen for the first popup which gets shown if no + // empty space can be found. + int popup_position_offset_from_screen_corner_x; + int popup_position_offset_from_screen_corner_y; + + // The last used position. + int last_popup_position_x_; + int last_popup_position_y_; + + DISALLOW_COPY_AND_ASSIGN(WindowPositioner); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_POSITIONER_H_
diff --git a/ash/common/wm/window_positioning_utils.cc b/ash/common/wm/window_positioning_utils.cc new file mode 100644 index 0000000..babed2f4 --- /dev/null +++ b/ash/common/wm/window_positioning_utils.cc
@@ -0,0 +1,201 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_positioning_utils.h" + +#include <algorithm> + +#include "ash/common/wm/system_modal_container_layout_manager.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ui/aura/window_tracker.h" +#include "ui/display/display.h" +#include "ui/display/types/display_constants.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" + +namespace ash { +namespace wm { + +namespace { + +// Returns the default width of a snapped window. +int GetDefaultSnappedWindowWidth(WmWindow* window) { + const float kSnappedWidthWorkspaceRatio = 0.5f; + + int work_area_width = GetDisplayWorkAreaBoundsInParent(window).width(); + int min_width = window->GetMinimumSize().width(); + int ideal_width = + static_cast<int>(work_area_width * kSnappedWidthWorkspaceRatio); + return std::min(work_area_width, std::max(ideal_width, min_width)); +} + +// Return true if the window or one of its ancestor returns true from +// IsLockedToRoot(). +bool IsWindowOrAncestorLockedToRoot(const WmWindow* window) { + return window && (window->IsLockedToRoot() || + IsWindowOrAncestorLockedToRoot(window->GetParent())); +} + +// Move all transient children to |dst_root|, including the ones in +// the child windows and transient children of the transient children. +void MoveAllTransientChildrenToNewRoot(const display::Display& display, + WmWindow* window) { + WmWindow* dst_root = + Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow(); + for (WmWindow* transient_child : window->GetTransientChildren()) { + const int container_id = transient_child->GetParent()->GetShellWindowId(); + DCHECK_GE(container_id, 0); + WmWindow* container = dst_root->GetChildByShellWindowId(container_id); + const gfx::Rect transient_child_bounds_in_screen = + transient_child->GetBoundsInScreen(); + container->AddChild(transient_child); + transient_child->SetBoundsInScreen(transient_child_bounds_in_screen, + display); + + // Transient children may have transient children. + MoveAllTransientChildrenToNewRoot(display, transient_child); + } + // Move transient children of the child windows if any. + for (WmWindow* child : window->GetChildren()) + MoveAllTransientChildrenToNewRoot(display, child); +} + +} // namespace + +void AdjustBoundsSmallerThan(const gfx::Size& max_size, gfx::Rect* bounds) { + bounds->set_width(std::min(bounds->width(), max_size.width())); + bounds->set_height(std::min(bounds->height(), max_size.height())); +} + +void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& visible_area, + int min_width, + int min_height, + gfx::Rect* bounds) { + AdjustBoundsSmallerThan(visible_area.size(), bounds); + + min_width = std::min(min_width, visible_area.width()); + min_height = std::min(min_height, visible_area.height()); + + if (bounds->right() < visible_area.x() + min_width) { + bounds->set_x(visible_area.x() + std::min(bounds->width(), min_width) - + bounds->width()); + } else if (bounds->x() > visible_area.right() - min_width) { + bounds->set_x(visible_area.right() - std::min(bounds->width(), min_width)); + } + if (bounds->bottom() < visible_area.y() + min_height) { + bounds->set_y(visible_area.y() + std::min(bounds->height(), min_height) - + bounds->height()); + } else if (bounds->y() > visible_area.bottom() - min_height) { + bounds->set_y(visible_area.bottom() - + std::min(bounds->height(), min_height)); + } + if (bounds->y() < visible_area.y()) + bounds->set_y(visible_area.y()); +} + +void AdjustBoundsToEnsureMinimumWindowVisibility(const gfx::Rect& visible_area, + gfx::Rect* bounds) { + AdjustBoundsToEnsureWindowVisibility(visible_area, kMinimumOnScreenArea, + kMinimumOnScreenArea, bounds); +} + +gfx::Rect GetDefaultLeftSnappedWindowBoundsInParent(WmWindow* window) { + gfx::Rect work_area_in_parent(GetDisplayWorkAreaBoundsInParent(window)); + return gfx::Rect(work_area_in_parent.x(), work_area_in_parent.y(), + GetDefaultSnappedWindowWidth(window), + work_area_in_parent.height()); +} + +gfx::Rect GetDefaultRightSnappedWindowBoundsInParent(WmWindow* window) { + gfx::Rect work_area_in_parent(GetDisplayWorkAreaBoundsInParent(window)); + int width = GetDefaultSnappedWindowWidth(window); + return gfx::Rect(work_area_in_parent.right() - width, work_area_in_parent.y(), + width, work_area_in_parent.height()); +} + +void CenterWindow(WmWindow* window) { + WMEvent event(WM_EVENT_CENTER); + window->GetWindowState()->OnWMEvent(&event); +} + +void SetBoundsInScreen(WmWindow* window, + const gfx::Rect& bounds_in_screen, + const display::Display& display) { + DCHECK_NE(display::kInvalidDisplayId, display.id()); + // Don't move a window to other root window if: + // a) the window is a transient window. It moves when its + // transient parent moves. + // b) if the window or its ancestor has IsLockedToRoot(). It's intentionally + // kept in the same root window even if the bounds is outside of the + // display. + if (!window->GetTransientParent() && + !IsWindowOrAncestorLockedToRoot(window)) { + RootWindowController* dst_root_window_controller = + Shell::GetRootWindowControllerWithDisplayId(display.id()); + DCHECK(dst_root_window_controller); + WmWindow* dst_root = dst_root_window_controller->GetWindow(); + DCHECK(dst_root); + WmWindow* dst_container = nullptr; + if (dst_root != window->GetRootWindow()) { + int container_id = window->GetParent()->GetShellWindowId(); + // All containers that uses screen coordinates must have valid window ids. + DCHECK_GE(container_id, 0); + // Don't move modal background. + if (!SystemModalContainerLayoutManager::IsModalBackground(window)) + dst_container = dst_root->GetChildByShellWindowId(container_id); + } + + if (dst_container && window->GetParent() != dst_container) { + WmWindow* focused = WmShell::Get()->GetFocusedWindow(); + WmWindow* active = WmShell::Get()->GetActiveWindow(); + + aura::WindowTracker tracker; + if (focused) + tracker.Add(focused->aura_window()); + if (active && focused != active) + tracker.Add(active->aura_window()); + + gfx::Point origin = bounds_in_screen.origin(); + const gfx::Point display_origin = display.bounds().origin(); + origin.Offset(-display_origin.x(), -display_origin.y()); + gfx::Rect new_bounds = gfx::Rect(origin, bounds_in_screen.size()); + + // Set new bounds now so that the container's layout manager can adjust + // the bounds if necessary. + window->SetBounds(new_bounds); + + dst_container->AddChild(window); + + MoveAllTransientChildrenToNewRoot(display, window); + + // Restore focused/active window. + if (focused && tracker.Contains(focused->aura_window())) { + focused->SetFocused(); + WmShell::Get()->set_root_window_for_new_windows( + focused->GetRootWindow()); + } else if (active && tracker.Contains(active->aura_window())) { + active->Activate(); + } + // TODO(oshima): We should not have to update the bounds again + // below in theory, but we currently do need as there is a code + // that assumes that the bounds will never be overridden by the + // layout mananger. We should have more explicit control how + // constraints are applied by the layout manager. + } + } + gfx::Point origin(bounds_in_screen.origin()); + const gfx::Point display_origin = + window->GetDisplayNearestWindow().bounds().origin(); + origin.Offset(-display_origin.x(), -display_origin.y()); + window->SetBounds(gfx::Rect(origin, bounds_in_screen.size())); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/window_positioning_utils.h b/ash/common/wm/window_positioning_utils.h new file mode 100644 index 0000000..e515c5b --- /dev/null +++ b/ash/common/wm/window_positioning_utils.h
@@ -0,0 +1,70 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_POSITIONING_UTILS_H_ +#define ASH_COMMON_WM_WINDOW_POSITIONING_UTILS_H_ + +#include "ash/ash_export.h" + +namespace display { +class Display; +} + +namespace gfx { +class Rect; +class Size; +} + +namespace ash { + +class WmWindow; + +namespace wm { + +// We force at least this many DIPs for any window on the screen. +const int kMinimumOnScreenArea = 25; + +// Adjusts |bounds| so that the size does not exceed |max_size|. +ASH_EXPORT void AdjustBoundsSmallerThan(const gfx::Size& max_size, + gfx::Rect* bounds); + +// Move the given bounds inside the given |visible_area| in parent coordinates, +// including a safety margin given by |min_width| and |min_height|. +// This also ensures that the top of the bounds is visible. +ASH_EXPORT void AdjustBoundsToEnsureWindowVisibility( + const gfx::Rect& visible_area, + int min_width, + int min_height, + gfx::Rect* bounds); + +// Move the given bounds inside the given |visible_area| in parent coordinates, +// including a safety margin given by |kMinimumOnScreenArea|. +// This also ensures that the top of the bounds is visible. +ASH_EXPORT void AdjustBoundsToEnsureMinimumWindowVisibility( + const gfx::Rect& visible_area, + gfx::Rect* bounds); + +// Returns the bounds of a left snapped window with default width in parent +// coordinates. +ASH_EXPORT gfx::Rect GetDefaultLeftSnappedWindowBoundsInParent( + WmWindow* window); + +// Returns the bounds of a right snapped window with default width in parent +// coordinates. +ASH_EXPORT gfx::Rect GetDefaultRightSnappedWindowBoundsInParent( + WmWindow* window); + +// Moves the window to the center of the display. +ASH_EXPORT void CenterWindow(WmWindow* window); + +// Sets the bounds of |window| to |bounds_in_screen|. This may move |window| +// to |display| if necessary. +ASH_EXPORT void SetBoundsInScreen(WmWindow* window, + const gfx::Rect& bounds_in_screen, + const display::Display& display); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_POSITIONING_UTILS_H_
diff --git a/ash/common/wm/window_resizer.cc b/ash/common/wm/window_resizer.cc new file mode 100644 index 0000000..bb96876 --- /dev/null +++ b/ash/common/wm/window_resizer.cc
@@ -0,0 +1,329 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_resizer.h" + +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm_window.h" +#include "ui/base/hit_test.h" +#include "ui/base/ui_base_types.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { + +namespace { + +// Returns true for resize components along the right edge, where a drag in +// positive x will make the window larger. +bool IsRightEdge(int window_component) { + return window_component == HTTOPRIGHT || window_component == HTRIGHT || + window_component == HTBOTTOMRIGHT || window_component == HTGROWBOX; +} + +} // namespace + +// static +const int WindowResizer::kBoundsChange_None = 0; +// static +const int WindowResizer::kBoundsChange_Repositions = 1; +// static +const int WindowResizer::kBoundsChange_Resizes = 2; + +// static +const int WindowResizer::kBoundsChangeDirection_None = 0; +// static +const int WindowResizer::kBoundsChangeDirection_Horizontal = 1; +// static +const int WindowResizer::kBoundsChangeDirection_Vertical = 2; + +WindowResizer::WindowResizer(wm::WindowState* window_state) + : window_state_(window_state) { + DCHECK(window_state_->drag_details()); +} + +WindowResizer::~WindowResizer() {} + +// static +int WindowResizer::GetBoundsChangeForWindowComponent(int component) { + int bounds_change = WindowResizer::kBoundsChange_None; + switch (component) { + case HTTOPLEFT: + case HTTOP: + case HTTOPRIGHT: + case HTLEFT: + case HTBOTTOMLEFT: + bounds_change |= WindowResizer::kBoundsChange_Repositions | + WindowResizer::kBoundsChange_Resizes; + break; + case HTCAPTION: + bounds_change |= WindowResizer::kBoundsChange_Repositions; + break; + case HTRIGHT: + case HTBOTTOMRIGHT: + case HTBOTTOM: + case HTGROWBOX: + bounds_change |= WindowResizer::kBoundsChange_Resizes; + break; + default: + break; + } + return bounds_change; +} + +// static +int WindowResizer::GetPositionChangeDirectionForWindowComponent( + int window_component) { + int pos_change_direction = WindowResizer::kBoundsChangeDirection_None; + switch (window_component) { + case HTTOPLEFT: + case HTBOTTOMRIGHT: + case HTGROWBOX: + case HTCAPTION: + pos_change_direction |= WindowResizer::kBoundsChangeDirection_Horizontal | + WindowResizer::kBoundsChangeDirection_Vertical; + break; + case HTTOP: + case HTTOPRIGHT: + case HTBOTTOM: + pos_change_direction |= WindowResizer::kBoundsChangeDirection_Vertical; + break; + case HTBOTTOMLEFT: + case HTRIGHT: + case HTLEFT: + pos_change_direction |= WindowResizer::kBoundsChangeDirection_Horizontal; + break; + default: + break; + } + return pos_change_direction; +} + +gfx::Rect WindowResizer::CalculateBoundsForDrag( + const gfx::Point& passed_location) { + if (!details().is_resizable) + return details().initial_bounds_in_parent; + + gfx::Point location = passed_location; + int delta_x = location.x() - details().initial_location_in_parent.x(); + int delta_y = location.y() - details().initial_location_in_parent.y(); + + AdjustDeltaForTouchResize(&delta_x, &delta_y); + + // The minimize size constraint may limit how much we change the window + // position. For example, dragging the left edge to the right should stop + // repositioning the window when the minimize size is reached. + gfx::Size size = GetSizeForDrag(&delta_x, &delta_y); + gfx::Point origin = GetOriginForDrag(delta_x, delta_y); + gfx::Rect new_bounds(origin, size); + + // Sizing has to keep the result on the screen. Note that this correction + // has to come first since it might have an impact on the origin as well as + // on the size. + if (details().bounds_change & kBoundsChange_Resizes) { + gfx::Rect work_area = GetTarget()->GetDisplayNearestWindow().work_area(); + DockedWindowLayoutManager* dock_layout = + DockedWindowLayoutManager::Get(GetTarget()); + + work_area.Union(dock_layout->docked_bounds()); + work_area = GetTarget()->GetParent()->ConvertRectFromScreen(work_area); + if (details().size_change_direction & kBoundsChangeDirection_Horizontal) { + if (IsRightEdge(details().window_component) && + new_bounds.right() < work_area.x() + wm::kMinimumOnScreenArea) { + int delta = + work_area.x() + wm::kMinimumOnScreenArea - new_bounds.right(); + new_bounds.set_width(new_bounds.width() + delta); + } else if (new_bounds.x() > + work_area.right() - wm::kMinimumOnScreenArea) { + int width = + new_bounds.right() - work_area.right() + wm::kMinimumOnScreenArea; + new_bounds.set_x(work_area.right() - wm::kMinimumOnScreenArea); + new_bounds.set_width(width); + } + } + if (details().size_change_direction & kBoundsChangeDirection_Vertical) { + if (!IsBottomEdge(details().window_component) && + new_bounds.y() > work_area.bottom() - wm::kMinimumOnScreenArea) { + int height = + new_bounds.bottom() - work_area.bottom() + wm::kMinimumOnScreenArea; + new_bounds.set_y(work_area.bottom() - wm::kMinimumOnScreenArea); + new_bounds.set_height(height); + } else if (details().window_component == HTBOTTOM || + details().window_component == HTBOTTOMRIGHT || + details().window_component == HTBOTTOMLEFT) { + // Update bottom edge to stay in the work area when we are resizing + // by dragging the bottom edge or corners. + if (new_bounds.bottom() > work_area.bottom()) + new_bounds.Inset(0, 0, 0, new_bounds.bottom() - work_area.bottom()); + } + } + if (details().bounds_change & kBoundsChange_Repositions && + new_bounds.y() < 0) { + int delta = new_bounds.y(); + new_bounds.set_y(0); + new_bounds.set_height(new_bounds.height() + delta); + } + } + + if (details().bounds_change & kBoundsChange_Repositions) { + // When we might want to reposition a window which is also restored to its + // previous size, to keep the cursor within the dragged window. + if (!details().restore_bounds.IsEmpty()) { + // However - it is not desirable to change the origin if the window would + // be still hit by the cursor. + if (details().initial_location_in_parent.x() > + details().initial_bounds_in_parent.x() + + details().restore_bounds.width()) + new_bounds.set_x(location.x() - details().restore_bounds.width() / 2); + } + + // Make sure that |new_bounds| doesn't leave any of the displays. Note that + // the |work_area| above isn't good for this check since it is the work area + // for the current display but the window can move to a different one. + WmWindow* parent = GetTarget()->GetParent(); + gfx::Point passed_location_in_screen( + parent->ConvertPointToScreen(passed_location)); + gfx::Rect near_passed_location(passed_location_in_screen, gfx::Size()); + // Use a pointer location (matching the logic in DragWindowResizer) to + // calculate the target display after the drag. + const display::Display& display = + display::Screen::GetScreen()->GetDisplayMatching(near_passed_location); + DockedWindowLayoutManager* dock_layout = DockedWindowLayoutManager::Get( + wm::GetRootWindowMatching(near_passed_location)); + + gfx::Rect screen_work_area = display.work_area(); + screen_work_area.Union(dock_layout->docked_bounds()); + screen_work_area.Inset(wm::kMinimumOnScreenArea, 0); + gfx::Rect new_bounds_in_screen = parent->ConvertRectToScreen(new_bounds); + if (!screen_work_area.Intersects(new_bounds_in_screen)) { + // Make sure that the x origin does not leave the current display. + new_bounds_in_screen.set_x(std::max( + screen_work_area.x() - new_bounds.width(), + std::min(screen_work_area.right(), new_bounds_in_screen.x()))); + new_bounds = parent->ConvertRectFromScreen(new_bounds_in_screen); + } + } + + return new_bounds; +} + +// static +bool WindowResizer::IsBottomEdge(int window_component) { + return window_component == HTBOTTOMLEFT || window_component == HTBOTTOM || + window_component == HTBOTTOMRIGHT || window_component == HTGROWBOX; +} + +void WindowResizer::AdjustDeltaForTouchResize(int* delta_x, int* delta_y) { + if (details().source != aura::client::WINDOW_MOVE_SOURCE_TOUCH || + !(details().bounds_change & kBoundsChange_Resizes)) + return; + + if (details().size_change_direction & kBoundsChangeDirection_Horizontal) { + if (IsRightEdge(details().window_component)) { + *delta_x += details().initial_location_in_parent.x() - + details().initial_bounds_in_parent.right(); + } else { + *delta_x += details().initial_location_in_parent.x() - + details().initial_bounds_in_parent.x(); + } + } + if (details().size_change_direction & kBoundsChangeDirection_Vertical) { + if (IsBottomEdge(details().window_component)) { + *delta_y += details().initial_location_in_parent.y() - + details().initial_bounds_in_parent.bottom(); + } else { + *delta_y += details().initial_location_in_parent.y() - + details().initial_bounds_in_parent.y(); + } + } +} + +gfx::Point WindowResizer::GetOriginForDrag(int delta_x, int delta_y) { + gfx::Point origin = details().initial_bounds_in_parent.origin(); + if (details().bounds_change & kBoundsChange_Repositions) { + int pos_change_direction = GetPositionChangeDirectionForWindowComponent( + details().window_component); + if (pos_change_direction & kBoundsChangeDirection_Horizontal) + origin.Offset(delta_x, 0); + if (pos_change_direction & kBoundsChangeDirection_Vertical) + origin.Offset(0, delta_y); + } + return origin; +} + +gfx::Size WindowResizer::GetSizeForDrag(int* delta_x, int* delta_y) { + gfx::Size size = details().initial_bounds_in_parent.size(); + if (details().bounds_change & kBoundsChange_Resizes) { + gfx::Size min_size = GetTarget()->GetMinimumSize(); + size.SetSize(GetWidthForDrag(min_size.width(), delta_x), + GetHeightForDrag(min_size.height(), delta_y)); + } else if (!details().restore_bounds.IsEmpty()) { + size = details().restore_bounds.size(); + } + return size; +} + +int WindowResizer::GetWidthForDrag(int min_width, int* delta_x) { + int width = details().initial_bounds_in_parent.width(); + if (details().size_change_direction & kBoundsChangeDirection_Horizontal) { + // Along the right edge, positive delta_x increases the window size. + int x_multiplier = IsRightEdge(details().window_component) ? 1 : -1; + width += x_multiplier * (*delta_x); + + // Ensure we don't shrink past the minimum width and clamp delta_x + // for the window origin computation. + if (width < min_width) { + width = min_width; + *delta_x = -x_multiplier * + (details().initial_bounds_in_parent.width() - min_width); + } + + // And don't let the window go bigger than the display. + int max_width = GetTarget()->GetDisplayNearestWindow().bounds().width(); + gfx::Size max_size = GetTarget()->GetMaximumSize(); + if (max_size.width() != 0) + max_width = std::min(max_width, max_size.width()); + if (width > max_width) { + width = max_width; + *delta_x = -x_multiplier * + (details().initial_bounds_in_parent.width() - max_width); + } + } + return width; +} + +int WindowResizer::GetHeightForDrag(int min_height, int* delta_y) { + int height = details().initial_bounds_in_parent.height(); + if (details().size_change_direction & kBoundsChangeDirection_Vertical) { + // Along the bottom edge, positive delta_y increases the window size. + int y_multiplier = IsBottomEdge(details().window_component) ? 1 : -1; + height += y_multiplier * (*delta_y); + + // Ensure we don't shrink past the minimum height and clamp delta_y + // for the window origin computation. + if (height < min_height) { + height = min_height; + *delta_y = -y_multiplier * + (details().initial_bounds_in_parent.height() - min_height); + } + + // And don't let the window go bigger than the display. + int max_height = GetTarget()->GetDisplayNearestWindow().bounds().height(); + gfx::Size max_size = GetTarget()->GetMaximumSize(); + if (max_size.height() != 0) + max_height = std::min(max_height, max_size.height()); + if (height > max_height) { + height = max_height; + *delta_y = -y_multiplier * + (details().initial_bounds_in_parent.height() - max_height); + } + } + return height; +} + +} // namespace ash
diff --git a/ash/common/wm/window_resizer.h b/ash/common/wm/window_resizer.h new file mode 100644 index 0000000..1caf9338 --- /dev/null +++ b/ash/common/wm/window_resizer.h
@@ -0,0 +1,110 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_RESIZER_H_ +#define ASH_COMMON_WM_WINDOW_RESIZER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/drag_details.h" +#include "ash/common/wm/window_state.h" +#include "base/macros.h" +#include "ui/wm/public/window_move_client.h" + +namespace gfx { +class Rect; +} + +namespace ash { + +class WmWindow; + +// WindowResizer is used by ToplevelWindowEventFilter to handle dragging, moving +// or resizing a window. All coordinates passed to this are in the parent +// windows coordinates. +class ASH_EXPORT WindowResizer { + public: + // Constants to identify the type of resize. + static const int kBoundsChange_None; + static const int kBoundsChange_Repositions; + static const int kBoundsChange_Resizes; + + // Used to indicate which direction the resize occurs in. + static const int kBoundsChangeDirection_None; + static const int kBoundsChangeDirection_Horizontal; + static const int kBoundsChangeDirection_Vertical; + + explicit WindowResizer(wm::WindowState* window_state); + virtual ~WindowResizer(); + + // Returns a bitmask of the kBoundsChange_ values. + static int GetBoundsChangeForWindowComponent(int component); + + // Returns a bitmask of the kBoundsChange_ values. + static int GetPositionChangeDirectionForWindowComponent(int window_component); + + // Invoked to drag/move/resize the window. |location| is in the coordinates + // of the window supplied to the constructor. |event_flags| is the event + // flags from the event. + virtual void Drag(const gfx::Point& location, int event_flags) = 0; + + // Invoked to complete the drag. + virtual void CompleteDrag() = 0; + + // Reverts the drag. + virtual void RevertDrag() = 0; + + // Returns the target window the resizer was created for. + WmWindow* GetTarget() const { + return window_state_ ? window_state_->window() : nullptr; + } + // See comment for |DragDetails::initial_location_in_parent|. + const gfx::Point& GetInitialLocation() const { + return window_state_->drag_details()->initial_location_in_parent; + } + + // Drag parameters established when drag starts. + const DragDetails& details() const { return *window_state_->drag_details(); } + + protected: + gfx::Rect CalculateBoundsForDrag(const gfx::Point& location); + + static bool IsBottomEdge(int component); + + // WindowState of the drag target. + wm::WindowState* window_state_; + + private: + // In case of touch resizing, adjusts deltas so that the border is positioned + // just under the touch point. + void AdjustDeltaForTouchResize(int* delta_x, int* delta_y); + + // Returns the new origin of the window. The arguments are the difference + // between the current location and the initial location. + gfx::Point GetOriginForDrag(int delta_x, int delta_y); + + // Returns the size of the window for the drag. + gfx::Size GetSizeForDrag(int* delta_x, int* delta_y); + + // Returns the width of the window. + int GetWidthForDrag(int min_width, int* delta_x); + + // Returns the height of the drag. + int GetHeightForDrag(int min_height, int* delta_y); + + DISALLOW_COPY_AND_ASSIGN(WindowResizer); +}; + +// Creates a WindowResizer for |window|. Returns a unique_ptr with null if +// |window| should not be resized nor dragged. +ASH_EXPORT std::unique_ptr<WindowResizer> CreateWindowResizer( + WmWindow* window, + const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source); + +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_RESIZER_H_
diff --git a/ash/common/wm/window_state.cc b/ash/common/wm/window_state.cc new file mode 100644 index 0000000..fbfa933 --- /dev/null +++ b/ash/common/wm/window_state.cc
@@ -0,0 +1,401 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_state.h" + +#include <utility> + +#include "ash/common/wm/default_state.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state_delegate.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm_window.h" +#include "base/auto_reset.h" + +namespace ash { +namespace wm { + +namespace { + +WMEventType WMEventTypeFromShowState(ui::WindowShowState requested_show_state) { + switch (requested_show_state) { + case ui::SHOW_STATE_DEFAULT: + case ui::SHOW_STATE_NORMAL: + return WM_EVENT_NORMAL; + case ui::SHOW_STATE_MINIMIZED: + return WM_EVENT_MINIMIZE; + case ui::SHOW_STATE_MAXIMIZED: + return WM_EVENT_MAXIMIZE; + case ui::SHOW_STATE_FULLSCREEN: + return WM_EVENT_FULLSCREEN; + case ui::SHOW_STATE_INACTIVE: + return WM_EVENT_SHOW_INACTIVE; + + // TODO(afakhry): Remove Docked Windows in M58. + case ui::SHOW_STATE_DOCKED: + return WM_EVENT_DOCK; + case ui::SHOW_STATE_END: + NOTREACHED() << "No WMEvent defined for the show state:" + << requested_show_state; + } + return WM_EVENT_NORMAL; +} + +} // namespace + +WindowState::~WindowState() {} + +bool WindowState::HasDelegate() const { + return !!delegate_; +} + +void WindowState::SetDelegate(std::unique_ptr<WindowStateDelegate> delegate) { + DCHECK(!delegate_.get()); + delegate_ = std::move(delegate); +} + +WindowStateType WindowState::GetStateType() const { + return current_state_->GetType(); +} + +bool WindowState::IsMinimized() const { + return GetStateType() == WINDOW_STATE_TYPE_MINIMIZED || + GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; +} + +bool WindowState::IsMaximized() const { + return GetStateType() == WINDOW_STATE_TYPE_MAXIMIZED; +} + +bool WindowState::IsFullscreen() const { + return GetStateType() == WINDOW_STATE_TYPE_FULLSCREEN; +} + +bool WindowState::IsMaximizedOrFullscreenOrPinned() const { + return GetStateType() == WINDOW_STATE_TYPE_MAXIMIZED || + GetStateType() == WINDOW_STATE_TYPE_FULLSCREEN || IsPinned(); +} + +bool WindowState::IsSnapped() const { + return GetStateType() == WINDOW_STATE_TYPE_LEFT_SNAPPED || + GetStateType() == WINDOW_STATE_TYPE_RIGHT_SNAPPED; +} + +bool WindowState::IsPinned() const { + return GetStateType() == WINDOW_STATE_TYPE_PINNED || + GetStateType() == WINDOW_STATE_TYPE_TRUSTED_PINNED; +} + +bool WindowState::IsTrustedPinned() const { + return GetStateType() == WINDOW_STATE_TYPE_TRUSTED_PINNED; +} + +bool WindowState::IsNormalStateType() const { + return GetStateType() == WINDOW_STATE_TYPE_NORMAL || + GetStateType() == WINDOW_STATE_TYPE_DEFAULT; +} + +bool WindowState::IsNormalOrSnapped() const { + return IsNormalStateType() || IsSnapped(); +} + +bool WindowState::IsActive() const { + return window_->IsActive(); +} + +bool WindowState::IsDocked() const { + return GetStateType() == WINDOW_STATE_TYPE_DOCKED || + GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; +} + +bool WindowState::IsUserPositionable() const { + return (window_->GetType() == ui::wm::WINDOW_TYPE_NORMAL || + window_->GetType() == ui::wm::WINDOW_TYPE_PANEL); +} + +bool WindowState::CanMaximize() const { + // Window must allow maximization and have no maximum width or height. + if (!window_->CanMaximize()) + return false; + + if (!window_->HasNonClientArea()) + return true; + + gfx::Size max_size = window_->GetMaximumSize(); + return !max_size.width() && !max_size.height(); +} + +bool WindowState::CanMinimize() const { + return window_->CanMinimize(); +} + +bool WindowState::CanResize() const { + return window_->CanResize(); +} + +bool WindowState::CanActivate() const { + return window_->CanActivate(); +} + +bool WindowState::CanSnap() const { + if (!CanResize() || window_->GetType() == ui::wm::WINDOW_TYPE_PANEL || + window_->GetTransientParent()) { + return false; + } + // If a window cannot be maximized, assume it cannot snap either. + // TODO(oshima): We should probably snap if the maximum size is greater than + // the snapped size. + return CanMaximize(); +} + +bool WindowState::HasRestoreBounds() const { + return window_->HasRestoreBounds(); +} + +void WindowState::Maximize() { + window_->Maximize(); +} + +void WindowState::Minimize() { + window_->Minimize(); +} + +void WindowState::Unminimize() { + window_->Unminimize(); +} + +void WindowState::Activate() { + window_->Activate(); +} + +void WindowState::Deactivate() { + window_->Deactivate(); +} + +void WindowState::Restore() { + if (!IsNormalStateType()) { + const WMEvent event(WM_EVENT_NORMAL); + OnWMEvent(&event); + } +} + +void WindowState::DisableAlwaysOnTop(WmWindow* window_on_top) { + if (GetAlwaysOnTop()) { + // |window_| is hidden first to avoid canceling fullscreen mode when it is + // no longer always on top and gets added to default container. This avoids + // sending redundant OnFullscreenStateChanged to the layout manager. The + // |window_| visibility is restored after it no longer obscures the + // |window_on_top|. + bool visible = window_->IsVisible(); + if (visible) + window_->Hide(); + window_->SetAlwaysOnTop(false); + // Technically it is possible that a |window_| could make itself + // always_on_top really quickly. This is probably not a realistic case but + // check if the two windows are in the same container just in case. + if (window_on_top && window_on_top->GetParent() == window_->GetParent()) + window_->GetParent()->StackChildAbove(window_on_top, window_); + if (visible) + window_->Show(); + cached_always_on_top_ = true; + } +} + +void WindowState::RestoreAlwaysOnTop() { + if (delegate() && delegate()->RestoreAlwaysOnTop(this)) + return; + if (cached_always_on_top_) { + cached_always_on_top_ = false; + window_->SetAlwaysOnTop(true); + } +} + +void WindowState::OnWMEvent(const WMEvent* event) { + current_state_->OnWMEvent(this, event); +} + +void WindowState::SaveCurrentBoundsForRestore() { + gfx::Rect bounds_in_screen = + window_->GetParent()->ConvertRectToScreen(window_->GetBounds()); + SetRestoreBoundsInScreen(bounds_in_screen); +} + +gfx::Rect WindowState::GetRestoreBoundsInScreen() const { + return window_->GetRestoreBoundsInScreen(); +} + +gfx::Rect WindowState::GetRestoreBoundsInParent() const { + return window_->GetParent()->ConvertRectFromScreen( + GetRestoreBoundsInScreen()); +} + +void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) { + window_->SetRestoreBoundsInScreen(bounds); +} + +void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) { + SetRestoreBoundsInScreen(window_->GetParent()->ConvertRectToScreen(bounds)); +} + +void WindowState::ClearRestoreBounds() { + window_->ClearRestoreBounds(); +} + +std::unique_ptr<WindowState::State> WindowState::SetStateObject( + std::unique_ptr<WindowState::State> new_state) { + current_state_->DetachState(this); + std::unique_ptr<WindowState::State> old_object = std::move(current_state_); + current_state_ = std::move(new_state); + current_state_->AttachState(this, old_object.get()); + return old_object; +} + +void WindowState::SetPreAutoManageWindowBounds(const gfx::Rect& bounds) { + pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds)); +} + +void WindowState::AddObserver(WindowStateObserver* observer) { + observer_list_.AddObserver(observer); +} + +void WindowState::RemoveObserver(WindowStateObserver* observer) { + observer_list_.RemoveObserver(observer); +} + +void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) { + bounds_changed_by_user_ = bounds_changed_by_user; + if (bounds_changed_by_user) + pre_auto_manage_window_bounds_.reset(); +} + +void WindowState::CreateDragDetails(const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source) { + drag_details_.reset( + new DragDetails(window_, point_in_parent, window_component, source)); +} + +void WindowState::DeleteDragDetails() { + drag_details_.reset(); +} + +void WindowState::SetAndClearRestoreBounds() { + DCHECK(HasRestoreBounds()); + SetBoundsInScreen(GetRestoreBoundsInScreen()); + ClearRestoreBounds(); +} + +void WindowState::OnWindowShowStateChanged() { + if (!ignore_property_change_) { + WMEvent event(WMEventTypeFromShowState(GetShowState())); + OnWMEvent(&event); + } +} + +WindowState::WindowState(WmWindow* window) + : window_(window), + window_position_managed_(false), + bounds_changed_by_user_(false), + ignored_by_shelf_(false), + can_consume_system_keys_(false), + unminimize_to_restore_bounds_(false), + in_immersive_fullscreen_(false), + hide_shelf_when_fullscreen_(true), + minimum_visibility_(false), + can_be_dragged_(true), + cached_always_on_top_(false), + ignore_property_change_(false), + current_state_(new DefaultState(ToWindowStateType(GetShowState()))) {} + +bool WindowState::GetAlwaysOnTop() const { + return window_->IsAlwaysOnTop(); +} + +ui::WindowShowState WindowState::GetShowState() const { + return window_->GetShowState(); +} + +void WindowState::SetBoundsInScreen(const gfx::Rect& bounds_in_screen) { + gfx::Rect bounds_in_parent = + window_->GetParent()->ConvertRectFromScreen(bounds_in_screen); + window_->SetBounds(bounds_in_parent); +} + +void WindowState::AdjustSnappedBounds(gfx::Rect* bounds) { + if (is_dragged() || !IsSnapped()) + return; + gfx::Rect maximized_bounds = GetMaximizedWindowBoundsInParent(window_); + if (GetStateType() == WINDOW_STATE_TYPE_LEFT_SNAPPED) + bounds->set_x(maximized_bounds.x()); + else if (GetStateType() == WINDOW_STATE_TYPE_RIGHT_SNAPPED) + bounds->set_x(maximized_bounds.right() - bounds->width()); + bounds->set_y(maximized_bounds.y()); + bounds->set_height(maximized_bounds.height()); +} + +void WindowState::UpdateWindowShowStateFromStateType() { + ui::WindowShowState new_window_state = + ToWindowShowState(current_state_->GetType()); + if (new_window_state != GetShowState()) { + base::AutoReset<bool> resetter(&ignore_property_change_, true); + window_->SetShowState(new_window_state); + } +} + +void WindowState::NotifyPreStateTypeChange( + WindowStateType old_window_state_type) { + for (auto& observer : observer_list_) + observer.OnPreWindowStateTypeChange(this, old_window_state_type); +} + +void WindowState::NotifyPostStateTypeChange( + WindowStateType old_window_state_type) { + for (auto& observer : observer_list_) + observer.OnPostWindowStateTypeChange(this, old_window_state_type); +} + +void WindowState::SetBoundsDirect(const gfx::Rect& bounds) { + gfx::Rect actual_new_bounds(bounds); + // Ensure we don't go smaller than our minimum bounds in "normal" window + // modes + if (window_->HasNonClientArea() && !IsMaximized() && !IsFullscreen()) { + // Get the minimum usable size of the minimum size and the screen size. + gfx::Size min_size = window_->GetMinimumSize(); + min_size.SetToMin(window_->GetDisplayNearestWindow().work_area().size()); + + actual_new_bounds.set_width( + std::max(min_size.width(), actual_new_bounds.width())); + actual_new_bounds.set_height( + std::max(min_size.height(), actual_new_bounds.height())); + } + window_->SetBoundsDirect(actual_new_bounds); +} + +void WindowState::SetBoundsConstrained(const gfx::Rect& bounds) { + gfx::Rect work_area_in_parent = GetDisplayWorkAreaBoundsInParent(window_); + gfx::Rect child_bounds(bounds); + AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds); + SetBoundsDirect(child_bounds); +} + +void WindowState::SetBoundsDirectAnimated(const gfx::Rect& bounds) { + window_->SetBoundsDirectAnimated(bounds); +} + +void WindowState::SetBoundsDirectCrossFade(const gfx::Rect& new_bounds) { + // Some test results in invoking CrossFadeToBounds when window is not visible. + // No animation is necessary in that case, thus just change the bounds and + // quit. + if (!window_->GetTargetVisibility()) { + SetBoundsConstrained(new_bounds); + return; + } + + window_->SetBoundsDirectCrossFade(new_bounds); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/window_state.h b/ash/common/wm/window_state.h new file mode 100644 index 0000000..53a5c15 --- /dev/null +++ b/ash/common/wm/window_state.h
@@ -0,0 +1,397 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_STATE_H_ +#define ASH_COMMON_WM_WINDOW_STATE_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/drag_details.h" +#include "ash/common/wm/wm_types.h" +#include "base/gtest_prod_util.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "ui/base/ui_base_types.h" + +namespace aura { +class Window; +} + +namespace gfx { +class Rect; +} + +namespace ash { +class LockWindowState; +class MaximizeModeWindowState; +class WmWindow; + +namespace wm { +class WindowStateDelegate; +class WindowStateObserver; +class WMEvent; + +// WindowState manages and defines ash specific window state and +// behavior. Ash specific per-window state (such as ones that controls +// window manager behavior) and ash specific window behavior (such as +// maximize, minimize, snap sizing etc) should be added here instead +// of defining separate functions (like |MaximizeWindow(aura::Window* +// window)|) or using aura Window property. +// The WindowState gets created when first accessed by +// |wm::GetWindowState|, and deleted when the window is deleted. +// Prefer using this class instead of passing aura::Window* around in +// ash code as this is often what you need to interact with, and +// accessing the window using |window()| is cheap. +class ASH_EXPORT WindowState { + public: + // A subclass of State class represents one of the window's states + // that corresponds to WindowStateType in Ash environment, e.g. + // maximized, minimized or side snapped, as subclass. + // Each subclass defines its own behavior and transition for each WMEvent. + class State { + public: + State() {} + virtual ~State() {} + + // Update WindowState based on |event|. + virtual void OnWMEvent(WindowState* window_state, const WMEvent* event) = 0; + + virtual WindowStateType GetType() const = 0; + + // Gets called when the state object became active and the managed window + // needs to be adjusted to the State's requirement. + // The passed |previous_state| may be used to properly implement state + // transitions such as bound animations from the previous state. + // Note: This only gets called when the state object gets changed. + virtual void AttachState(WindowState* window_state, + State* previous_state) = 0; + + // Gets called before the state objects gets deactivated / detached from the + // window, so that it can save the various states it is interested in. + // Note: This only gets called when the state object gets changed. + virtual void DetachState(WindowState* window_state) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(State); + }; + + // Call GetWindowState() to instantiate this class. + virtual ~WindowState(); + + WmWindow* window() { return window_; } + const WmWindow* window() const { return window_; } + + bool HasDelegate() const; + void SetDelegate(std::unique_ptr<WindowStateDelegate> delegate); + + // Returns the window's current ash state type. + // Refer to WindowStateType definition in wm_types.h as for why Ash + // has its own state type. + WindowStateType GetStateType() const; + + // Predicates to check window state. + bool IsMinimized() const; + bool IsMaximized() const; + bool IsFullscreen() const; + bool IsSnapped() const; + bool IsPinned() const; + bool IsTrustedPinned() const; + + // True if the window's state type is WINDOW_STATE_TYPE_MAXIMIZED, + // WINDOW_STATE_TYPE_FULLSCREEN or WINDOW_STATE_TYPE_PINNED. + bool IsMaximizedOrFullscreenOrPinned() const; + + // True if the window's state type is WINDOW_STATE_TYPE_NORMAL or + // WINDOW_STATE_TYPE_DEFAULT. + bool IsNormalStateType() const; + + bool IsNormalOrSnapped() const; + + bool IsActive() const; + bool IsDocked() const; + + // Returns true if the window's location can be controlled by the user. + bool IsUserPositionable() const; + + // Checks if the window can change its state accordingly. + bool CanMaximize() const; + bool CanMinimize() const; + bool CanResize() const; + bool CanSnap() const; + bool CanActivate() const; + + // Returns true if the window has restore bounds. + bool HasRestoreBounds() const; + + // These methods use aura::WindowProperty to change the window's state + // instead of using WMEvent directly. This is to use the same mechanism as + // what views::Widget is using. + void Maximize(); + void Minimize(); + void Unminimize(); + + void Activate(); + void Deactivate(); + + // Set the window state to normal. + // TODO(oshima): Change to use RESTORE event. + void Restore(); + + // Caches, then disables always on top state and then stacks |window_| below + // |window_on_top| if a |window_| is currently in always on top state. + void DisableAlwaysOnTop(WmWindow* window_on_top); + + // Restores always on top state that a window might have cached. + void RestoreAlwaysOnTop(); + + // Invoked when a WMevent occurs, which drives the internal + // state machine. + void OnWMEvent(const WMEvent* event); + + // TODO(oshima): Try hiding these methods and making them accessible only to + // state impl. State changes should happen through events (as much + // as possible). + + // Saves the current bounds to be used as a restore bounds. + void SaveCurrentBoundsForRestore(); + + // Same as |GetRestoreBoundsInScreen| except that it returns the + // bounds in the parent's coordinates. + gfx::Rect GetRestoreBoundsInParent() const; + + // Returns the restore bounds property on the window in the virtual screen + // coordinates. The bounds can be NULL if the bounds property does not + // exist for the window. The window owns the bounds object. + gfx::Rect GetRestoreBoundsInScreen() const; + + // Same as |SetRestoreBoundsInScreen| except that the bounds is in the + // parent's coordinates. + void SetRestoreBoundsInParent(const gfx::Rect& bounds_in_parent); + + // Sets the restore bounds property on the window in the virtual screen + // coordinates. Deletes existing bounds value if exists. + void SetRestoreBoundsInScreen(const gfx::Rect& bounds_in_screen); + + // Deletes and clears the restore bounds property on the window. + void ClearRestoreBounds(); + + // Replace the State object of a window with a state handler which can + // implement a new window manager type. The passed object will be owned + // by this object and the returned object will be owned by the caller. + std::unique_ptr<State> SetStateObject(std::unique_ptr<State> new_state); + + // True if the window should be unminimized to the restore bounds, as + // opposed to the window's current bounds. |unminimized_to_restore_bounds_| is + // reset to the default value after the window is unminimized. + bool unminimize_to_restore_bounds() const { + return unminimize_to_restore_bounds_; + } + void set_unminimize_to_restore_bounds(bool value) { + unminimize_to_restore_bounds_ = value; + } + + // Gets/sets whether the shelf should be hidden when this window is + // fullscreen. + bool hide_shelf_when_fullscreen() const { + return hide_shelf_when_fullscreen_; + } + + void set_hide_shelf_when_fullscreen(bool value) { + hide_shelf_when_fullscreen_ = value; + } + + // If the minimum visibility is true, ash will try to keep a + // minimum amount of the window is always visible on the work area + // when shown. + // TODO(oshima): Consolidate this and window_position_managed + // into single parameter to control the window placement. + bool minimum_visibility() const { return minimum_visibility_; } + void set_minimum_visibility(bool minimum_visibility) { + minimum_visibility_ = minimum_visibility; + } + + // Specifies if the window can be dragged by the user via the caption or not. + bool can_be_dragged() const { return can_be_dragged_; } + void set_can_be_dragged(bool can_be_dragged) { + can_be_dragged_ = can_be_dragged; + } + + // Gets/Sets the bounds of the window before it was moved by the auto window + // management. As long as it was not auto-managed, it will return NULL. + const gfx::Rect* pre_auto_manage_window_bounds() const { + return pre_auto_manage_window_bounds_.get(); + } + void SetPreAutoManageWindowBounds(const gfx::Rect& bounds); + + // Layout related properties + + void AddObserver(WindowStateObserver* observer); + void RemoveObserver(WindowStateObserver* observer); + + // Whether the window is being dragged. + bool is_dragged() const { return !!drag_details_; } + + // Whether or not the window's position can be managed by the + // auto management logic. + bool window_position_managed() const { return window_position_managed_; } + void set_window_position_managed(bool window_position_managed) { + window_position_managed_ = window_position_managed; + } + + // Whether or not the window's position or size was changed by a user. + bool bounds_changed_by_user() const { return bounds_changed_by_user_; } + void set_bounds_changed_by_user(bool bounds_changed_by_user); + + // True if the window is ignored by the shelf layout manager for + // purposes of darkening the shelf. + bool ignored_by_shelf() const { return ignored_by_shelf_; } + void set_ignored_by_shelf(bool ignored_by_shelf) { + ignored_by_shelf_ = ignored_by_shelf; + } + + // True if the window should be offered a chance to consume special system + // keys such as brightness, volume, etc. that are usually handled by the + // shell. + bool can_consume_system_keys() const { return can_consume_system_keys_; } + void set_can_consume_system_keys(bool can_consume_system_keys) { + can_consume_system_keys_ = can_consume_system_keys; + } + + // True if the window is in "immersive full screen mode" which is slightly + // different from the normal fullscreen mode by allowing the user to reveal + // the top portion of the window through a touch / mouse gesture. It might + // also allow the shelf to be shown in some situations. + bool in_immersive_fullscreen() const { return in_immersive_fullscreen_; } + void set_in_immersive_fullscreen(bool enable) { + in_immersive_fullscreen_ = enable; + } + + // True if the window should not adjust the window's bounds when + // virtual keyboard bounds changes. + // TODO(oshima): This is hack. Replace this with proper + // implementation based on EnsureCaretNotInRect. + bool ignore_keyboard_bounds_change() const { + return ignore_keyboard_bounds_change_; + } + void set_ignore_keyboard_bounds_change(bool ignore_keyboard_bounds_change) { + ignore_keyboard_bounds_change_ = ignore_keyboard_bounds_change; + } + + // True if the window's bounds can be updated using SET_BOUNDS event in + // maiximzed/fullscreen mode. + void set_allow_set_bounds_in_maximized(bool value) { + allow_set_bounds_in_maximized_ = value; + } + bool allow_set_bounds_in_maximized() const { + return allow_set_bounds_in_maximized_; + } + + // Creates and takes ownership of a pointer to DragDetails when resizing is + // active. This should be done before a resizer gets created. + void CreateDragDetails(const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source); + + // Deletes and clears a pointer to DragDetails. This should be done when the + // resizer gets destroyed. + void DeleteDragDetails(); + + // Sets the currently stored restore bounds and clears the restore bounds. + void SetAndClearRestoreBounds(); + + // Returns a pointer to DragDetails during drag operations. + const DragDetails* drag_details() const { return drag_details_.get(); } + DragDetails* drag_details() { return drag_details_.get(); } + + // Called from the associated WmWindow once the show state changes. + void OnWindowShowStateChanged(); + + protected: + explicit WindowState(WmWindow* window); + + private: + friend class DefaultState; + friend class ash::LockWindowState; + friend class ash::MaximizeModeWindowState; + FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeToBounds); + FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, + CrossFadeToBoundsFromTransform); + + WindowStateDelegate* delegate() { return delegate_.get(); } + + // Returns the window's current always_on_top state. + bool GetAlwaysOnTop() const; + + // Returns the window's current show state. + ui::WindowShowState GetShowState() const; + + // Sets the window's bounds in screen coordinates. + void SetBoundsInScreen(const gfx::Rect& bounds_in_screen); + + // Adjusts the |bounds| so that they are flush with the edge of the + // workspace if the window represented by |window_state| is side snapped. + void AdjustSnappedBounds(gfx::Rect* bounds); + + // Updates the window show state according to the current window state type. + // Note that this does not update the window bounds. + void UpdateWindowShowStateFromStateType(); + + void NotifyPreStateTypeChange(WindowStateType old_window_state_type); + void NotifyPostStateTypeChange(WindowStateType old_window_state_type); + + // Sets |bounds| as is and ensure the layer is aligned with pixel boundary. + void SetBoundsDirect(const gfx::Rect& bounds); + + // Sets the window's |bounds| with constraint where the size of the + // new bounds will not exceeds the size of the work area. + void SetBoundsConstrained(const gfx::Rect& bounds); + + // Sets the wndow's |bounds| and transitions to the new bounds with + // a scale animation. + void SetBoundsDirectAnimated(const gfx::Rect& bounds); + + // Sets the window's |bounds| and transition to the new bounds with + // a cross fade animation. + void SetBoundsDirectCrossFade(const gfx::Rect& bounds); + + // The owner of this window settings. + WmWindow* window_; + std::unique_ptr<WindowStateDelegate> delegate_; + + bool window_position_managed_; + bool bounds_changed_by_user_; + bool ignored_by_shelf_; + bool can_consume_system_keys_; + std::unique_ptr<DragDetails> drag_details_; + + bool unminimize_to_restore_bounds_; + bool in_immersive_fullscreen_; + bool ignore_keyboard_bounds_change_ = false; + bool hide_shelf_when_fullscreen_; + bool minimum_visibility_; + bool can_be_dragged_; + bool cached_always_on_top_; + bool allow_set_bounds_in_maximized_ = false; + + // A property to remember the window position which was set before the + // auto window position manager changed the window bounds, so that it can get + // restored when only this one window gets shown. + std::unique_ptr<gfx::Rect> pre_auto_manage_window_bounds_; + + base::ObserverList<WindowStateObserver> observer_list_; + + // True to ignore a property change event to avoid reentrance in + // UpdateWindowStateType() + bool ignore_property_change_; + + std::unique_ptr<State> current_state_; + + DISALLOW_COPY_AND_ASSIGN(WindowState); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_STATE_H_
diff --git a/ash/common/wm/window_state_delegate.cc b/ash/common/wm/window_state_delegate.cc new file mode 100644 index 0000000..0c3fe59 --- /dev/null +++ b/ash/common/wm/window_state_delegate.cc
@@ -0,0 +1,23 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_state_delegate.h" + +namespace ash { +namespace wm { + +WindowStateDelegate::WindowStateDelegate() {} + +WindowStateDelegate::~WindowStateDelegate() {} + +bool WindowStateDelegate::ToggleFullscreen(WindowState* window_state) { + return false; +} + +bool WindowStateDelegate::RestoreAlwaysOnTop(WindowState* window_state) { + return false; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/window_state_delegate.h b/ash/common/wm/window_state_delegate.h new file mode 100644 index 0000000..11bd17f --- /dev/null +++ b/ash/common/wm/window_state_delegate.h
@@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_STATE_DELEGATE_H_ +#define ASH_COMMON_WM_WINDOW_STATE_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" + +namespace ash { +namespace wm { +class WindowState; + +class ASH_EXPORT WindowStateDelegate { + public: + WindowStateDelegate(); + virtual ~WindowStateDelegate(); + + // Invoked when the user uses Shift+F4/F4 to toggle the window fullscreen + // state. If the window is not fullscreen and the window supports immersive + // fullscreen ToggleFullscreen() should put the window into immersive + // fullscreen instead of the default fullscreen type. The caller + // (ash::wm::WindowState) falls backs to the default implementation if this + // returns false. + virtual bool ToggleFullscreen(WindowState* window_state); + + // Invoked when workspace fullscreen state changes and a window may need to + // reassert its always on top state. Returns true if delegate has handled this + // and no additional work is needed, false otherwise. + virtual bool RestoreAlwaysOnTop(WindowState* window_state); + + private: + DISALLOW_COPY_AND_ASSIGN(WindowStateDelegate); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_STATE_DELEGATE_H_
diff --git a/ash/common/wm/window_state_observer.h b/ash/common/wm/window_state_observer.h new file mode 100644 index 0000000..7bfec4e1 --- /dev/null +++ b/ash/common/wm/window_state_observer.h
@@ -0,0 +1,42 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_STATE_OBSERVER_H_ +#define ASH_COMMON_WM_WINDOW_STATE_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm/wm_types.h" + +namespace ash { +namespace wm { +class WindowState; + +class ASH_EXPORT WindowStateObserver { + public: + virtual ~WindowStateObserver() {} + + // Following observer methods are different from kWindowShowStatekey + // property change as they will be invoked when the window + // gets left/right maximized, and auto positioned. |old_type| is the value + // before the change. + + // Called after the window's state type is set to new type, but before + // the window's bounds has been updated for the new type. + // This is used to update the shell state such as work area so + // that the window can use the correct environment to update its bounds. + // TODO(oshima): Remove this once docked windows has its own state. + virtual void OnPreWindowStateTypeChange(WindowState* window_state, + WindowStateType old_type) {} + + // Called after the window's state has been updated. + // This is used to update the shell state that depends on the updated + // window bounds, such as shelf visibility. + virtual void OnPostWindowStateTypeChange(WindowState* window_state, + WindowStateType old_type) {} +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_STATE_OBSERVER_H_
diff --git a/ash/common/wm/window_state_util.cc b/ash/common/wm/window_state_util.cc new file mode 100644 index 0000000..cea13eb --- /dev/null +++ b/ash/common/wm/window_state_util.cc
@@ -0,0 +1,28 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/window_state_util.h" + +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_delegate.h" +#include "ash/common/wm_window.h" + +namespace ash { +namespace wm { + +void ToggleFullScreen(wm::WindowState* window_state, + WindowStateDelegate* delegate) { + // Window which cannot be maximized should not be full screen'ed. + // It can, however, be restored if it was full screen'ed. + bool is_fullscreen = window_state->IsFullscreen(); + if (!is_fullscreen && !window_state->CanMaximize()) + return; + + if (delegate && delegate->ToggleFullscreen(window_state)) + return; + window_state->window()->SetFullscreen(!is_fullscreen); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/window_state_util.h b/ash/common/wm/window_state_util.h new file mode 100644 index 0000000..33bb590d --- /dev/null +++ b/ash/common/wm/window_state_util.h
@@ -0,0 +1,22 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WINDOW_STATE_UTIL_H_ +#define ASH_COMMON_WM_WINDOW_STATE_UTIL_H_ + +#include "ash/ash_export.h" + +namespace ash { +namespace wm { +class WindowState; +class WindowStateDelegate; + +// Toggle the full screen from inside a WindowState::State handler. +ASH_EXPORT void ToggleFullScreen(WindowState* window_state, + WindowStateDelegate* delegate); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WINDOW_STATE_UTIL_H_
diff --git a/ash/common/wm/wm_event.cc b/ash/common/wm/wm_event.cc new file mode 100644 index 0000000..f4c03643 --- /dev/null +++ b/ash/common/wm/wm_event.cc
@@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/wm_event.h" + +namespace ash { +namespace wm { + +WMEvent::WMEvent(WMEventType type) : type_(type) {} + +WMEvent::~WMEvent() {} + +SetBoundsEvent::SetBoundsEvent(WMEventType type, const gfx::Rect& bounds) + : WMEvent(type), requested_bounds_(bounds) {} + +SetBoundsEvent::~SetBoundsEvent() {} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/wm_event.h b/ash/common/wm/wm_event.h new file mode 100644 index 0000000..e26ba78 --- /dev/null +++ b/ash/common/wm/wm_event.h
@@ -0,0 +1,129 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WM_EVENT_H_ +#define ASH_COMMON_WM_WM_EVENT_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm/wm_types.h" +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { +namespace wm { + +// WMEventType defines a set of operations that can change the +// window's state type and bounds. +enum WMEventType { + // Following events are the request to become corresponding state. + // Note that this does not mean the window will be in corresponding + // state and the request may not be fullfilled. + + // NORMAL is used as a restore operation with a few exceptions. + WM_EVENT_NORMAL, + WM_EVENT_MAXIMIZE, + WM_EVENT_MINIMIZE, + WM_EVENT_FULLSCREEN, + WM_EVENT_SNAP_LEFT, + WM_EVENT_SNAP_RIGHT, + WM_EVENT_DOCK, + + // A window is requested to be the given bounds. The request may or + // may not be fulfilled depending on the requested bounds and window's + // state. This will not change the window state type. + WM_EVENT_SET_BOUNDS, + + // Following events are compond events which may lead to different + // states depending on the current state. + + // A user requested to toggle maximized state by double clicking window + // header. + WM_EVENT_TOGGLE_MAXIMIZE_CAPTION, + + // A user requested to toggle maximized state using shortcut. + WM_EVENT_TOGGLE_MAXIMIZE, + + // A user requested to toggle vertical maximize by double clicking + // top/bottom edge. + WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE, + + // A user requested to toggle horizontal maximize by double clicking + // left/right edge. + WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE, + + // A user requested to toggle fullscreen state. + WM_EVENT_TOGGLE_FULLSCREEN, + + // A user requested a cycle of dock and snap left. + // The way this event is processed is the current window state is used as + // the starting state. Assuming normal window start state; if the window can + // be snapped left, snap it; otherwise progress to next state. If the window + // can be docked left, dock it; otherwise progress to next state. If the + // window can be restored; and this isn't the entry condition restore it; + // otherwise apply the bounce animation to the window. + WM_EVENT_CYCLE_SNAP_DOCK_LEFT, + + // A user requested a cycle of dock and snap right. + // See decription of WM_EVENT_CYCLE_SNAP_DOCK_LEFT. + WM_EVENT_CYCLE_SNAP_DOCK_RIGHT, + + // A user requested to center a window. + WM_EVENT_CENTER, + + // TODO(oshima): Investigate if this can be removed from ash. + // Widget requested to show in inactive state. + WM_EVENT_SHOW_INACTIVE, + + // Following events are generated when the workspace envrionment has changed. + // The window's state type will not be changed by these events. + + // The window is added to the workspace, either as a new window, due to + // display disconnection or dragging. + WM_EVENT_ADDED_TO_WORKSPACE, + + // Bounds of the display has changed. + WM_EVENT_DISPLAY_BOUNDS_CHANGED, + + // Bounds of the work area has changed. This will not occur when the work + // area has changed as a result of DISPLAY_BOUNDS_CHANGED. + WM_EVENT_WORKAREA_BOUNDS_CHANGED, + + // A user requested to pin a window. + WM_EVENT_PIN, + + // A user requested to pin a window for a trusted application. This is similar + // WM_EVENT_PIN but does not allow user to exit the mode by shortcut key. + WM_EVENT_TRUSTED_PIN, +}; + +class ASH_EXPORT WMEvent { + public: + explicit WMEvent(WMEventType type); + virtual ~WMEvent(); + + WMEventType type() const { return type_; } + + private: + WMEventType type_; + DISALLOW_COPY_AND_ASSIGN(WMEvent); +}; + +// An WMEvent to request new bounds for the window. +class ASH_EXPORT SetBoundsEvent : public WMEvent { + public: + SetBoundsEvent(WMEventType type, const gfx::Rect& requested_bounds); + ~SetBoundsEvent() override; + + const gfx::Rect& requested_bounds() const { return requested_bounds_; } + + private: + gfx::Rect requested_bounds_; + + DISALLOW_COPY_AND_ASSIGN(SetBoundsEvent); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WM_EVENT_H_
diff --git a/ash/common/wm/wm_screen_util.cc b/ash/common/wm/wm_screen_util.cc new file mode 100644 index 0000000..768556a6 --- /dev/null +++ b/ash/common/wm/wm_screen_util.cc
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/wm_screen_util.h" + +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/root_window_controller.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/size_conversions.h" + +namespace ash { +namespace wm { + +gfx::Rect GetDisplayWorkAreaBoundsInParent(WmWindow* window) { + display::Display display = window->GetDisplayNearestWindow(); + return window->GetParent()->ConvertRectFromScreen(display.work_area()); +} + +gfx::Rect GetDisplayBoundsInParent(WmWindow* window) { + display::Display display = window->GetDisplayNearestWindow(); + return window->GetParent()->ConvertRectFromScreen(display.bounds()); +} + +gfx::Rect GetMaximizedWindowBoundsInParent(WmWindow* window) { + if (window->GetRootWindowController()->HasShelf()) + return GetDisplayWorkAreaBoundsInParent(window); + + return GetDisplayBoundsInParent(window); +} + +gfx::Rect GetDisplayBoundsWithShelf(WmWindow* window) { + if (WmShell::Get()->IsInUnifiedMode()) { + // In unified desktop mode, there is only one shelf in the first display. + gfx::SizeF size(WmShell::Get()->GetFirstDisplay().size()); + float scale = window->GetRootWindow()->GetBounds().height() / size.height(); + size.Scale(scale, scale); + return gfx::Rect(gfx::ToCeiledSize(size)); + } + + return window->GetRootWindow()->GetBounds(); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/wm_screen_util.h b/ash/common/wm/wm_screen_util.h new file mode 100644 index 0000000..dc18200 --- /dev/null +++ b/ash/common/wm/wm_screen_util.h
@@ -0,0 +1,33 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WM_SCREEN_UTIL_H_ +#define ASH_COMMON_WM_WM_SCREEN_UTIL_H_ + +#include "ash/ash_export.h" + +namespace gfx { +class Rect; +} + +namespace ash { + +class WmWindow; + +namespace wm { + +ASH_EXPORT gfx::Rect GetDisplayWorkAreaBoundsInParent(WmWindow* window); +ASH_EXPORT gfx::Rect GetDisplayBoundsInParent(WmWindow* window); +ASH_EXPORT gfx::Rect GetMaximizedWindowBoundsInParent(WmWindow* window); + +// Returns the bounds of the physical display containing the shelf for |window|. +// Physical displays can differ from logical displays in unified desktop mode. +// TODO(oshima): Consider using physical displays in window layout, instead of +// root windows, and only use logical display in display management code. +ASH_EXPORT gfx::Rect GetDisplayBoundsWithShelf(WmWindow* window); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WM_SCREEN_UTIL_H_
diff --git a/ash/common/wm/wm_snap_to_pixel_layout_manager.cc b/ash/common/wm/wm_snap_to_pixel_layout_manager.cc new file mode 100644 index 0000000..79afc89 --- /dev/null +++ b/ash/common/wm/wm_snap_to_pixel_layout_manager.cc
@@ -0,0 +1,56 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h" + +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/wm/window_properties.h" +#include "base/memory/ptr_util.h" +#include "ui/aura/window.h" + +namespace ash { +namespace wm { + +WmSnapToPixelLayoutManager::WmSnapToPixelLayoutManager() {} + +WmSnapToPixelLayoutManager::~WmSnapToPixelLayoutManager() {} + +// static +void WmSnapToPixelLayoutManager::InstallOnContainers(WmWindow* window) { + for (WmWindow* child : window->GetChildren()) { + if (child->GetShellWindowId() < kShellWindowId_Min || + child->GetShellWindowId() > kShellWindowId_Max) // not a container + continue; + if (child->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)) { + if (!child->GetLayoutManager()) + child->SetLayoutManager(base::MakeUnique<WmSnapToPixelLayoutManager>()); + } else { + InstallOnContainers(child); + } + } +} + +void WmSnapToPixelLayoutManager::OnWindowResized() {} + +void WmSnapToPixelLayoutManager::OnWindowAddedToLayout(WmWindow* child) {} + +void WmSnapToPixelLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) { +} + +void WmSnapToPixelLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {} + +void WmSnapToPixelLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, + bool visibile) { +} + +void WmSnapToPixelLayoutManager::SetChildBounds( + WmWindow* child, + const gfx::Rect& requested_bounds) { + child->SetBoundsDirect(requested_bounds); + child->SnapToPixelBoundaryIfNecessary(); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/wm_snap_to_pixel_layout_manager.h b/ash/common/wm/wm_snap_to_pixel_layout_manager.h new file mode 100644 index 0000000..7cf38ca --- /dev/null +++ b/ash/common/wm/wm_snap_to_pixel_layout_manager.h
@@ -0,0 +1,43 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WM_SNAP_TO_PIXEL_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_WM_SNAP_TO_PIXEL_LAYOUT_MANAGER_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm_layout_manager.h" +#include "base/macros.h" + +namespace ash { +namespace wm { + +// A layout manager that places children's layer at the physical pixel +// boundaries. +class ASH_EXPORT WmSnapToPixelLayoutManager : public WmLayoutManager { + public: + WmSnapToPixelLayoutManager(); + ~WmSnapToPixelLayoutManager() override; + + // Sets WmSnapToPixelLayoutManager as the LayoutManager on the appropriate + // descendants of |window|. + static void InstallOnContainers(WmWindow* window); + + protected: + // Overridden from aura::LayoutManager: + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override; + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + private: + DISALLOW_COPY_AND_ASSIGN(WmSnapToPixelLayoutManager); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WM_SNAP_TO_PIXEL_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/wm_toplevel_window_event_handler.cc b/ash/common/wm/wm_toplevel_window_event_handler.cc new file mode 100644 index 0000000..5e670b9 --- /dev/null +++ b/ash/common/wm/wm_toplevel_window_event_handler.cc
@@ -0,0 +1,550 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/wm_toplevel_window_event_handler.h" + +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/aura/window.h" +#include "ui/aura/window_observer.h" +#include "ui/base/hit_test.h" +#include "ui/events/event.h" + +namespace { +const double kMinHorizVelocityForWindowSwipe = 1100; +const double kMinVertVelocityForWindowMinimize = 1000; +} + +namespace ash { +namespace wm { + +namespace { + +// Returns whether |window| can be moved via a two finger drag given +// the hittest results of the two fingers. +bool CanStartTwoFingerMove(WmWindow* window, + int window_component1, + int window_component2) { + // We allow moving a window via two fingers when the hittest components are + // HTCLIENT. This is done so that a window can be dragged via two fingers when + // the tab strip is full and hitting the caption area is difficult. We check + // the window type and the state type so that we do not steal touches from the + // web contents. + if (!window->GetWindowState()->IsNormalOrSnapped() || + window->GetType() != ui::wm::WINDOW_TYPE_NORMAL) { + return false; + } + int component1_behavior = + WindowResizer::GetBoundsChangeForWindowComponent(window_component1); + int component2_behavior = + WindowResizer::GetBoundsChangeForWindowComponent(window_component2); + return (component1_behavior & WindowResizer::kBoundsChange_Resizes) == 0 && + (component2_behavior & WindowResizer::kBoundsChange_Resizes) == 0; +} + +// Returns whether |window| can be moved or resized via one finger given +// |window_component|. +bool CanStartOneFingerDrag(int window_component) { + return WindowResizer::GetBoundsChangeForWindowComponent(window_component) != + 0; +} + +// Returns the window component containing |event|'s location. +int GetWindowComponent(WmWindow* window, const ui::LocatedEvent& event) { + return window->GetNonClientComponent(event.location()); +} + +} // namespace + +// ScopedWindowResizer --------------------------------------------------------- + +// Wraps a WindowResizer and installs an observer on its target window. When +// the window is destroyed ResizerWindowDestroyed() is invoked back on the +// WmToplevelWindowEventHandler to clean up. +class WmToplevelWindowEventHandler::ScopedWindowResizer + : public aura::WindowObserver, + public wm::WindowStateObserver { + public: + ScopedWindowResizer(WmToplevelWindowEventHandler* handler, + std::unique_ptr<WindowResizer> resizer); + ~ScopedWindowResizer() override; + + // Returns true if the drag moves the window and does not resize. + bool IsMove() const; + + WindowResizer* resizer() { return resizer_.get(); } + + // WindowObserver overrides: + void OnWindowDestroying(aura::Window* window) override; + + // WindowStateObserver overrides: + void OnPreWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType type) override; + + private: + WmToplevelWindowEventHandler* handler_; + std::unique_ptr<WindowResizer> resizer_; + + // Whether ScopedWindowResizer grabbed capture. + bool grabbed_capture_; + + DISALLOW_COPY_AND_ASSIGN(ScopedWindowResizer); +}; + +WmToplevelWindowEventHandler::ScopedWindowResizer::ScopedWindowResizer( + WmToplevelWindowEventHandler* handler, + std::unique_ptr<WindowResizer> resizer) + : handler_(handler), resizer_(std::move(resizer)), grabbed_capture_(false) { + WmWindow* target = resizer_->GetTarget(); + target->aura_window()->AddObserver(this); + target->GetWindowState()->AddObserver(this); + + if (!target->HasCapture()) { + grabbed_capture_ = true; + target->SetCapture(); + } +} + +WmToplevelWindowEventHandler::ScopedWindowResizer::~ScopedWindowResizer() { + WmWindow* target = resizer_->GetTarget(); + target->aura_window()->RemoveObserver(this); + target->GetWindowState()->RemoveObserver(this); + if (grabbed_capture_) + target->ReleaseCapture(); +} + +bool WmToplevelWindowEventHandler::ScopedWindowResizer::IsMove() const { + return resizer_->details().bounds_change == + WindowResizer::kBoundsChange_Repositions; +} + +void WmToplevelWindowEventHandler::ScopedWindowResizer:: + OnPreWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old) { + handler_->CompleteDrag(DragResult::SUCCESS); +} + +void WmToplevelWindowEventHandler::ScopedWindowResizer::OnWindowDestroying( + aura::Window* window) { + DCHECK_EQ(resizer_->GetTarget(), WmWindow::Get(window)); + handler_->ResizerWindowDestroyed(); +} + +// WmToplevelWindowEventHandler +// -------------------------------------------------- + +WmToplevelWindowEventHandler::WmToplevelWindowEventHandler(WmShell* shell) + : shell_(shell), first_finger_hittest_(HTNOWHERE) { + shell_->AddDisplayObserver(this); +} + +WmToplevelWindowEventHandler::~WmToplevelWindowEventHandler() { + shell_->RemoveDisplayObserver(this); +} + +void WmToplevelWindowEventHandler::OnKeyEvent(ui::KeyEvent* event) { + if (window_resizer_.get() && event->type() == ui::ET_KEY_PRESSED && + event->key_code() == ui::VKEY_ESCAPE) { + CompleteDrag(DragResult::REVERT); + } +} + +void WmToplevelWindowEventHandler::OnMouseEvent(ui::MouseEvent* event, + WmWindow* target) { + if (event->handled()) + return; + if ((event->flags() & + (ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON)) != 0) + return; + + if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED) { + // Capture is grabbed when both gesture and mouse drags start. Handle + // capture loss regardless of which type of drag is in progress. + HandleCaptureLost(event); + return; + } + + if (in_gesture_drag_) + return; + + switch (event->type()) { + case ui::ET_MOUSE_PRESSED: + HandleMousePressed(target, event); + break; + case ui::ET_MOUSE_DRAGGED: + HandleDrag(target, event); + break; + case ui::ET_MOUSE_RELEASED: + HandleMouseReleased(target, event); + break; + case ui::ET_MOUSE_MOVED: + HandleMouseMoved(target, event); + break; + case ui::ET_MOUSE_EXITED: + HandleMouseExited(target, event); + break; + default: + break; + } +} + +void WmToplevelWindowEventHandler::OnGestureEvent(ui::GestureEvent* event, + WmWindow* target) { + if (event->handled()) + return; + if (!target->HasNonClientArea()) + return; + + if (window_resizer_.get() && !in_gesture_drag_) + return; + + if (window_resizer_.get() && + window_resizer_->resizer()->GetTarget() != target) { + return; + } + + if (event->details().touch_points() > 2) { + if (CompleteDrag(DragResult::SUCCESS)) + event->StopPropagation(); + return; + } + + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: { + int component = GetWindowComponent(target, *event); + if (!(WindowResizer::GetBoundsChangeForWindowComponent(component) & + WindowResizer::kBoundsChange_Resizes)) + return; + target->ShowResizeShadow(component); + return; + } + case ui::ET_GESTURE_END: { + target->HideResizeShadow(); + + if (window_resizer_.get() && + (event->details().touch_points() == 1 || + !CanStartOneFingerDrag(first_finger_hittest_))) { + CompleteDrag(DragResult::SUCCESS); + event->StopPropagation(); + } + return; + } + case ui::ET_GESTURE_BEGIN: { + if (event->details().touch_points() == 1) { + first_finger_hittest_ = GetWindowComponent(target, *event); + } else if (window_resizer_.get()) { + if (!window_resizer_->IsMove()) { + // The transition from resizing with one finger to resizing with two + // fingers causes unintended resizing because the location of + // ET_GESTURE_SCROLL_UPDATE jumps from the position of the first + // finger to the position in the middle of the two fingers. For this + // reason two finger resizing is not supported. + CompleteDrag(DragResult::SUCCESS); + event->StopPropagation(); + } + } else { + int second_finger_hittest = GetWindowComponent(target, *event); + if (CanStartTwoFingerMove(target, first_finger_hittest_, + second_finger_hittest)) { + gfx::Point location_in_parent = + event->details().bounding_box().CenterPoint(); + AttemptToStartDrag(target, location_in_parent, HTCAPTION, + aura::client::WINDOW_MOVE_SOURCE_TOUCH, + EndClosure()); + event->StopPropagation(); + } + } + return; + } + case ui::ET_GESTURE_SCROLL_BEGIN: { + // The one finger drag is not started in ET_GESTURE_BEGIN to avoid the + // window jumping upon initiating a two finger drag. When a one finger + // drag is converted to a two finger drag, a jump occurs because the + // location of the ET_GESTURE_SCROLL_UPDATE event switches from the single + // finger's position to the position in the middle of the two fingers. + if (window_resizer_.get()) + return; + int component = GetWindowComponent(target, *event); + if (!CanStartOneFingerDrag(component)) + return; + gfx::Point location_in_parent( + target->ConvertPointToTarget(target->GetParent(), event->location())); + AttemptToStartDrag(target, location_in_parent, component, + aura::client::WINDOW_MOVE_SOURCE_TOUCH, EndClosure()); + event->StopPropagation(); + return; + } + default: + break; + } + + if (!window_resizer_.get()) + return; + + switch (event->type()) { + case ui::ET_GESTURE_SCROLL_UPDATE: + HandleDrag(target, event); + event->StopPropagation(); + return; + case ui::ET_GESTURE_SCROLL_END: + // We must complete the drag here instead of as a result of ET_GESTURE_END + // because otherwise the drag will be reverted when EndMoveLoop() is + // called. + // TODO(pkotwicz): Pass drag completion status to + // WindowMoveClient::EndMoveLoop(). + CompleteDrag(DragResult::SUCCESS); + event->StopPropagation(); + return; + case ui::ET_SCROLL_FLING_START: + CompleteDrag(DragResult::SUCCESS); + + // TODO(pkotwicz): Fix tests which inadvertantly start flings and check + // window_resizer_->IsMove() instead of the hittest component at |event|'s + // location. + if (GetWindowComponent(target, *event) != HTCAPTION || + !target->GetWindowState()->IsNormalOrSnapped()) { + return; + } + + if (event->details().velocity_y() > kMinVertVelocityForWindowMinimize) { + SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MINIMIZED); + } else if (event->details().velocity_y() < + -kMinVertVelocityForWindowMinimize) { + SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MAXIMIZED); + } else if (event->details().velocity_x() > + kMinHorizVelocityForWindowSwipe) { + SetWindowStateTypeFromGesture(target, + wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED); + } else if (event->details().velocity_x() < + -kMinHorizVelocityForWindowSwipe) { + SetWindowStateTypeFromGesture(target, + wm::WINDOW_STATE_TYPE_LEFT_SNAPPED); + } + event->StopPropagation(); + return; + case ui::ET_GESTURE_SWIPE: + DCHECK_GT(event->details().touch_points(), 0); + if (event->details().touch_points() == 1) + return; + if (!target->GetWindowState()->IsNormalOrSnapped()) + return; + + CompleteDrag(DragResult::SUCCESS); + + if (event->details().swipe_down()) { + SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MINIMIZED); + } else if (event->details().swipe_up()) { + SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MAXIMIZED); + } else if (event->details().swipe_right()) { + SetWindowStateTypeFromGesture(target, + wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED); + } else { + SetWindowStateTypeFromGesture(target, + wm::WINDOW_STATE_TYPE_LEFT_SNAPPED); + } + event->StopPropagation(); + return; + default: + return; + } +} + +bool WmToplevelWindowEventHandler::AttemptToStartDrag( + WmWindow* window, + const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source, + const EndClosure& end_closure) { + if (window_resizer_.get()) + return false; + std::unique_ptr<WindowResizer> resizer( + CreateWindowResizer(window, point_in_parent, window_component, source)); + if (!resizer) + return false; + + end_closure_ = end_closure; + window_resizer_.reset(new ScopedWindowResizer(this, std::move(resizer))); + + pre_drag_window_bounds_ = window->GetBounds(); + in_gesture_drag_ = (source == aura::client::WINDOW_MOVE_SOURCE_TOUCH); + return true; +} + +void WmToplevelWindowEventHandler::RevertDrag() { + CompleteDrag(DragResult::REVERT); +} + +bool WmToplevelWindowEventHandler::CompleteDrag(DragResult result) { + if (!window_resizer_) + return false; + + std::unique_ptr<ScopedWindowResizer> resizer(std::move(window_resizer_)); + switch (result) { + case DragResult::SUCCESS: + resizer->resizer()->CompleteDrag(); + break; + case DragResult::REVERT: + resizer->resizer()->RevertDrag(); + break; + case DragResult::WINDOW_DESTROYED: + // We explicitly do not invoke RevertDrag() since that may do things to + // the window that was destroyed. + break; + } + + first_finger_hittest_ = HTNOWHERE; + in_gesture_drag_ = false; + if (!end_closure_.is_null()) { + // Clear local state in case running the closure deletes us. + EndClosure end_closure = end_closure_; + end_closure_.Reset(); + end_closure.Run(result); + } + return true; +} + +void WmToplevelWindowEventHandler::HandleMousePressed(WmWindow* target, + ui::MouseEvent* event) { + if (event->phase() != ui::EP_PRETARGET || !target->HasNonClientArea()) + return; + + // We also update the current window component here because for the + // mouse-drag-release-press case, where the mouse is released and + // pressed without mouse move event. + int component = GetWindowComponent(target, *event); + if ((event->flags() & (ui::EF_IS_DOUBLE_CLICK | ui::EF_IS_TRIPLE_CLICK)) == + 0 && + WindowResizer::GetBoundsChangeForWindowComponent(component)) { + gfx::Point location_in_parent( + target->ConvertPointToTarget(target->GetParent(), event->location())); + AttemptToStartDrag(target, location_in_parent, component, + aura::client::WINDOW_MOVE_SOURCE_MOUSE, EndClosure()); + // Set as handled so that other event handlers do no act upon the event + // but still receive it so that they receive both parts of each pressed/ + // released pair. + event->SetHandled(); + } else { + CompleteDrag(DragResult::SUCCESS); + } +} + +void WmToplevelWindowEventHandler::HandleMouseReleased(WmWindow* target, + ui::MouseEvent* event) { + if (event->phase() == ui::EP_PRETARGET) + CompleteDrag(DragResult::SUCCESS); +} + +void WmToplevelWindowEventHandler::HandleDrag(WmWindow* target, + ui::LocatedEvent* event) { + // This function only be triggered to move window + // by mouse drag or touch move event. + DCHECK(event->type() == ui::ET_MOUSE_DRAGGED || + event->type() == ui::ET_TOUCH_MOVED || + event->type() == ui::ET_GESTURE_SCROLL_UPDATE); + + // Drag actions are performed pre-target handling to prevent spurious mouse + // moves from the move/size operation from being sent to the target. + if (event->phase() != ui::EP_PRETARGET) + return; + + if (!window_resizer_) + return; + window_resizer_->resizer()->Drag( + target->ConvertPointToTarget(target->GetParent(), event->location()), + event->flags()); + event->StopPropagation(); +} + +void WmToplevelWindowEventHandler::HandleMouseMoved(WmWindow* target, + ui::LocatedEvent* event) { + // Shadow effects are applied after target handling. Note that we don't + // respect ER_HANDLED here right now since we have not had a reason to allow + // the target to cancel shadow rendering. + if (event->phase() != ui::EP_POSTTARGET || !target->HasNonClientArea()) + return; + + // TODO(jamescook): Move the resize cursor update code into here from + // CompoundEventFilter? + if (event->flags() & ui::EF_IS_NON_CLIENT) { + int component = target->GetNonClientComponent(event->location()); + target->ShowResizeShadow(component); + } else { + target->HideResizeShadow(); + } +} + +void WmToplevelWindowEventHandler::HandleMouseExited(WmWindow* target, + ui::LocatedEvent* event) { + // Shadow effects are applied after target handling. Note that we don't + // respect ER_HANDLED here right now since we have not had a reason to allow + // the target to cancel shadow rendering. + if (event->phase() != ui::EP_POSTTARGET) + return; + + target->HideResizeShadow(); +} + +void WmToplevelWindowEventHandler::HandleCaptureLost(ui::LocatedEvent* event) { + if (event->phase() == ui::EP_PRETARGET) { + // We complete the drag instead of reverting it, as reverting it will result + // in a weird behavior when a dragged tab produces a modal dialog while the + // drag is in progress. crbug.com/558201. + CompleteDrag(DragResult::SUCCESS); + } +} + +void WmToplevelWindowEventHandler::SetWindowStateTypeFromGesture( + WmWindow* window, + wm::WindowStateType new_state_type) { + wm::WindowState* window_state = window->GetWindowState(); + // TODO(oshima): Move extra logic (set_unminimize_to_restore_bounds, + // SetRestoreBoundsInParent) that modifies the window state + // into WindowState. + switch (new_state_type) { + case wm::WINDOW_STATE_TYPE_MINIMIZED: + if (window_state->CanMinimize()) { + window_state->Minimize(); + window_state->set_unminimize_to_restore_bounds(true); + window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); + } + break; + case wm::WINDOW_STATE_TYPE_MAXIMIZED: + if (window_state->CanMaximize()) { + window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); + window_state->Maximize(); + } + break; + case wm::WINDOW_STATE_TYPE_LEFT_SNAPPED: + if (window_state->CanSnap()) { + window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); + const wm::WMEvent event(wm::WM_EVENT_SNAP_LEFT); + window_state->OnWMEvent(&event); + } + break; + case wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED: + if (window_state->CanSnap()) { + window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); + const wm::WMEvent event(wm::WM_EVENT_SNAP_RIGHT); + window_state->OnWMEvent(&event); + } + break; + default: + NOTREACHED(); + } +} + +void WmToplevelWindowEventHandler::ResizerWindowDestroyed() { + CompleteDrag(DragResult::WINDOW_DESTROYED); +} + +void WmToplevelWindowEventHandler::OnDisplayConfigurationChanging() { + CompleteDrag(DragResult::REVERT); +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/wm_toplevel_window_event_handler.h b/ash/common/wm/wm_toplevel_window_event_handler.h new file mode 100644 index 0000000..161b627 --- /dev/null +++ b/ash/common/wm/wm_toplevel_window_event_handler.h
@@ -0,0 +1,128 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_ +#define ASH_COMMON_WM_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/wm_types.h" +#include "ash/common/wm_display_observer.h" +#include "base/callback.h" +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/wm/public/window_move_client.h" + +namespace ui { +class KeyEvent; +class LocatedEvent; +class MouseEvent; +class GestureEvent; +} + +namespace ash { + +class WmShell; +class WmWindow; + +namespace wm { + +// WmToplevelWindowEventHandler handles dragging and resizing of top level +// windows. WmToplevelWindowEventHandler is forwarded events, such as from an +// EventHandler. +class ASH_EXPORT WmToplevelWindowEventHandler : public WmDisplayObserver { + public: + // Describes what triggered ending the drag. + enum class DragResult { + // The drag successfully completed. + SUCCESS, + + REVERT, + + // The underlying window was destroyed while the drag is in process. + WINDOW_DESTROYED + }; + using EndClosure = base::Callback<void(DragResult)>; + + explicit WmToplevelWindowEventHandler(WmShell* shell); + ~WmToplevelWindowEventHandler() override; + + void OnKeyEvent(ui::KeyEvent* event); + void OnMouseEvent(ui::MouseEvent* event, WmWindow* target); + void OnGestureEvent(ui::GestureEvent* event, WmWindow* target); + + // Attempts to start a drag if one is not already in progress. Returns true if + // successful. |end_closure| is run when the drag completes. |end_closure| is + // not run if the drag does not start. + bool AttemptToStartDrag(WmWindow* window, + const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source, + const EndClosure& end_closure); + + // If there is a drag in progress it is reverted, otherwise does nothing. + void RevertDrag(); + + // Returns true if there is a drag in progress. + bool is_drag_in_progress() const { return window_resizer_.get() != nullptr; } + + private: + class ScopedWindowResizer; + + // Completes or reverts the drag if one is in progress. Returns true if a + // drag was completed or reverted. + bool CompleteDrag(DragResult result); + + void HandleMousePressed(WmWindow* target, ui::MouseEvent* event); + void HandleMouseReleased(WmWindow* target, ui::MouseEvent* event); + + // Called during a drag to resize/position the window. + void HandleDrag(WmWindow* target, ui::LocatedEvent* event); + + // Called during mouse moves to update window resize shadows. + void HandleMouseMoved(WmWindow* target, ui::LocatedEvent* event); + + // Called for mouse exits to hide window resize shadows. + void HandleMouseExited(WmWindow* target, ui::LocatedEvent* event); + + // Called when mouse capture is lost. + void HandleCaptureLost(ui::LocatedEvent* event); + + // Sets |window|'s state type to |new_state_type|. Called after the drag has + // been completed for fling gestures. + void SetWindowStateTypeFromGesture(WmWindow* window, + wm::WindowStateType new_state_type); + + // Invoked from ScopedWindowResizer if the window is destroyed. + void ResizerWindowDestroyed(); + + // WmDisplayObserver: + void OnDisplayConfigurationChanging() override; + + WmShell* shell_; + + // The hittest result for the first finger at the time that it initially + // touched the screen. |first_finger_hittest_| is one of ui/base/hit_test.h + int first_finger_hittest_; + + // The window bounds when the drag was started. When a window is minimized, + // maximized or snapped via a swipe/fling gesture, the restore bounds should + // be set to the bounds of the window when the drag was started. + gfx::Rect pre_drag_window_bounds_; + + // Is a window move/resize in progress because of gesture events? + bool in_gesture_drag_ = false; + + std::unique_ptr<ScopedWindowResizer> window_resizer_; + + EndClosure end_closure_; + + DISALLOW_COPY_AND_ASSIGN(WmToplevelWindowEventHandler); +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_
diff --git a/ash/common/wm/wm_types.cc b/ash/common/wm/wm_types.cc new file mode 100644 index 0000000..4deed1a --- /dev/null +++ b/ash/common/wm/wm_types.cc
@@ -0,0 +1,60 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/wm_types.h" + +#include "base/logging.h" + +namespace ash { +namespace wm { + +// This is to catch the change to WindowShowState. +static_assert(ui::SHOW_STATE_END == + static_cast<ui::WindowShowState>(WINDOW_STATE_TYPE_END), + "show enum mismatch"); + +WindowStateType ToWindowStateType(ui::WindowShowState state) { + return static_cast<WindowStateType>(state); +} + +ui::WindowShowState ToWindowShowState(WindowStateType type) { + switch (type) { + case WINDOW_STATE_TYPE_DEFAULT: + return ui::SHOW_STATE_DEFAULT; + case WINDOW_STATE_TYPE_NORMAL: + case WINDOW_STATE_TYPE_RIGHT_SNAPPED: + case WINDOW_STATE_TYPE_LEFT_SNAPPED: + case WINDOW_STATE_TYPE_AUTO_POSITIONED: + return ui::SHOW_STATE_NORMAL; + + // TODO(afakhry): Remove Docked Windows in M58. + case WINDOW_STATE_TYPE_DOCKED: + return ui::SHOW_STATE_DOCKED; + case WINDOW_STATE_TYPE_MINIMIZED: + case WINDOW_STATE_TYPE_DOCKED_MINIMIZED: + return ui::SHOW_STATE_MINIMIZED; + case WINDOW_STATE_TYPE_MAXIMIZED: + return ui::SHOW_STATE_MAXIMIZED; + case WINDOW_STATE_TYPE_INACTIVE: + return ui::SHOW_STATE_INACTIVE; + case WINDOW_STATE_TYPE_FULLSCREEN: + case WINDOW_STATE_TYPE_PINNED: + case WINDOW_STATE_TYPE_TRUSTED_PINNED: + return ui::SHOW_STATE_FULLSCREEN; + case WINDOW_STATE_TYPE_END: + NOTREACHED(); + } + NOTREACHED(); + return ui::SHOW_STATE_DEFAULT; +} + +bool IsMaximizedOrFullscreenOrPinnedWindowStateType(WindowStateType type) { + return type == WINDOW_STATE_TYPE_MAXIMIZED || + type == WINDOW_STATE_TYPE_FULLSCREEN || + type == WINDOW_STATE_TYPE_PINNED || + type == WINDOW_STATE_TYPE_TRUSTED_PINNED; +} + +} // namespace wm +} // namespace ash
diff --git a/ash/common/wm/wm_types.h b/ash/common/wm/wm_types.h new file mode 100644 index 0000000..ad886d8c --- /dev/null +++ b/ash/common/wm/wm_types.h
@@ -0,0 +1,66 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WM_TYPES_H_ +#define ASH_COMMON_WM_WM_TYPES_H_ + +#include "ash/ash_export.h" +#include "ui/base/ui_base_types.h" + +namespace ash { +namespace wm { + +// This enum defines both common show state copied from +// ui::WindowShowState as well as new states introduced in ash. +// The separate enum is defined here because we don't want to leak +// these type to ui/base until they're stable and we know for sure +// that they'll persist over time. +enum WindowStateType { + // Common state + WINDOW_STATE_TYPE_DEFAULT = 0, + + // Normal represents a state where the position/size has been + // specified by a use. + WINDOW_STATE_TYPE_NORMAL, + WINDOW_STATE_TYPE_MINIMIZED, + WINDOW_STATE_TYPE_MAXIMIZED, + WINDOW_STATE_TYPE_INACTIVE, + WINDOW_STATE_TYPE_FULLSCREEN, + WINDOW_STATE_TYPE_DOCKED, + WINDOW_STATE_TYPE_END, // to avoid using SHOW_STATE_END + + // Ash specific states: + + WINDOW_STATE_TYPE_LEFT_SNAPPED, + WINDOW_STATE_TYPE_RIGHT_SNAPPED, + + WINDOW_STATE_TYPE_DOCKED_MINIMIZED, + + // A window is in this state when it is automatically placed and + // sized by the window manager. (it's newly opened, or pushed to the side + // due to new window, for example). + WINDOW_STATE_TYPE_AUTO_POSITIONED, + + // A window is pinned on top of other windows with fullscreenized. + // Corresponding shelf should be hidden, also most of windows other than the + // pinned one should be hidden. + WINDOW_STATE_TYPE_PINNED, + WINDOW_STATE_TYPE_TRUSTED_PINNED, +}; + +// Utility functions to convert WindowStateType <-> ui::WindowShowState. +// Note: LEFT/RIGHT MAXIMIZED, AUTO_POSITIONED type will be lost when +// converting to ui::WindowShowState. +ASH_EXPORT WindowStateType ToWindowStateType(ui::WindowShowState state); +ASH_EXPORT ui::WindowShowState ToWindowShowState(WindowStateType type); + +// Returns true if |type| is WINDOW_STATE_TYPE_MAXIMIZED, +// WINDOW_STATE_TYPE_FULLSCREEN or WINDOW_STATE_TYPE_PINNED. +ASH_EXPORT bool IsMaximizedOrFullscreenOrPinnedWindowStateType( + WindowStateType type); + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WM_TYPES_H_
diff --git a/ash/common/wm/wm_window_animations.cc b/ash/common/wm/wm_window_animations.cc new file mode 100644 index 0000000..64b431f --- /dev/null +++ b/ash/common/wm/wm_window_animations.cc
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/wm_window_animations.h" + +#include "ui/compositor/layer.h" +#include "ui/gfx/transform.h" + +namespace ash { + +void SetTransformForScaleAnimation(ui::Layer* layer, + LayerScaleAnimationDirection type) { + // Scales for windows above and below the current workspace. + const float kLayerScaleAboveSize = 1.1f; + const float kLayerScaleBelowSize = .9f; + + const float scale = type == LAYER_SCALE_ANIMATION_ABOVE + ? kLayerScaleAboveSize + : kLayerScaleBelowSize; + gfx::Transform transform; + transform.Translate(-layer->bounds().width() * (scale - 1.0f) / 2, + -layer->bounds().height() * (scale - 1.0f) / 2); + transform.Scale(scale, scale); + layer->SetTransform(transform); +} + +} // namespace ash
diff --git a/ash/common/wm/wm_window_animations.h b/ash/common/wm/wm_window_animations.h new file mode 100644 index 0000000..d704304 --- /dev/null +++ b/ash/common/wm/wm_window_animations.h
@@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WM_WINDOW_ANIMATIONS_H_ +#define ASH_COMMON_WM_WM_WINDOW_ANIMATIONS_H_ + +#include "ash/ash_export.h" + +namespace ui { +class Layer; +} + +// This is only for animations specific to Ash. For window animations shared +// with desktop Chrome, see ui/views/corewm/window_animations.h. +namespace ash { + +// Direction for ash-specific window animations used in workspaces and +// lock/unlock animations. +enum LayerScaleAnimationDirection { + LAYER_SCALE_ANIMATION_ABOVE, + LAYER_SCALE_ANIMATION_BELOW, +}; + +// Applies scale related to the specified AshWindowScaleType. +ASH_EXPORT void SetTransformForScaleAnimation( + ui::Layer* layer, + LayerScaleAnimationDirection type); + +} // namespace ash + +#endif // ASH_COMMON_WM_WM_WINDOW_ANIMATIONS_H_
diff --git a/ash/common/wm/workspace/magnetism_matcher.cc b/ash/common/wm/workspace/magnetism_matcher.cc new file mode 100644 index 0000000..e428d96 --- /dev/null +++ b/ash/common/wm/workspace/magnetism_matcher.cc
@@ -0,0 +1,195 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/magnetism_matcher.h" + +#include <algorithm> +#include <cmath> + +#include "base/memory/ptr_util.h" + +namespace ash { +namespace { + +// Returns true if |a| is close enough to |b| that the two edges snap. +bool IsCloseEnough(int a, int b) { + return abs(a - b) <= MagnetismMatcher::kMagneticDistance; +} + +// Returns true if the specified SecondaryMagnetismEdge can be matched with a +// primary edge of |primary|. |edges| is a bitmask of the allowed +// MagnetismEdges. +bool CanMatchSecondaryEdge(MagnetismEdge primary, + SecondaryMagnetismEdge secondary, + uint32_t edges) { + // Convert |secondary| to a MagnetismEdge so we can compare it to |edges|. + MagnetismEdge secondary_as_magnetism_edge = MAGNETISM_EDGE_TOP; + switch (primary) { + case MAGNETISM_EDGE_TOP: + case MAGNETISM_EDGE_BOTTOM: + if (secondary == SECONDARY_MAGNETISM_EDGE_LEADING) + secondary_as_magnetism_edge = MAGNETISM_EDGE_LEFT; + else if (secondary == SECONDARY_MAGNETISM_EDGE_TRAILING) + secondary_as_magnetism_edge = MAGNETISM_EDGE_RIGHT; + else + NOTREACHED(); + break; + case MAGNETISM_EDGE_LEFT: + case MAGNETISM_EDGE_RIGHT: + if (secondary == SECONDARY_MAGNETISM_EDGE_LEADING) + secondary_as_magnetism_edge = MAGNETISM_EDGE_TOP; + else if (secondary == SECONDARY_MAGNETISM_EDGE_TRAILING) + secondary_as_magnetism_edge = MAGNETISM_EDGE_BOTTOM; + else + NOTREACHED(); + break; + } + return (edges & secondary_as_magnetism_edge) != 0; +} + +} // namespace + +// MagnetismEdgeMatcher -------------------------------------------------------- + +MagnetismEdgeMatcher::MagnetismEdgeMatcher(const gfx::Rect& bounds, + MagnetismEdge edge) + : bounds_(bounds), edge_(edge) { + ranges_.push_back(GetSecondaryRange(bounds_)); +} + +MagnetismEdgeMatcher::~MagnetismEdgeMatcher() {} + +bool MagnetismEdgeMatcher::ShouldAttach(const gfx::Rect& bounds) { + if (is_edge_obscured()) + return false; + + if (IsCloseEnough(GetPrimaryCoordinate(bounds_, edge_), + GetPrimaryCoordinate(bounds, FlipEdge(edge_)))) { + const Range range(GetSecondaryRange(bounds)); + Ranges::const_iterator i = + std::lower_bound(ranges_.begin(), ranges_.end(), range); + // Close enough, but only attach if some portion of the edge is visible. + if ((i != ranges_.begin() && RangesIntersect(*(i - 1), range)) || + (i != ranges_.end() && RangesIntersect(*i, range))) { + return true; + } + } + // NOTE: this checks against the current bounds, we may want to allow some + // flexibility here. + const Range primary_range(GetPrimaryRange(bounds)); + if (primary_range.first <= GetPrimaryCoordinate(bounds_, edge_) && + primary_range.second >= GetPrimaryCoordinate(bounds_, edge_)) { + UpdateRanges(GetSecondaryRange(bounds)); + } + return false; +} + +void MagnetismEdgeMatcher::UpdateRanges(const Range& range) { + Ranges::const_iterator it = + std::lower_bound(ranges_.begin(), ranges_.end(), range); + if (it != ranges_.begin() && RangesIntersect(*(it - 1), range)) + --it; + if (it == ranges_.end()) + return; + + for (size_t i = it - ranges_.begin(); + i < ranges_.size() && RangesIntersect(ranges_[i], range);) { + if (range.first <= ranges_[i].first && range.second >= ranges_[i].second) { + ranges_.erase(ranges_.begin() + i); + } else if (range.first < ranges_[i].first) { + DCHECK_GT(range.second, ranges_[i].first); + ranges_[i] = Range(range.second, ranges_[i].second); + ++i; + } else { + Range existing(ranges_[i]); + ranges_[i].second = range.first; + ++i; + if (existing.second > range.second) { + ranges_.insert(ranges_.begin() + i, + Range(range.second, existing.second)); + ++i; + } + } + } +} + +// MagnetismMatcher ------------------------------------------------------------ + +// static +const int MagnetismMatcher::kMagneticDistance = 8; + +MagnetismMatcher::MagnetismMatcher(const gfx::Rect& bounds, uint32_t edges) + : edges_(edges) { + if (edges & MAGNETISM_EDGE_TOP) { + matchers_.push_back( + base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_TOP)); + } + if (edges & MAGNETISM_EDGE_LEFT) { + matchers_.push_back( + base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_LEFT)); + } + if (edges & MAGNETISM_EDGE_BOTTOM) { + matchers_.push_back( + base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_BOTTOM)); + } + if (edges & MAGNETISM_EDGE_RIGHT) { + matchers_.push_back( + base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_RIGHT)); + } +} + +MagnetismMatcher::~MagnetismMatcher() {} + +bool MagnetismMatcher::ShouldAttach(const gfx::Rect& bounds, + MatchedEdge* edge) { + for (const auto& matcher : matchers_) { + if (matcher->ShouldAttach(bounds)) { + edge->primary_edge = matcher->edge(); + AttachToSecondaryEdge(bounds, edge->primary_edge, + &(edge->secondary_edge)); + return true; + } + } + return false; +} + +bool MagnetismMatcher::AreEdgesObscured() const { + for (const auto& matcher : matchers_) { + if (!matcher->is_edge_obscured()) + return false; + } + return true; +} + +void MagnetismMatcher::AttachToSecondaryEdge( + const gfx::Rect& bounds, + MagnetismEdge edge, + SecondaryMagnetismEdge* secondary_edge) const { + const gfx::Rect& src_bounds(matchers_[0]->bounds()); + if (edge == MAGNETISM_EDGE_LEFT || edge == MAGNETISM_EDGE_RIGHT) { + if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_LEADING, edges_) && + IsCloseEnough(bounds.y(), src_bounds.y())) { + *secondary_edge = SECONDARY_MAGNETISM_EDGE_LEADING; + } else if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_TRAILING, + edges_) && + IsCloseEnough(bounds.bottom(), src_bounds.bottom())) { + *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING; + } else { + *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE; + } + } else { + if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_LEADING, edges_) && + IsCloseEnough(bounds.x(), src_bounds.x())) { + *secondary_edge = SECONDARY_MAGNETISM_EDGE_LEADING; + } else if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_TRAILING, + edges_) && + IsCloseEnough(bounds.right(), src_bounds.right())) { + *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING; + } else { + *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE; + } + } +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/magnetism_matcher.h b/ash/common/wm/workspace/magnetism_matcher.h new file mode 100644 index 0000000..034f9c3 --- /dev/null +++ b/ash/common/wm/workspace/magnetism_matcher.h
@@ -0,0 +1,192 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_MAGNETISM_MATCHER_H_ +#define ASH_COMMON_WM_WORKSPACE_MAGNETISM_MATCHER_H_ + +#include <stdint.h> + +#include <memory> +#include <utility> +#include <vector> + +#include "ash/ash_export.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" + +namespace ash { + +enum MagnetismEdge { + MAGNETISM_EDGE_TOP = 1 << 0, + MAGNETISM_EDGE_LEFT = 1 << 1, + MAGNETISM_EDGE_BOTTOM = 1 << 2, + MAGNETISM_EDGE_RIGHT = 1 << 3, +}; + +const uint32_t kAllMagnetismEdges = MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_LEFT | + MAGNETISM_EDGE_BOTTOM | + MAGNETISM_EDGE_RIGHT; + +// MagnetismEdgeMatcher is used for matching a particular edge of a window. You +// shouldn't need to use this directly, instead use MagnetismMatcher which takes +// care of all edges. +// MagnetismEdgeMatcher maintains a range of the visible portions of the +// edge. As ShouldAttach() is invoked the visible range is updated. +class MagnetismEdgeMatcher { + public: + MagnetismEdgeMatcher(const gfx::Rect& bounds, MagnetismEdge edge); + ~MagnetismEdgeMatcher(); + + MagnetismEdge edge() const { return edge_; } + const gfx::Rect& bounds() const { return bounds_; } + + // Returns true if the edge is completely obscured. If true ShouldAttach() + // will return false. + bool is_edge_obscured() const { return ranges_.empty(); } + + // Returns true if should attach to the specified bounds. + bool ShouldAttach(const gfx::Rect& bounds); + + private: + typedef std::pair<int, int> Range; + typedef std::vector<Range> Ranges; + + // Removes |range| from |ranges_|. + void UpdateRanges(const Range& range); + + static int GetPrimaryCoordinate(const gfx::Rect& bounds, MagnetismEdge edge) { + switch (edge) { + case MAGNETISM_EDGE_TOP: + return bounds.y(); + case MAGNETISM_EDGE_LEFT: + return bounds.x(); + case MAGNETISM_EDGE_BOTTOM: + return bounds.bottom(); + case MAGNETISM_EDGE_RIGHT: + return bounds.right(); + } + NOTREACHED(); + return 0; + } + + static MagnetismEdge FlipEdge(MagnetismEdge edge) { + switch (edge) { + case MAGNETISM_EDGE_TOP: + return MAGNETISM_EDGE_BOTTOM; + case MAGNETISM_EDGE_BOTTOM: + return MAGNETISM_EDGE_TOP; + case MAGNETISM_EDGE_LEFT: + return MAGNETISM_EDGE_RIGHT; + case MAGNETISM_EDGE_RIGHT: + return MAGNETISM_EDGE_LEFT; + } + NOTREACHED(); + return MAGNETISM_EDGE_LEFT; + } + + Range GetPrimaryRange(const gfx::Rect& bounds) const { + switch (edge_) { + case MAGNETISM_EDGE_TOP: + case MAGNETISM_EDGE_BOTTOM: + return Range(bounds.y(), bounds.bottom()); + case MAGNETISM_EDGE_LEFT: + case MAGNETISM_EDGE_RIGHT: + return Range(bounds.x(), bounds.right()); + } + NOTREACHED(); + return Range(); + } + + Range GetSecondaryRange(const gfx::Rect& bounds) const { + switch (edge_) { + case MAGNETISM_EDGE_TOP: + case MAGNETISM_EDGE_BOTTOM: + return Range(bounds.x(), bounds.right()); + case MAGNETISM_EDGE_LEFT: + case MAGNETISM_EDGE_RIGHT: + return Range(bounds.y(), bounds.bottom()); + } + NOTREACHED(); + return Range(); + } + + static bool RangesIntersect(const Range& r1, const Range& r2) { + return r2.first < r1.second && r2.second > r1.first; + } + + // The bounds of window. + const gfx::Rect bounds_; + + // The edge this matcher checks. + const MagnetismEdge edge_; + + // Visible ranges of the edge. Initialized with GetSecondaryRange() and + // updated as ShouldAttach() is invoked. When empty the edge is completely + // obscured by other bounds. + Ranges ranges_; + + DISALLOW_COPY_AND_ASSIGN(MagnetismEdgeMatcher); +}; + +enum SecondaryMagnetismEdge { + SECONDARY_MAGNETISM_EDGE_LEADING, + SECONDARY_MAGNETISM_EDGE_TRAILING, + SECONDARY_MAGNETISM_EDGE_NONE, +}; + +// Used to identify a matched edge. |primary_edge| is relative to the source and +// indicates the edge the two are to share. For example, if |primary_edge| is +// MAGNETISM_EDGE_RIGHT then the right edge of the source should snap to to the +// left edge of the target. |secondary_edge| indicates one of the edges along +// the opposite axis should should also be aligned. For example, if +// |primary_edge| is MAGNETISM_EDGE_RIGHT and |secondary_edge| is +// SECONDARY_MAGNETISM_EDGE_LEADING then the source should snap to the left top +// corner of the target. +struct MatchedEdge { + MagnetismEdge primary_edge; + SecondaryMagnetismEdge secondary_edge; +}; + +// MagnetismMatcher is used to test if a window should snap to another window. +// To use MagnetismMatcher do the following: +// . Create it with the bounds of the window being dragged. +// . Iterate over the child windows checking if the window being dragged should +// attach to it using ShouldAttach(). +// . Use AreEdgesObscured() to test if no other windows can match (because all +// edges are completely obscured). +class ASH_EXPORT MagnetismMatcher { + public: + static const int kMagneticDistance; + + // |edges| is a bitmask of MagnetismEdges to match against. + MagnetismMatcher(const gfx::Rect& bounds, uint32_t edges); + ~MagnetismMatcher(); + + // Returns true if |bounds| is close enough to the initial bounds that the two + // should be attached. If true is returned |edge| is set to indicates how the + // two should snap together. See description of MatchedEdge for details. + bool ShouldAttach(const gfx::Rect& bounds, MatchedEdge* edge); + + // Returns true if no other matches are possible. + bool AreEdgesObscured() const; + + private: + // Sets |secondary_edge| based on whether the secondary edges should snap. + void AttachToSecondaryEdge(const gfx::Rect& bounds, + MagnetismEdge edge, + SecondaryMagnetismEdge* secondary_edge) const; + + // The edges to match against. + const int32_t edges_; + + std::vector<std::unique_ptr<MagnetismEdgeMatcher>> matchers_; + + DISALLOW_COPY_AND_ASSIGN(MagnetismMatcher); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_MAGNETISM_MATCHER_H_
diff --git a/ash/common/wm/workspace/multi_window_resize_controller.cc b/ash/common/wm/workspace/multi_window_resize_controller.cc new file mode 100644 index 0000000..48879e8 --- /dev/null +++ b/ash/common/wm/workspace/multi_window_resize_controller.cc
@@ -0,0 +1,540 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/multi_window_resize_controller.h" + +#include "ash/common/wm/workspace/workspace_window_resizer.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/root_window_controller.h" +#include "ui/base/cursor/cursor.h" +#include "ui/base/hit_test.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/display/screen.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/wm/core/compound_event_filter.h" + +namespace ash { +namespace { + +// Delay before showing. +const int kShowDelayMS = 400; + +// Delay before hiding. +const int kHideDelayMS = 500; + +// Padding from the bottom/right edge the resize widget is shown at. +const int kResizeWidgetPadding = 15; + +bool ContainsX(WmWindow* window, int x) { + return x >= 0 && x <= window->GetBounds().width(); +} + +bool ContainsScreenX(WmWindow* window, int x_in_screen) { + gfx::Point window_loc = + window->ConvertPointFromScreen(gfx::Point(x_in_screen, 0)); + return ContainsX(window, window_loc.x()); +} + +bool ContainsY(WmWindow* window, int y) { + return y >= 0 && y <= window->GetBounds().height(); +} + +bool ContainsScreenY(WmWindow* window, int y_in_screen) { + gfx::Point window_loc = + window->ConvertPointFromScreen(gfx::Point(0, y_in_screen)); + return ContainsY(window, window_loc.y()); +} + +bool Intersects(int x1, int max_1, int x2, int max_2) { + return x2 <= max_1 && max_2 > x1; +} + +} // namespace + +// View contained in the widget. Passes along mouse events to the +// MultiWindowResizeController so that it can start/stop the resize loop. +class MultiWindowResizeController::ResizeView : public views::View { + public: + explicit ResizeView(MultiWindowResizeController* controller, + Direction direction) + : controller_(controller), direction_(direction), image_(NULL) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + int image_id = direction == TOP_BOTTOM ? IDR_AURA_MULTI_WINDOW_RESIZE_H + : IDR_AURA_MULTI_WINDOW_RESIZE_V; + image_ = rb.GetImageNamed(image_id).ToImageSkia(); + } + + // views::View overrides: + gfx::Size GetPreferredSize() const override { + return gfx::Size(image_->width(), image_->height()); + } + void OnPaint(gfx::Canvas* canvas) override { + canvas->DrawImageInt(*image_, 0, 0); + } + bool OnMousePressed(const ui::MouseEvent& event) override { + gfx::Point location(event.location()); + views::View::ConvertPointToScreen(this, &location); + controller_->StartResize(location); + return true; + } + bool OnMouseDragged(const ui::MouseEvent& event) override { + gfx::Point location(event.location()); + views::View::ConvertPointToScreen(this, &location); + controller_->Resize(location, event.flags()); + return true; + } + void OnMouseReleased(const ui::MouseEvent& event) override { + controller_->CompleteResize(); + } + void OnMouseCaptureLost() override { controller_->CancelResize(); } + gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override { + int component = (direction_ == LEFT_RIGHT) ? HTRIGHT : HTBOTTOM; + return ::wm::CompoundEventFilter::CursorForWindowComponent(component); + } + + private: + MultiWindowResizeController* controller_; + const Direction direction_; + const gfx::ImageSkia* image_; + + DISALLOW_COPY_AND_ASSIGN(ResizeView); +}; + +// MouseWatcherHost implementation for MultiWindowResizeController. Forwards +// Contains() to MultiWindowResizeController. +class MultiWindowResizeController::ResizeMouseWatcherHost + : public views::MouseWatcherHost { + public: + ResizeMouseWatcherHost(MultiWindowResizeController* host) : host_(host) {} + + // MouseWatcherHost overrides: + bool Contains(const gfx::Point& point_in_screen, + MouseEventType type) override { + return (type == MOUSE_PRESS) ? host_->IsOverResizeWidget(point_in_screen) + : host_->IsOverWindows(point_in_screen); + } + + private: + MultiWindowResizeController* host_; + + DISALLOW_COPY_AND_ASSIGN(ResizeMouseWatcherHost); +}; + +MultiWindowResizeController::ResizeWindows::ResizeWindows() + : window1(nullptr), window2(nullptr), direction(TOP_BOTTOM) {} + +MultiWindowResizeController::ResizeWindows::ResizeWindows( + const ResizeWindows& other) = default; + +MultiWindowResizeController::ResizeWindows::~ResizeWindows() {} + +bool MultiWindowResizeController::ResizeWindows::Equals( + const ResizeWindows& other) const { + return window1 == other.window1 && window2 == other.window2 && + direction == other.direction; +} + +MultiWindowResizeController::MultiWindowResizeController() {} + +MultiWindowResizeController::~MultiWindowResizeController() { + window_resizer_.reset(); + Hide(); +} + +void MultiWindowResizeController::Show(WmWindow* window, + int component, + const gfx::Point& point_in_window) { + // When the resize widget is showing we ignore Show() requests. Instead we + // only care about mouse movements from MouseWatcher. This is necessary as + // WorkspaceEventHandler only sees mouse movements over the windows, not all + // windows or over the desktop. + if (resize_widget_) + return; + + ResizeWindows windows(DetermineWindows(window, component, point_in_window)); + if (IsShowing() && windows_.Equals(windows)) + return; + + Hide(); + if (!windows.is_valid()) { + windows_ = ResizeWindows(); + return; + } + + windows_ = windows; + windows_.window1->aura_window()->AddObserver(this); + windows_.window2->aura_window()->AddObserver(this); + show_location_in_parent_ = + window->ConvertPointToTarget(window->GetParent(), point_in_window); + show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMS), + this, + &MultiWindowResizeController::ShowIfValidMouseLocation); +} + +void MultiWindowResizeController::Hide() { + if (window_resizer_) + return; // Ignore hides while actively resizing. + + if (windows_.window1) { + windows_.window1->aura_window()->RemoveObserver(this); + windows_.window1 = NULL; + } + if (windows_.window2) { + windows_.window2->aura_window()->RemoveObserver(this); + windows_.window2 = NULL; + } + + show_timer_.Stop(); + + if (!resize_widget_) + return; + + for (size_t i = 0; i < windows_.other_windows.size(); ++i) + windows_.other_windows[i]->aura_window()->RemoveObserver(this); + mouse_watcher_.reset(); + resize_widget_.reset(); + windows_ = ResizeWindows(); +} + +void MultiWindowResizeController::MouseMovedOutOfHost() { + Hide(); +} + +void MultiWindowResizeController::OnWindowDestroying(aura::Window* window) { + // Have to explicitly reset the WindowResizer, otherwise Hide() does nothing. + window_resizer_.reset(); + Hide(); +} + +MultiWindowResizeController::ResizeWindows +MultiWindowResizeController::DetermineWindowsFromScreenPoint( + WmWindow* window) const { + gfx::Point mouse_location( + display::Screen::GetScreen()->GetCursorScreenPoint()); + mouse_location = window->ConvertPointFromScreen(mouse_location); + const int component = window->GetNonClientComponent(mouse_location); + return DetermineWindows(window, component, mouse_location); +} + +void MultiWindowResizeController::CreateMouseWatcher() { + mouse_watcher_.reset( + new views::MouseWatcher(new ResizeMouseWatcherHost(this), this)); + mouse_watcher_->set_notify_on_exit_time( + base::TimeDelta::FromMilliseconds(kHideDelayMS)); + mouse_watcher_->Start(); +} + +MultiWindowResizeController::ResizeWindows +MultiWindowResizeController::DetermineWindows(WmWindow* window, + int window_component, + const gfx::Point& point) const { + ResizeWindows result; + gfx::Point point_in_parent = + window->ConvertPointToTarget(window->GetParent(), point); + switch (window_component) { + case HTRIGHT: + result.direction = LEFT_RIGHT; + result.window1 = window; + result.window2 = FindWindowByEdge( + window, HTLEFT, window->GetBounds().right(), point_in_parent.y()); + break; + case HTLEFT: + result.direction = LEFT_RIGHT; + result.window1 = FindWindowByEdge( + window, HTRIGHT, window->GetBounds().x(), point_in_parent.y()); + result.window2 = window; + break; + case HTTOP: + result.direction = TOP_BOTTOM; + result.window1 = FindWindowByEdge(window, HTBOTTOM, point_in_parent.x(), + window->GetBounds().y()); + result.window2 = window; + break; + case HTBOTTOM: + result.direction = TOP_BOTTOM; + result.window1 = window; + result.window2 = FindWindowByEdge(window, HTTOP, point_in_parent.x(), + window->GetBounds().bottom()); + break; + default: + break; + } + return result; +} + +WmWindow* MultiWindowResizeController::FindWindowByEdge( + WmWindow* window_to_ignore, + int edge_want, + int x_in_parent, + int y_in_parent) const { + WmWindow* parent = window_to_ignore->GetParent(); + std::vector<WmWindow*> windows = parent->GetChildren(); + for (auto i = windows.rbegin(); i != windows.rend(); ++i) { + WmWindow* window = *i; + if (window == window_to_ignore || !window->IsVisible()) + continue; + + // Ignore windows without a non-client area. + if (!window->HasNonClientArea()) + continue; + + gfx::Point p = parent->ConvertPointToTarget( + window, gfx::Point(x_in_parent, y_in_parent)); + switch (edge_want) { + case HTLEFT: + if (ContainsY(window, p.y()) && p.x() == 0) + return window; + break; + case HTRIGHT: + if (ContainsY(window, p.y()) && p.x() == window->GetBounds().width()) + return window; + break; + case HTTOP: + if (ContainsX(window, p.x()) && p.y() == 0) + return window; + break; + case HTBOTTOM: + if (ContainsX(window, p.x()) && p.y() == window->GetBounds().height()) + return window; + break; + default: + NOTREACHED(); + } + // Window doesn't contain the edge, but if window contains |point| + // it's obscuring any other window that could be at the location. + if (window->GetBounds().Contains(x_in_parent, y_in_parent)) + return NULL; + } + return NULL; +} + +WmWindow* MultiWindowResizeController::FindWindowTouching( + WmWindow* window, + Direction direction) const { + int right = window->GetBounds().right(); + int bottom = window->GetBounds().bottom(); + WmWindow* parent = window->GetParent(); + std::vector<WmWindow*> windows = parent->GetChildren(); + for (auto i = windows.rbegin(); i != windows.rend(); ++i) { + WmWindow* other = *i; + if (other == window || !other->IsVisible()) + continue; + switch (direction) { + case TOP_BOTTOM: + if (other->GetBounds().y() == bottom && + Intersects(other->GetBounds().x(), other->GetBounds().right(), + window->GetBounds().x(), window->GetBounds().right())) { + return other; + } + break; + case LEFT_RIGHT: + if (other->GetBounds().x() == right && + Intersects(other->GetBounds().y(), other->GetBounds().bottom(), + window->GetBounds().y(), window->GetBounds().bottom())) { + return other; + } + break; + default: + NOTREACHED(); + } + } + return NULL; +} + +void MultiWindowResizeController::FindWindowsTouching( + WmWindow* start, + Direction direction, + std::vector<WmWindow*>* others) const { + while (start) { + start = FindWindowTouching(start, direction); + if (start) + others->push_back(start); + } +} + +void MultiWindowResizeController::ShowIfValidMouseLocation() { + if (DetermineWindowsFromScreenPoint(windows_.window1).Equals(windows_) || + DetermineWindowsFromScreenPoint(windows_.window2).Equals(windows_)) { + ShowNow(); + } else { + Hide(); + } +} + +void MultiWindowResizeController::ShowNow() { + DCHECK(!resize_widget_.get()); + DCHECK(windows_.is_valid()); + show_timer_.Stop(); + resize_widget_.reset(new views::Widget); + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.name = "MultiWindowResizeController"; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + windows_.window1->GetRootWindowController() + ->ConfigureWidgetInitParamsForContainer( + resize_widget_.get(), kShellWindowId_AlwaysOnTopContainer, ¶ms); + ResizeView* view = new ResizeView(this, windows_.direction); + resize_widget_->set_focus_on_creation(false); + resize_widget_->Init(params); + WmWindow::Get(resize_widget_->GetNativeWindow()) + ->SetVisibilityAnimationType(::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); + resize_widget_->SetContentsView(view); + show_bounds_in_screen_ = windows_.window1->GetParent()->ConvertRectToScreen( + CalculateResizeWidgetBounds(show_location_in_parent_)); + resize_widget_->SetBounds(show_bounds_in_screen_); + resize_widget_->Show(); + CreateMouseWatcher(); +} + +bool MultiWindowResizeController::IsShowing() const { + return resize_widget_.get() || show_timer_.IsRunning(); +} + +void MultiWindowResizeController::StartResize( + const gfx::Point& location_in_screen) { + DCHECK(!window_resizer_.get()); + DCHECK(windows_.is_valid()); + gfx::Point location_in_parent = + windows_.window2->GetParent()->ConvertPointFromScreen(location_in_screen); + std::vector<WmWindow*> windows; + windows.push_back(windows_.window2); + DCHECK(windows_.other_windows.empty()); + FindWindowsTouching(windows_.window2, windows_.direction, + &windows_.other_windows); + for (size_t i = 0; i < windows_.other_windows.size(); ++i) { + windows_.other_windows[i]->aura_window()->AddObserver(this); + windows.push_back(windows_.other_windows[i]); + } + int component = windows_.direction == LEFT_RIGHT ? HTRIGHT : HTBOTTOM; + wm::WindowState* window_state = windows_.window1->GetWindowState(); + window_state->CreateDragDetails(location_in_parent, component, + aura::client::WINDOW_MOVE_SOURCE_MOUSE); + window_resizer_.reset(WorkspaceWindowResizer::Create(window_state, windows)); + + // Do not hide the resize widget while a drag is active. + mouse_watcher_.reset(); +} + +void MultiWindowResizeController::Resize(const gfx::Point& location_in_screen, + int event_flags) { + gfx::Point location_in_parent = + windows_.window1->GetParent()->ConvertPointFromScreen(location_in_screen); + window_resizer_->Drag(location_in_parent, event_flags); + gfx::Rect bounds = windows_.window1->GetParent()->ConvertRectToScreen( + CalculateResizeWidgetBounds(location_in_parent)); + + if (windows_.direction == LEFT_RIGHT) + bounds.set_y(show_bounds_in_screen_.y()); + else + bounds.set_x(show_bounds_in_screen_.x()); + resize_widget_->SetBounds(bounds); +} + +void MultiWindowResizeController::CompleteResize() { + window_resizer_->CompleteDrag(); + window_resizer_->GetTarget()->GetWindowState()->DeleteDragDetails(); + window_resizer_.reset(); + + // Mouse may still be over resizer, if not hide. + gfx::Point screen_loc = display::Screen::GetScreen()->GetCursorScreenPoint(); + if (!resize_widget_->GetWindowBoundsInScreen().Contains(screen_loc)) { + Hide(); + } else { + // If the mouse is over the resizer we need to remove observers on any of + // the |other_windows|. If we start another resize we'll recalculate the + // |other_windows| and invoke AddObserver() as necessary. + for (size_t i = 0; i < windows_.other_windows.size(); ++i) + windows_.other_windows[i]->aura_window()->RemoveObserver(this); + windows_.other_windows.clear(); + + CreateMouseWatcher(); + } +} + +void MultiWindowResizeController::CancelResize() { + if (!window_resizer_) + return; // Happens if window was destroyed and we nuked the WindowResizer. + window_resizer_->RevertDrag(); + window_resizer_->GetTarget()->GetWindowState()->DeleteDragDetails(); + window_resizer_.reset(); + Hide(); +} + +gfx::Rect MultiWindowResizeController::CalculateResizeWidgetBounds( + const gfx::Point& location_in_parent) const { + gfx::Size pref = resize_widget_->GetContentsView()->GetPreferredSize(); + int x = 0, y = 0; + if (windows_.direction == LEFT_RIGHT) { + x = windows_.window1->GetBounds().right() - pref.width() / 2; + y = location_in_parent.y() + kResizeWidgetPadding; + if (y + pref.height() / 2 > windows_.window1->GetBounds().bottom() && + y + pref.height() / 2 > windows_.window2->GetBounds().bottom()) { + y = location_in_parent.y() - kResizeWidgetPadding - pref.height(); + } + } else { + x = location_in_parent.x() + kResizeWidgetPadding; + if (x + pref.height() / 2 > windows_.window1->GetBounds().right() && + x + pref.height() / 2 > windows_.window2->GetBounds().right()) { + x = location_in_parent.x() - kResizeWidgetPadding - pref.width(); + } + y = windows_.window1->GetBounds().bottom() - pref.height() / 2; + } + return gfx::Rect(x, y, pref.width(), pref.height()); +} + +bool MultiWindowResizeController::IsOverResizeWidget( + const gfx::Point& location_in_screen) const { + return resize_widget_->GetWindowBoundsInScreen().Contains(location_in_screen); +} + +bool MultiWindowResizeController::IsOverWindows( + const gfx::Point& location_in_screen) const { + if (IsOverResizeWidget(location_in_screen)) + return true; + + if (windows_.direction == TOP_BOTTOM) { + if (!ContainsScreenX(windows_.window1, location_in_screen.x()) || + !ContainsScreenX(windows_.window2, location_in_screen.x())) { + return false; + } + } else { + if (!ContainsScreenY(windows_.window1, location_in_screen.y()) || + !ContainsScreenY(windows_.window2, location_in_screen.y())) { + return false; + } + } + + // Check whether |location_in_screen| is in the event target's resize region. + // This is tricky because a window's resize region can extend outside a + // window's bounds. + WmWindow* target = + windows_.window1->GetRootWindowController()->FindEventTarget( + location_in_screen); + if (target == windows_.window1) { + return IsOverComponent( + windows_.window1, location_in_screen, + windows_.direction == TOP_BOTTOM ? HTBOTTOM : HTRIGHT); + } + if (target == windows_.window2) { + return IsOverComponent(windows_.window2, location_in_screen, + windows_.direction == TOP_BOTTOM ? HTTOP : HTLEFT); + } + return false; +} + +bool MultiWindowResizeController::IsOverComponent( + WmWindow* window, + const gfx::Point& location_in_screen, + int component) const { + gfx::Point window_loc = window->ConvertPointFromScreen(location_in_screen); + return window->GetNonClientComponent(window_loc) == component; +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/multi_window_resize_controller.h b/ash/common/wm/workspace/multi_window_resize_controller.h new file mode 100644 index 0000000..48bd35a6 --- /dev/null +++ b/ash/common/wm/workspace/multi_window_resize_controller.h
@@ -0,0 +1,180 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_ +#define ASH_COMMON_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_ + +#include <memory> +#include <vector> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/timer/timer.h" +#include "ui/aura/window_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/views/mouse_watcher.h" + +namespace views { +class Widget; +} + +namespace ash { +class MultiWindowResizeControllerTest; +class WmWindow; +class WorkspaceWindowResizer; + +// Two directions resizes happen in. +enum Direction { + TOP_BOTTOM, + LEFT_RIGHT, +}; + +// MultiWindowResizeController is responsible for determining and showing a +// widget that allows resizing multiple windows at the same time. +// MultiWindowResizeController is driven by WorkspaceEventFilter. +class ASH_EXPORT MultiWindowResizeController + : public views::MouseWatcherListener, + public aura::WindowObserver { + public: + MultiWindowResizeController(); + ~MultiWindowResizeController() override; + + // If necessary, shows the resize widget. |window| is the window the mouse + // is over, |component| the edge and |point| the location of the mouse. + void Show(WmWindow* window, int component, const gfx::Point& point); + + // Hides the resize widget. + void Hide(); + + // MouseWatcherListenre overrides: + void MouseMovedOutOfHost() override; + + // WindowObserver overrides: + void OnWindowDestroying(aura::Window* window) override; + + private: + friend class MultiWindowResizeControllerTest; + + // Used to track the two resizable windows and direction. + struct ResizeWindows { + ResizeWindows(); + ResizeWindows(const ResizeWindows& other); + ~ResizeWindows(); + + // Returns true if |other| equals this ResizeWindows. This does *not* + // consider the windows in |other_windows|. + bool Equals(const ResizeWindows& other) const; + + // Returns true if this ResizeWindows is valid. + bool is_valid() const { return window1 && window2; } + + // The left/top window to resize. + WmWindow* window1; + + // Other window to resize. + WmWindow* window2; + + // Direction + Direction direction; + + // Windows after |window2| that are to be resized. Determined at the time + // the resize starts. + std::vector<WmWindow*> other_windows; + }; + + class ResizeMouseWatcherHost; + class ResizeView; + + void CreateMouseWatcher(); + + // Returns a ResizeWindows based on the specified arguments. Use is_valid() + // to test if the return value is a valid multi window resize location. + ResizeWindows DetermineWindows(WmWindow* window, + int window_component, + const gfx::Point& point) const; + + // Variant of DetermineWindows() that uses the current location of the mouse + // to determine the resize windows. + ResizeWindows DetermineWindowsFromScreenPoint(WmWindow* window) const; + + // Finds a window by edge (one of the constants HitTestCompat. + WmWindow* FindWindowByEdge(WmWindow* window_to_ignore, + int edge_want, + int x_in_parent, + int y_in_parent) const; + + // Returns the first window touching |window|. + WmWindow* FindWindowTouching(WmWindow* window, Direction direction) const; + + // Places any windows touching |start| into |others|. + void FindWindowsTouching(WmWindow* start, + Direction direction, + std::vector<WmWindow*>* others) const; + + // Shows the resizer if the mouse is still at a valid location. This is called + // from the |show_timer_|. + void ShowIfValidMouseLocation(); + + // Shows the widget immediately. + void ShowNow(); + + // Returns true if the widget is showing. + bool IsShowing() const; + + // Initiates a resize. + void StartResize(const gfx::Point& location_in_screen); + + // Resizes to the new location. + void Resize(const gfx::Point& location_in_screen, int event_flags); + + // Completes the resize. + void CompleteResize(); + + // Cancels the resize. + void CancelResize(); + + // Returns the bounds for the resize widget. + gfx::Rect CalculateResizeWidgetBounds( + const gfx::Point& location_in_parent) const; + + // Returns true if |location_in_screen| is over the resize widget. + bool IsOverResizeWidget(const gfx::Point& location_in_screen) const; + + // Returns true if |location_in_screen| is over the resize windows + // (or the resize widget itself). + bool IsOverWindows(const gfx::Point& location_in_screen) const; + + // Returns true if |location_in_screen| is over |component| in |window|. + bool IsOverComponent(WmWindow* window, + const gfx::Point& location_in_screen, + int component) const; + + // Windows and direction to resize. + ResizeWindows windows_; + + // Timer used before showing. + base::OneShotTimer show_timer_; + + std::unique_ptr<views::Widget> resize_widget_; + + // If non-null we're in a resize loop. + std::unique_ptr<WorkspaceWindowResizer> window_resizer_; + + // Mouse coordinate passed to Show() in container's coodinates. + gfx::Point show_location_in_parent_; + + // Bounds the widget was last shown at in screen coordinates. + gfx::Rect show_bounds_in_screen_; + + // Used to detect whether the mouse is over the windows. While + // |resize_widget_| is non-NULL (ie the widget is showing) we ignore calls + // to Show(). + std::unique_ptr<views::MouseWatcher> mouse_watcher_; + + DISALLOW_COPY_AND_ASSIGN(MultiWindowResizeController); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_
diff --git a/ash/common/wm/workspace/phantom_window_controller.cc b/ash/common/wm/workspace/phantom_window_controller.cc new file mode 100644 index 0000000..af75b3c --- /dev/null +++ b/ash/common/wm/workspace/phantom_window_controller.cc
@@ -0,0 +1,151 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/phantom_window_controller.h" + +#include <math.h> + +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/root_window_controller.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/views/background.h" +#include "ui/views/painter.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +// The duration of the show animation. +const int kAnimationDurationMs = 200; + +// The size of the phantom window at the beginning of the show animation in +// relation to the size of the phantom window at the end of the animation. +const float kStartBoundsRatio = 0.85f; + +// The amount of pixels that the phantom window's shadow should extend past +// the bounds passed into Show(). +const int kShadowThickness = 15; + +// The minimum size of a phantom window including the shadow. The minimum size +// is derived from the size of the IDR_AURA_PHANTOM_WINDOW image assets. +const int kMinSizeWithShadow = 100; + +// Adjusts the phantom window's bounds so that the bounds: +// - Include the size of the shadow. +// - Have a size equal to or larger than the minimum phantom window size. +gfx::Rect GetAdjustedBounds(const gfx::Rect& bounds) { + int x_inset = std::max( + static_cast<int>(ceil((kMinSizeWithShadow - bounds.width()) / 2.0f)), + kShadowThickness); + int y_inset = std::max( + static_cast<int>(ceil((kMinSizeWithShadow - bounds.height()) / 2.0f)), + kShadowThickness); + + gfx::Rect adjusted_bounds(bounds); + adjusted_bounds.Inset(-x_inset, -y_inset); + return adjusted_bounds; +} + +// Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget| +// is NULL. +void AnimateToBounds(views::Widget* widget, + const gfx::Rect& new_bounds_in_screen) { + if (!widget) + return; + + ui::ScopedLayerAnimationSettings scoped_setter( + WmWindow::Get(widget->GetNativeWindow())->GetLayer()->GetAnimator()); + scoped_setter.SetTweenType(gfx::Tween::EASE_IN); + scoped_setter.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + scoped_setter.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); + widget->SetBounds(new_bounds_in_screen); +} + +} // namespace + +// PhantomWindowController ---------------------------------------------------- + +PhantomWindowController::PhantomWindowController(WmWindow* window) + : window_(window) {} + +PhantomWindowController::~PhantomWindowController() {} + +void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { + gfx::Rect adjusted_bounds_in_screen = GetAdjustedBounds(bounds_in_screen); + if (adjusted_bounds_in_screen == target_bounds_in_screen_) + return; + target_bounds_in_screen_ = adjusted_bounds_in_screen; + + gfx::Rect start_bounds_in_screen = target_bounds_in_screen_; + int start_width = std::max( + kMinSizeWithShadow, + static_cast<int>(start_bounds_in_screen.width() * kStartBoundsRatio)); + int start_height = std::max( + kMinSizeWithShadow, + static_cast<int>(start_bounds_in_screen.height() * kStartBoundsRatio)); + start_bounds_in_screen.Inset( + floor((start_bounds_in_screen.width() - start_width) / 2.0f), + floor((start_bounds_in_screen.height() - start_height) / 2.0f)); + phantom_widget_ = + CreatePhantomWidget(wm::GetRootWindowMatching(target_bounds_in_screen_), + start_bounds_in_screen); + + AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_); +} + +std::unique_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget( + WmWindow* root_window, + const gfx::Rect& bounds_in_screen) { + std::unique_ptr<views::Widget> phantom_widget(new views::Widget); + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + // PhantomWindowController is used by FrameMaximizeButton to highlight the + // launcher button. Put the phantom in the same window as the launcher so that + // the phantom is visible. + params.keep_on_top = true; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.name = "PhantomWindow"; + root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( + phantom_widget.get(), kShellWindowId_ShelfContainer, ¶ms); + phantom_widget->set_focus_on_creation(false); + phantom_widget->Init(params); + phantom_widget->SetVisibilityChangedAnimationsEnabled(false); + WmWindow* phantom_widget_window = + WmWindow::Get(phantom_widget->GetNativeWindow()); + phantom_widget_window->SetShellWindowId(kShellWindowId_PhantomWindow); + phantom_widget->SetBounds(bounds_in_screen); + // TODO(sky): I suspect this is never true, verify that. + if (phantom_widget_window->GetParent() == window_->GetParent()) { + phantom_widget_window->GetParent()->StackChildAbove(phantom_widget_window, + window_); + } + + const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW); + views::View* content_view = new views::View; + content_view->set_background(views::Background::CreateBackgroundPainter( + views::Painter::CreateImageGridPainter(kImages))); + phantom_widget->SetContentsView(content_view); + + // Show the widget after all the setups. + phantom_widget->Show(); + + // Fade the window in. + ui::Layer* widget_layer = phantom_widget_window->GetLayer(); + widget_layer->SetOpacity(0); + ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); + scoped_setter.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); + widget_layer->SetOpacity(1); + + return phantom_widget; +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/phantom_window_controller.h b/ash/common/wm/workspace/phantom_window_controller.h new file mode 100644 index 0000000..6ac7da2 --- /dev/null +++ b/ash/common/wm/workspace/phantom_window_controller.h
@@ -0,0 +1,57 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_PHANTOM_WINDOW_CONTROLLER_H_ +#define ASH_COMMON_WM_WORKSPACE_PHANTOM_WINDOW_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "ui/gfx/geometry/rect.h" + +namespace views { +class Widget; +} + +namespace ash { + +class WmWindow; + +// PhantomWindowController is responsible for showing a phantom representation +// of a window. It's used to show a preview of how snapping or docking a window +// will affect the window's bounds. +class ASH_EXPORT PhantomWindowController { + public: + explicit PhantomWindowController(WmWindow* window); + + // Hides the phantom window without any animation. + ~PhantomWindowController(); + + // Shows the phantom window and animates shrinking it to |bounds_in_screen|. + void Show(const gfx::Rect& bounds_in_screen); + + private: + // Creates, shows and returns a phantom widget at |bounds| + // with kShellWindowId_ShelfContainer in |root_window| as a parent. + std::unique_ptr<views::Widget> CreatePhantomWidget( + WmWindow* root_window, + const gfx::Rect& bounds_in_screen); + + // Window that the phantom window is stacked above. + WmWindow* window_; + + // Target bounds (including the shadows if any) of the animation in screen + // coordinates. + gfx::Rect target_bounds_in_screen_; + + // Phantom representation of the window. + std::unique_ptr<views::Widget> phantom_widget_; + + DISALLOW_COPY_AND_ASSIGN(PhantomWindowController); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_PHANTOM_WINDOW_CONTROLLER_H_
diff --git a/ash/common/wm/workspace/two_step_edge_cycler.cc b/ash/common/wm/workspace/two_step_edge_cycler.cc new file mode 100644 index 0000000..9e87de9 --- /dev/null +++ b/ash/common/wm/workspace/two_step_edge_cycler.cc
@@ -0,0 +1,63 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/two_step_edge_cycler.h" + +#include <cstdlib> + +namespace ash { +namespace { + +// We cycle to the second mode if any of the following happens while the mouse +// is on the edge of the workspace: +// . The user stops moving the mouse for |kMaxDelay| and then moves the mouse +// again in the preferred direction from the last paused location for at least +// |kMaxPixelsAfterPause| horizontal pixels. +// . The mouse moves |kMaxPixels| horizontal pixels in the preferred direction. +// . The mouse is moved |kMaxMoves| times since the last pause. +const int kMaxDelay = 400; +const int kMaxPixels = 100; +const int kMaxPixelsAfterPause = 10; +const int kMaxMoves = 25; + +} // namespace + +TwoStepEdgeCycler::TwoStepEdgeCycler(const gfx::Point& start, + TwoStepEdgeCycler::Direction direction) + : second_mode_(false), + time_last_move_(base::TimeTicks::Now()), + num_moves_(0), + start_x_(start.x()), + paused_x_(start.x()), + paused_(false), + direction_(direction) {} + +TwoStepEdgeCycler::~TwoStepEdgeCycler() {} + +void TwoStepEdgeCycler::OnMove(const gfx::Point& location) { + if (second_mode_) + return; + + if ((base::TimeTicks::Now() - time_last_move_).InMilliseconds() > kMaxDelay) { + paused_ = true; + paused_x_ = location.x(); + num_moves_ = 0; + } + time_last_move_ = base::TimeTicks::Now(); + + int compare_x = paused_ ? paused_x_ : start_x_; + if (location.x() != compare_x && + (location.x() < compare_x) != (direction_ == DIRECTION_LEFT)) { + return; + } + + ++num_moves_; + bool moved_in_the_same_direction_after_pause = + paused_ && std::abs(location.x() - paused_x_) >= kMaxPixelsAfterPause; + second_mode_ = moved_in_the_same_direction_after_pause || + std::abs(location.x() - start_x_) >= kMaxPixels || + num_moves_ >= kMaxMoves; +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/two_step_edge_cycler.h b/ash/common/wm/workspace/two_step_edge_cycler.h new file mode 100644 index 0000000..64743eb1 --- /dev/null +++ b/ash/common/wm/workspace/two_step_edge_cycler.h
@@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_TWO_STEP_EDGE_CYCLER_H_ +#define ASH_COMMON_WM_WORKSPACE_TWO_STEP_EDGE_CYCLER_H_ + +#include "ash/ash_export.h" +#include "base/macros.h" +#include "base/time/time.h" +#include "ui/gfx/geometry/point.h" + +namespace ash { + +// TwoStepEdgeCycler is responsible for cycling between two modes when the mouse +// is at the edge of the workspace. The cycler does not loop so it is impossible +// to get back to the first mode once the second mode is reached. +// TwoStepEdgeCycler should be destroyed once the mouse moves off the edge of +// the workspace. +class ASH_EXPORT TwoStepEdgeCycler { + public: + // The direction in which a mouse should travel to switch mode. + enum Direction { DIRECTION_LEFT, DIRECTION_RIGHT }; + + explicit TwoStepEdgeCycler(const gfx::Point& start, Direction direction); + ~TwoStepEdgeCycler(); + + // Update which mode should be used as a result of a mouse / touch move. + // |location| is the location of the event. + void OnMove(const gfx::Point& location); + + bool use_second_mode() const { return second_mode_; } + + private: + // Whether the second mode should be used. + bool second_mode_; + + // Time OnMove() was last invoked. + base::TimeTicks time_last_move_; + + // The number of moves since the cycler was constructed. + int num_moves_; + + // Initial x-coordinate. + int start_x_; + + // x-coordinate when paused. + int paused_x_; + + // Whether the movement was paused. + bool paused_; + + // Determines a preferred movement direction that we are watching. + Direction direction_; + + DISALLOW_COPY_AND_ASSIGN(TwoStepEdgeCycler); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_TWO_STEP_EDGE_CYCLER_H_
diff --git a/ash/common/wm/workspace/workspace_event_handler.cc b/ash/common/wm/workspace/workspace_event_handler.cc new file mode 100644 index 0000000..0e26b16 --- /dev/null +++ b/ash/common/wm/workspace/workspace_event_handler.cc
@@ -0,0 +1,119 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/workspace_event_handler.h" + +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ui/base/hit_test.h" +#include "ui/events/event.h" + +namespace ash { + +WorkspaceEventHandler::WorkspaceEventHandler() : click_component_(HTNOWHERE) {} + +WorkspaceEventHandler::~WorkspaceEventHandler() {} + +void WorkspaceEventHandler::OnMouseEvent(ui::MouseEvent* event, + WmWindow* target) { + if (event->type() == ui::ET_MOUSE_PRESSED && event->IsOnlyLeftMouseButton() && + ((event->flags() & (ui::EF_IS_DOUBLE_CLICK | ui::EF_IS_TRIPLE_CLICK)) == + 0)) { + click_component_ = target->GetNonClientComponent(event->location()); + } + + if (event->handled()) + return; + + switch (event->type()) { + case ui::ET_MOUSE_MOVED: { + int component = target->GetNonClientComponent(event->location()); + multi_window_resize_controller_.Show(target, component, + event->location()); + break; + } + case ui::ET_MOUSE_ENTERED: + break; + case ui::ET_MOUSE_CAPTURE_CHANGED: + case ui::ET_MOUSE_EXITED: + break; + case ui::ET_MOUSE_PRESSED: { + wm::WindowState* target_state = target->GetWindowState(); + + if (event->IsOnlyLeftMouseButton()) { + if (event->flags() & ui::EF_IS_DOUBLE_CLICK) { + int component = target->GetNonClientComponent(event->location()); + if (component == HTCAPTION && component == click_component_) { + WmShell::Get()->RecordUserMetricsAction( + UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK); + const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION); + target_state->OnWMEvent(&wm_event); + event->StopPropagation(); + } + click_component_ = HTNOWHERE; + } + } else { + click_component_ = HTNOWHERE; + } + + HandleVerticalResizeDoubleClick(target_state, event); + break; + } + default: + break; + } +} + +void WorkspaceEventHandler::OnGestureEvent(ui::GestureEvent* event, + WmWindow* target) { + if (event->handled() || event->type() != ui::ET_GESTURE_TAP) + return; + + int previous_target_component = click_component_; + click_component_ = target->GetNonClientComponent(event->location()); + + if (click_component_ != HTCAPTION) + return; + + if (event->details().tap_count() != 2) { + WmShell::Get()->RecordGestureAction(GESTURE_FRAMEVIEW_TAP); + return; + } + + if (click_component_ == previous_target_component) { + WmShell::Get()->RecordUserMetricsAction( + UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE); + WmShell::Get()->RecordGestureAction(GESTURE_MAXIMIZE_DOUBLETAP); + const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION); + target->GetWindowState()->OnWMEvent(&wm_event); + event->StopPropagation(); + } + click_component_ = HTNOWHERE; +} + +void WorkspaceEventHandler::HandleVerticalResizeDoubleClick( + wm::WindowState* target_state, + ui::MouseEvent* event) { + WmWindow* target = target_state->window(); + if (event->flags() & ui::EF_IS_DOUBLE_CLICK) { + int component = target->GetNonClientComponent(event->location()); + if (component == HTBOTTOM || component == HTTOP) { + WmShell::Get()->RecordUserMetricsAction( + UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK); + const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE); + target_state->OnWMEvent(&wm_event); + event->StopPropagation(); + } else if (component == HTLEFT || component == HTRIGHT) { + WmShell::Get()->RecordUserMetricsAction( + UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK); + const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE); + target_state->OnWMEvent(&wm_event); + event->StopPropagation(); + } + } +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/workspace_event_handler.h b/ash/common/wm/workspace/workspace_event_handler.h new file mode 100644 index 0000000..eca5650 --- /dev/null +++ b/ash/common/wm/workspace/workspace_event_handler.h
@@ -0,0 +1,61 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_H_ +#define ASH_COMMON_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm/workspace/multi_window_resize_controller.h" +#include "base/macros.h" + +namespace ui { +class GestureEvent; +class MouseEvent; +} + +namespace ash { +class WmWindow; +class WorkspaceEventHandlerTestHelper; + +namespace wm { +class WindowState; +} + +// ui::EventHandler like class installed on the window associated with +// WorkspaceLayoutManager. This handles various events happening on child +// windows and takes appropriate action. It is expected the environment specific +// file calls OnMouseEvent()/OnGestureEvent() as appropriate. +class ASH_EXPORT WorkspaceEventHandler { + public: + WorkspaceEventHandler(); + virtual ~WorkspaceEventHandler(); + + void OnMouseEvent(ui::MouseEvent* event, WmWindow* target); + void OnGestureEvent(ui::GestureEvent* event, WmWindow* target); + + private: + friend class WorkspaceEventHandlerTestHelper; + + // Determines if |event| corresponds to a double click on either the top or + // bottom vertical resize edge, and if so toggles the vertical height of the + // window between its restored state and the full available height of the + // workspace. + void HandleVerticalResizeDoubleClick(wm::WindowState* window_state, + ui::MouseEvent* event); + + MultiWindowResizeController multi_window_resize_controller_; + + // The non-client component for the target of a MouseEvent or GestureEvent. + // Events can be destructive to the window tree, which can cause the + // component of a ui::EF_IS_DOUBLE_CLICK event to no longer be the same as + // that of the initial click. Acting on a double click should only occur for + // matching components. This will be set for left clicks, and tap events. + int click_component_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceEventHandler); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_H_
diff --git a/ash/common/wm/workspace/workspace_layout_manager.cc b/ash/common/wm/workspace/workspace_layout_manager.cc new file mode 100644 index 0000000..055ff85 --- /dev/null +++ b/ash/common/wm/workspace/workspace_layout_manager.cc
@@ -0,0 +1,387 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/workspace_layout_manager.h" + +#include <algorithm> + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/always_on_top_controller.h" +#include "ash/common/wm/fullscreen_window_finder.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_properties.h" +#include "ash/wm/window_state_aura.h" +#include "base/command_line.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/base/ui_base_switches.h" +#include "ui/compositor/layer.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/keyboard/keyboard_controller.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace ash { + +WorkspaceLayoutManager::WorkspaceLayoutManager(WmWindow* window) + : window_(window), + root_window_(window->GetRootWindow()), + root_window_controller_(root_window_->GetRootWindowController()), + shell_(window_->GetShell()), + work_area_in_parent_(wm::GetDisplayWorkAreaBoundsInParent(window_)), + is_fullscreen_(wm::GetWindowForFullscreenMode(window) != nullptr) { + shell_->AddShellObserver(this); + shell_->AddActivationObserver(this); + root_window_->aura_window()->AddObserver(this); + display::Screen::GetScreen()->AddObserver(this); + DCHECK(window->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)); +} + +WorkspaceLayoutManager::~WorkspaceLayoutManager() { + if (root_window_) + root_window_->aura_window()->RemoveObserver(this); + for (WmWindow* window : windows_) { + wm::WindowState* window_state = window->GetWindowState(); + window_state->RemoveObserver(this); + window->aura_window()->RemoveObserver(this); + } + display::Screen::GetScreen()->RemoveObserver(this); + shell_->RemoveActivationObserver(this); + shell_->RemoveShellObserver(this); +} + +void WorkspaceLayoutManager::SetMaximizeBackdropDelegate( + std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate) { + backdrop_delegate_ = std::move(delegate); +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, aura::LayoutManager implementation: + +void WorkspaceLayoutManager::OnWindowResized() {} + +void WorkspaceLayoutManager::OnWindowAddedToLayout(WmWindow* child) { + wm::WindowState* window_state = child->GetWindowState(); + wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); + window_state->OnWMEvent(&event); + windows_.insert(child); + child->aura_window()->AddObserver(this); + window_state->AddObserver(this); + UpdateShelfVisibility(); + UpdateFullscreenState(); + if (backdrop_delegate_) + backdrop_delegate_->OnWindowAddedToLayout(child); + WindowPositioner::RearrangeVisibleWindowOnShow(child); + if (WmShell::Get()->IsPinned()) + child->GetWindowState()->DisableAlwaysOnTop(nullptr); +} + +void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) { + windows_.erase(child); + child->aura_window()->RemoveObserver(this); + child->GetWindowState()->RemoveObserver(this); + + if (child->GetTargetVisibility()) + WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); +} + +void WorkspaceLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) { + UpdateShelfVisibility(); + UpdateFullscreenState(); + if (backdrop_delegate_) + backdrop_delegate_->OnWindowRemovedFromLayout(child); +} + +void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) { + wm::WindowState* window_state = child->GetWindowState(); + // Attempting to show a minimized window. Unminimize it. + if (visible && window_state->IsMinimized()) + window_state->Unminimize(); + + if (child->GetTargetVisibility()) + WindowPositioner::RearrangeVisibleWindowOnShow(child); + else + WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); + UpdateFullscreenState(); + UpdateShelfVisibility(); + if (backdrop_delegate_) + backdrop_delegate_->OnChildWindowVisibilityChanged(child, visible); +} + +void WorkspaceLayoutManager::SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) { + wm::SetBoundsEvent event(wm::WM_EVENT_SET_BOUNDS, requested_bounds); + child->GetWindowState()->OnWMEvent(&event); + UpdateShelfVisibility(); +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, keyboard::KeyboardControllerObserver implementation: + +void WorkspaceLayoutManager::OnKeyboardBoundsChanging( + const gfx::Rect& new_bounds) { + // If new window behavior flag enabled and in non-sticky mode, do not change + // the work area. + bool change_work_area = + (!base::CommandLine::ForCurrentProcess()->HasSwitch( + ::switches::kUseNewVirtualKeyboardBehavior) || + keyboard::KeyboardController::GetInstance()->keyboard_locked()); + if (!change_work_area) + return; + + WmWindow* window = shell_->GetActiveWindow(); + if (!window) + return; + + window = window->GetToplevelWindow(); + if (!window_->Contains(window)) + return; + + wm::WindowState* window_state = window->GetWindowState(); + if (window_state->ignore_keyboard_bounds_change()) + return; + + if (!new_bounds.IsEmpty()) { + // Store existing bounds to be restored before resizing for keyboard if it + // is not already stored. + if (!window_state->HasRestoreBounds()) + window_state->SaveCurrentBoundsForRestore(); + + gfx::Rect window_bounds = + window_->ConvertRectToScreen(window->GetTargetBounds()); + int vertical_displacement = + std::max(0, window_bounds.bottom() - new_bounds.y()); + int shift = std::min(vertical_displacement, + window_bounds.y() - work_area_in_parent_.y()); + if (shift > 0) { + gfx::Point origin(window_bounds.x(), window_bounds.y() - shift); + SetChildBounds(window, gfx::Rect(origin, window_bounds.size())); + } + } else if (window_state->HasRestoreBounds()) { + // Keyboard hidden, restore original bounds if they exist. If the user has + // resized or dragged the window in the meantime, WorkspaceWindowResizer + // will have cleared the restore bounds and this code will not accidentally + // override user intent. + window_state->SetAndClearRestoreBounds(); + } +} + +void WorkspaceLayoutManager::OnKeyboardClosed() {} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, aura::WindowObserver implementation: + +void WorkspaceLayoutManager::OnWindowHierarchyChanged( + const HierarchyChangeParams& params) { + if (!wm::GetWindowState(params.target)->IsActive()) + return; + // If the window is already tracked by the workspace this update would be + // redundant as the fullscreen and shelf state would have been handled in + // OnWindowAddedToLayout. + if (windows_.find(WmWindow::Get(params.target)) != windows_.end()) + return; + + // If the active window has moved to this root window then update the + // fullscreen state. + // TODO(flackr): Track the active window leaving this root window and update + // the fullscreen state accordingly. + if (params.new_parent && + WmWindow::Get(params.new_parent->GetRootWindow()) == root_window_) { + UpdateFullscreenState(); + UpdateShelfVisibility(); + } +} + +void WorkspaceLayoutManager::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + if (key == aura::client::kAlwaysOnTopKey && + window->GetProperty(aura::client::kAlwaysOnTopKey)) { + WmWindow* container = + root_window_controller_->always_on_top_controller()->GetContainer( + WmWindow::Get(window)); + if (WmWindow::Get(window->parent()) != container) + container->AddChild(WmWindow::Get(window)); + } +} + +void WorkspaceLayoutManager::OnWindowStackingChanged(aura::Window* window) { + UpdateShelfVisibility(); + UpdateFullscreenState(); + if (backdrop_delegate_) + backdrop_delegate_->OnWindowStackingChanged(WmWindow::Get(window)); +} + +void WorkspaceLayoutManager::OnWindowDestroying(aura::Window* window) { + if (root_window_ == WmWindow::Get(window)) { + root_window_->aura_window()->RemoveObserver(this); + root_window_ = nullptr; + } +} + +void WorkspaceLayoutManager::OnWindowBoundsChanged( + aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + if (root_window_ == WmWindow::Get(window)) { + const wm::WMEvent wm_event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); + AdjustAllWindowsBoundsForWorkAreaChange(&wm_event); + } +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, +// aura::client::ActivationChangeObserver implementation: + +void WorkspaceLayoutManager::OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) { + wm::WindowState* window_state = + gained_active ? gained_active->GetWindowState() : nullptr; + if (window_state && window_state->IsMinimized() && + !gained_active->IsVisible()) { + window_state->Unminimize(); + DCHECK(!window_state->IsMinimized()); + } + UpdateFullscreenState(); + UpdateShelfVisibility(); +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, wm::WindowStateObserver implementation: + +void WorkspaceLayoutManager::OnPostWindowStateTypeChange( + wm::WindowState* window_state, + wm::WindowStateType old_type) { + // Notify observers that fullscreen state may be changing. + if (window_state->IsFullscreen() || + old_type == wm::WINDOW_STATE_TYPE_FULLSCREEN) { + UpdateFullscreenState(); + } + + UpdateShelfVisibility(); + if (backdrop_delegate_) + backdrop_delegate_->OnPostWindowStateTypeChange(window_state, old_type); +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, display::DisplayObserver implementation: + +void WorkspaceLayoutManager::OnDisplayMetricsChanged( + const display::Display& display, + uint32_t changed_metrics) { + if (window_->GetDisplayNearestWindow().id() != display.id()) + return; + + const gfx::Rect work_area(wm::GetDisplayWorkAreaBoundsInParent(window_)); + if (work_area != work_area_in_parent_) { + const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); + AdjustAllWindowsBoundsForWorkAreaChange(&event); + } + if (backdrop_delegate_) + backdrop_delegate_->OnDisplayWorkAreaInsetsChanged(); +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, ShellObserver implementation: + +void WorkspaceLayoutManager::OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) { + if (root_window != root_window_ || is_fullscreen_ == is_fullscreen) + return; + + is_fullscreen_ = is_fullscreen; + if (WmShell::Get()->IsPinned()) { + // If this is in pinned mode, then this event does not trigger the + // always-on-top state change, because it is kept disabled regardless of + // the fullscreen state change. + return; + } + + UpdateAlwaysOnTop(is_fullscreen_ ? wm::GetWindowForFullscreenMode(window_) + : nullptr); +} + +void WorkspaceLayoutManager::OnPinnedStateChanged(WmWindow* pinned_window) { + if (!WmShell::Get()->IsPinned() && is_fullscreen_) { + // On exiting from pinned mode, if the workspace is still in fullscreen + // mode, then this event does not trigger the restoring yet. On exiting + // from fullscreen, the temporarily disabled always-on-top property will be + // restored. + return; + } + + UpdateAlwaysOnTop(WmShell::Get()->IsPinned() ? pinned_window : nullptr); +} + +////////////////////////////////////////////////////////////////////////////// +// WorkspaceLayoutManager, private: + +void WorkspaceLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange( + const wm::WMEvent* event) { + DCHECK(event->type() == wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED || + event->type() == wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); + + work_area_in_parent_ = wm::GetDisplayWorkAreaBoundsInParent(window_); + + // Don't do any adjustments of the insets while we are in screen locked mode. + // This would happen if the launcher was auto hidden before the login screen + // was shown and then gets shown when the login screen gets presented. + if (event->type() == wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED && + shell_->GetSessionStateDelegate()->IsScreenLocked()) + return; + + // If a user plugs an external display into a laptop running Aura the + // display size will change. Maximized windows need to resize to match. + // We also do this when developers running Aura on a desktop manually resize + // the host window. + // We also need to do this when the work area insets changes. + for (WmWindow* window : windows_) + window->GetWindowState()->OnWMEvent(event); +} + +void WorkspaceLayoutManager::UpdateShelfVisibility() { + if (root_window_controller_->HasShelf()) + root_window_controller_->GetShelf()->UpdateVisibilityState(); +} + +void WorkspaceLayoutManager::UpdateFullscreenState() { + // TODO(flackr): The fullscreen state is currently tracked per workspace + // but the shell notification implies a per root window state. Currently + // only windows in the default workspace container will go fullscreen but + // this should really be tracked by the RootWindowController since + // technically any container could get a fullscreen window. + if (window_->GetShellWindowId() != kShellWindowId_DefaultContainer) + return; + bool is_fullscreen = wm::GetWindowForFullscreenMode(window_) != nullptr; + if (is_fullscreen != is_fullscreen_) { + WmShell::Get()->NotifyFullscreenStateChanged(is_fullscreen, root_window_); + is_fullscreen_ = is_fullscreen; + } +} + +void WorkspaceLayoutManager::UpdateAlwaysOnTop(WmWindow* window_on_top) { + // Changing always on top state may change window's parent. Iterate on a copy + // of |windows_| to avoid invalidating an iterator. Since both workspace and + // always_on_top containers' layouts are managed by this class all the + // appropriate windows will be included in the iteration. + WindowSet windows(windows_); + for (auto* window : windows) { + wm::WindowState* window_state = window->GetWindowState(); + if (window_on_top) + window_state->DisableAlwaysOnTop(window_on_top); + else + window_state->RestoreAlwaysOnTop(); + } +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/workspace_layout_manager.h b/ash/common/wm/workspace/workspace_layout_manager.h new file mode 100644 index 0000000..85413a71 --- /dev/null +++ b/ash/common/wm/workspace/workspace_layout_manager.h
@@ -0,0 +1,141 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_ +#define ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_ + +#include <memory> +#include <set> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm/wm_types.h" +#include "ash/common/wm_activation_observer.h" +#include "ash/common/wm_layout_manager.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" +#include "ui/display/display_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/keyboard/keyboard_controller_observer.h" + +namespace ash { + +class RootWindowController; +class WmShell; +class WmWindow; +class WorkspaceLayoutManagerBackdropDelegate; + +namespace wm { +class WMEvent; +} + +// LayoutManager used on the window created for a workspace. +class ASH_EXPORT WorkspaceLayoutManager + : public WmLayoutManager, + public aura::WindowObserver, + public WmActivationObserver, + public keyboard::KeyboardControllerObserver, + public display::DisplayObserver, + public ShellObserver, + public wm::WindowStateObserver { + public: + // |window| is the container for this layout manager. + explicit WorkspaceLayoutManager(WmWindow* window); + ~WorkspaceLayoutManager() override; + + // A delegate which can be set to add a backdrop behind the top most visible + // window. With the call the ownership of the delegate will be transferred to + // the WorkspaceLayoutManager. + void SetMaximizeBackdropDelegate( + std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate); + + // Overridden from WmLayoutManager: + void OnWindowResized() override; + void OnWindowAddedToLayout(WmWindow* child) override; + void OnWillRemoveWindowFromLayout(WmWindow* child) override; + void OnWindowRemovedFromLayout(WmWindow* child) override; + void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; + void SetChildBounds(WmWindow* child, + const gfx::Rect& requested_bounds) override; + + // Overriden from aura::WindowObserver: + void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + void OnWindowStackingChanged(aura::Window* window) override; + void OnWindowDestroying(aura::Window* window) override; + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) override; + + // WmActivationObserver overrides: + void OnWindowActivated(WmWindow* gained_active, + WmWindow* lost_active) override; + + // keyboard::KeyboardControllerObserver overrides: + void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; + void OnKeyboardClosed() override; + + // WindowStateObserver overrides: + void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) override; + + // display::DisplayObserver overrides: + void OnDisplayMetricsChanged(const display::Display& display, + uint32_t changed_metrics) override; + + // ShellObserver overrides: + void OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) override; + void OnPinnedStateChanged(WmWindow* pinned_window) override; + + private: + typedef std::set<WmWindow*> WindowSet; + + // Adjusts the bounds of all managed windows when the display area changes. + // This happens when the display size, work area insets has changed. + // If this is called for a display size change (i.e. |event| + // is DISPLAY_RESIZED), the non-maximized/non-fullscreen + // windows are readjusted to make sure the window is completely within the + // display region. Otherwise, it makes sure at least some parts of the window + // is on display. + void AdjustAllWindowsBoundsForWorkAreaChange(const wm::WMEvent* event); + + // Updates the visibility state of the shelf. + void UpdateShelfVisibility(); + + // Updates the fullscreen state of the workspace and notifies Shell if it + // has changed. + void UpdateFullscreenState(); + + // Updates the always-on-top state for windows managed by this layout + // manager. + void UpdateAlwaysOnTop(WmWindow* window_on_top); + + WmWindow* window_; + WmWindow* root_window_; + RootWindowController* root_window_controller_; + WmShell* shell_; + + // Set of windows we're listening to. + WindowSet windows_; + + // The work area in the coordinates of |window_|. + gfx::Rect work_area_in_parent_; + + // True if this workspace is currently in fullscreen mode. + bool is_fullscreen_; + + // A window which covers the full container and which gets inserted behind the + // topmost visible window. + std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> backdrop_delegate_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManager); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_
diff --git a/ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h b/ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h new file mode 100644 index 0000000..ec4fe68 --- /dev/null +++ b/ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h
@@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_ +#define ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "ash/common/wm/wm_types.h" + +namespace ash { + +class WmWindow; + +namespace wm { +class WindowState; +} + +// A delegate which can be set to create and control a backdrop which gets +// placed below the top level window. +class ASH_EXPORT WorkspaceLayoutManagerBackdropDelegate { + public: + virtual ~WorkspaceLayoutManagerBackdropDelegate() {} + + // A window got added to the layout. + virtual void OnWindowAddedToLayout(WmWindow* child) = 0; + + // A window got removed from the layout. + virtual void OnWindowRemovedFromLayout(WmWindow* child) = 0; + + // The visibility of a window has changed. + virtual void OnChildWindowVisibilityChanged(WmWindow* child, + bool visible) = 0; + + // The stacking order of a window has changed. + virtual void OnWindowStackingChanged(WmWindow* window) = 0; + + // A window state type has changed. + virtual void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) = 0; + + // The work area insets have changed, altering the total available space. + virtual void OnDisplayWorkAreaInsetsChanged() = 0; +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_
diff --git a/ash/common/wm/workspace/workspace_layout_manager_unittest.cc b/ash/common/wm/workspace/workspace_layout_manager_unittest.cc new file mode 100644 index 0000000..5ca89034 --- /dev/null +++ b/ash/common/wm/workspace/workspace_layout_manager_unittest.cc
@@ -0,0 +1,1268 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/workspace_layout_manager.h" + +#include <string> +#include <utility> + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shell_observer.h" +#include "ash/common/test/ash_test.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm/fullscreen_window_finder.h" +#include "ash/common/wm/maximize_mode/workspace_backdrop_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm/workspace/workspace_window_resizer.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/wm/window_state_aura.h" +#include "base/command_line.h" +#include "base/run_loop.h" +#include "ui/aura/env.h" +#include "ui/base/ui_base_switches.h" +#include "ui/base/ui_base_types.h" +#include "ui/compositor/scoped_animation_duration_scale_mode.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/insets.h" +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" + +namespace ash { +namespace { + +class MaximizeDelegateView : public views::WidgetDelegateView { + public: + explicit MaximizeDelegateView(const gfx::Rect& initial_bounds) + : initial_bounds_(initial_bounds) {} + ~MaximizeDelegateView() override {} + + bool GetSavedWindowPlacement(const views::Widget* widget, + gfx::Rect* bounds, + ui::WindowShowState* show_state) const override { + *bounds = initial_bounds_; + *show_state = ui::SHOW_STATE_MAXIMIZED; + return true; + } + + private: + const gfx::Rect initial_bounds_; + + DISALLOW_COPY_AND_ASSIGN(MaximizeDelegateView); +}; + +class TestShellObserver : public ShellObserver { + public: + TestShellObserver() : call_count_(0), is_fullscreen_(false) { + WmShell::Get()->AddShellObserver(this); + } + + ~TestShellObserver() override { WmShell::Get()->RemoveShellObserver(this); } + + void OnFullscreenStateChanged(bool is_fullscreen, + WmWindow* root_window) override { + call_count_++; + is_fullscreen_ = is_fullscreen; + } + + int call_count() const { return call_count_; } + + bool is_fullscreen() const { return is_fullscreen_; } + + private: + int call_count_; + bool is_fullscreen_; + + DISALLOW_COPY_AND_ASSIGN(TestShellObserver); +}; + +} // namespace + +using WorkspaceLayoutManagerTest = AshTest; + +// Verifies that a window containing a restore coordinate will be restored to +// to the size prior to minimize, keeping the restore rectangle in tact (if +// there is one). +TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) { + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + WmWindow* window = window_owner->window(); + gfx::Rect bounds(10, 15, 25, 35); + window->SetBounds(bounds); + + wm::WindowState* window_state = window->GetWindowState(); + + // This will not be used for un-minimizing window. + window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100)); + window_state->Minimize(); + window_state->Restore(); + EXPECT_EQ("0,0 100x100", window_state->GetRestoreBoundsInScreen().ToString()); + EXPECT_EQ("10,15 25x35", window->GetBounds().ToString()); + + UpdateDisplay("400x300,500x400"); + window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100), GetSecondaryDisplay()); + EXPECT_EQ(WmShell::Get()->GetAllRootWindows()[1], window->GetRootWindow()); + window_state->Minimize(); + // This will not be used for un-minimizing window. + window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100)); + window_state->Restore(); + EXPECT_EQ("600,0 100x100", window->GetBoundsInScreen().ToString()); + + // Make sure the unminimized window moves inside the display when + // 2nd display is disconnected. + window_state->Minimize(); + UpdateDisplay("400x300"); + window_state->Restore(); + EXPECT_EQ(WmShell::Get()->GetPrimaryRootWindow(), window->GetRootWindow()); + EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( + window->GetBounds())); +} + +TEST_F(WorkspaceLayoutManagerTest, KeepMinimumVisibilityInDisplays) { + UpdateDisplay("300x400,400x500"); + WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows(); + + if (!SetSecondaryDisplayPlacement(display::DisplayPlacement::TOP, 0)) + return; + + EXPECT_EQ("0,-500 400x500", root_windows[1]->GetBoundsInScreen().ToString()); + + std::unique_ptr<WindowOwner> window1_owner( + CreateTestWindow(gfx::Rect(10, -400, 200, 200))); + EXPECT_EQ("10,-400 200x200", + window1_owner->window()->GetBoundsInScreen().ToString()); + + // Make sure the caption is visible. + std::unique_ptr<WindowOwner> window2_owner( + CreateTestWindow(gfx::Rect(10, -600, 200, 200))); + EXPECT_EQ("10,-500 200x200", + window2_owner->window()->GetBoundsInScreen().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, NoMinimumVisibilityForPopupWindows) { + UpdateDisplay("300x400"); + + // Create a popup window out of display boundaries and make sure it is not + // moved to have minimum visibility. + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(400, 100, 50, 50), ui::wm::WINDOW_TYPE_POPUP)); + EXPECT_EQ("400,100 50x50", + window_owner->window()->GetBoundsInScreen().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) { + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 30, 40))); + WmWindow* window = window_owner->window(); + wm::WindowState* window_state = window->GetWindowState(); + + // Maximized -> Normal transition. + window_state->Maximize(); + window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40)); + window_state->Restore(); + EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( + window->GetBounds())); + // Y bounds should not be negative. + EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString()); + + // Minimized -> Normal transition. + window->SetBounds(gfx::Rect(-100, -100, 30, 40)); + window_state->Minimize(); + EXPECT_FALSE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( + window->GetBounds())); + EXPECT_EQ("-100,-100 30x40", window->GetBounds().ToString()); + window->Show(); + EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( + window->GetBounds())); + // Y bounds should not be negative. + EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString()); + + // Fullscreen -> Normal transition. + window->SetBounds(gfx::Rect(0, 0, 30, 40)); // reset bounds. + ASSERT_EQ("0,0 30x40", window->GetBounds().ToString()); + window->SetShowState(ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(window->GetBounds(), window->GetRootWindow()->GetBounds()); + window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40)); + window_state->Restore(); + EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( + window->GetBounds())); + // Y bounds should not be negative. + EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, MaximizeInDisplayToBeRestored) { + UpdateDisplay("300x400,400x500"); + + WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows(); + + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 30, 40))); + WmWindow* window = window_owner->window(); + EXPECT_EQ(root_windows[0], window->GetRootWindow()); + + wm::WindowState* window_state = window->GetWindowState(); + window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40)); + // Maximize the window in 2nd display as the restore bounds + // is inside 2nd display. + window_state->Maximize(); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ( + gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(), + window->GetBoundsInScreen().ToString()); + + window_state->Restore(); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString()); + + // If the restore bounds intersects with the current display, + // don't move. + window_state->SetRestoreBoundsInScreen(gfx::Rect(295, 0, 30, 40)); + window_state->Maximize(); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ( + gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(), + window->GetBoundsInScreen().ToString()); + + window_state->Restore(); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString()); + + // Restoring widget state. + std::unique_ptr<views::Widget> w1(new views::Widget); + views::Widget::InitParams params; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.delegate = new MaximizeDelegateView(gfx::Rect(400, 0, 30, 40)); + ConfigureWidgetInitParamsForDisplay(root_windows[0], ¶ms); + w1->Init(params); + EXPECT_EQ(root_windows[0], + WmWindow::Get(w1->GetNativeWindow())->GetRootWindow()); + w1->Show(); + EXPECT_TRUE(w1->IsMaximized()); + EXPECT_EQ(root_windows[1], + WmWindow::Get(w1->GetNativeWindow())->GetRootWindow()); + EXPECT_EQ( + gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(), + w1->GetWindowBoundsInScreen().ToString()); + w1->Restore(); + EXPECT_EQ(root_windows[1], + WmWindow::Get(w1->GetNativeWindow())->GetRootWindow()); + EXPECT_EQ("400,0 30x40", w1->GetWindowBoundsInScreen().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, FullscreenInDisplayToBeRestored) { + UpdateDisplay("300x400,400x500"); + + WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows(); + + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 30, 40))); + WmWindow* window = window_owner->window(); + EXPECT_EQ(root_windows[0], window->GetRootWindow()); + + wm::WindowState* window_state = window->GetWindowState(); + window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40)); + // Maximize the window in 2nd display as the restore bounds + // is inside 2nd display. + window->SetShowState(ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString()); + + window_state->Restore(); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString()); + + // If the restore bounds intersects with the current display, + // don't move. + window_state->SetRestoreBoundsInScreen(gfx::Rect(295, 0, 30, 40)); + window->SetShowState(ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString()); + + window_state->Restore(); + EXPECT_EQ(root_windows[1], window->GetRootWindow()); + EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString()); +} + +// aura::WindowObserver implementation used by +// DontClobberRestoreBoundsWindowObserver. This code mirrors what +// BrowserFrameAsh does. In particular when this code sees the window was +// maximized it changes the bounds of a secondary window. The secondary window +// mirrors the status window. +class DontClobberRestoreBoundsWindowObserver : public aura::WindowObserver { + public: + DontClobberRestoreBoundsWindowObserver() : window_(nullptr) {} + + void set_window(WmWindow* window) { window_ = window; } + + // aura::WindowObserver: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override { + if (!window_) + return; + + if (wm::GetWindowState(window)->IsMaximized()) { + WmWindow* w = window_; + window_ = nullptr; + + gfx::Rect shelf_bounds(AshTest::GetPrimaryShelf()->GetIdealBounds()); + const gfx::Rect& window_bounds(w->GetBounds()); + w->SetBounds(gfx::Rect(window_bounds.x(), shelf_bounds.y() - 1, + window_bounds.width(), window_bounds.height())); + } + } + + private: + WmWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(DontClobberRestoreBoundsWindowObserver); +}; + +// Creates a window, maximized the window and from within the maximized +// notification sets the bounds of a window to overlap the shelf. Verifies this +// doesn't effect the restore bounds. +TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) { + DontClobberRestoreBoundsWindowObserver window_observer; + WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_TEXTURED)); + WmWindow* window = window_owner.window(); + window->SetBounds(gfx::Rect(10, 20, 30, 40)); + // NOTE: for this test to exercise the failure the observer needs to be added + // before the parent set. This mimics what BrowserFrameAsh does. + window->aura_window()->AddObserver(&window_observer); + ParentWindowInPrimaryRootWindow(window); + window->Show(); + + wm::WindowState* window_state = window->GetWindowState(); + window_state->Activate(); + + std::unique_ptr<WindowOwner> window2_owner( + CreateTestWindow(gfx::Rect(12, 20, 30, 40))); + WmWindow* window2 = window2_owner->window(); + AddTransientChild(window, window2); + window2->Show(); + + window_observer.set_window(window2); + window_state->Maximize(); + EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInScreen().ToString()); + window->aura_window()->RemoveObserver(&window_observer); +} + +// Verifies when a window is maximized all descendant windows have a size. +TEST_F(WorkspaceLayoutManagerTest, ChildBoundsResetOnMaximize) { + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(10, 20, 30, 40))); + WmWindow* window = window_owner->window(); + window->Show(); + wm::WindowState* window_state = window->GetWindowState(); + window_state->Activate(); + std::unique_ptr<WindowOwner> child_window_owner( + CreateChildWindow(window, gfx::Rect(5, 6, 7, 8))); + WmWindow* child_window = child_window_owner->window(); + window_state->Maximize(); + EXPECT_EQ("5,6 7x8", child_window->GetBounds().ToString()); +} + +// Verifies a window created with maximized state has the maximized +// bounds. +TEST_F(WorkspaceLayoutManagerTest, MaximizeWithEmptySize) { + WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_TEXTURED)); + WmWindow* window = window_owner.window(); + window->GetWindowState()->Maximize(); + WmWindow* default_container = + WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer( + kShellWindowId_DefaultContainer); + default_container->AddChild(window); + window->Show(); + gfx::Rect work_area( + display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); + EXPECT_EQ(work_area.ToString(), window->GetBoundsInScreen().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) { + // TODO: fix. This test verifies that when a window is added the bounds are + // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes + // from NativeWidgetAura), which means this test now fails for aura-mus. + if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS) + return; + + // Normal window bounds shouldn't be changed. + gfx::Rect window_bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(window_bounds)); + WmWindow* window = window_owner->window(); + EXPECT_EQ(window_bounds, window->GetBounds()); + + // If the window is out of the workspace, it would be moved on screen. + gfx::Rect root_window_bounds = + WmShell::Get()->GetPrimaryRootWindow()->GetBounds(); + window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height()); + ASSERT_FALSE(window_bounds.Intersects(root_window_bounds)); + std::unique_ptr<WindowOwner> out_window_owner( + CreateTestWindow(window_bounds)); + WmWindow* out_window = out_window_owner->window(); + EXPECT_EQ(window_bounds.size(), out_window->GetBounds().size()); + gfx::Rect bounds = out_window->GetBounds(); + bounds.Intersect(root_window_bounds); + + // 30% of the window edge must be visible. + EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); + + WmWindow* parent = out_window->GetParent(); + parent->RemoveChild(out_window); + out_window->SetBounds(gfx::Rect(-200, -200, 200, 200)); + // UserHasChangedWindowPositionOrSize flag shouldn't turn off this behavior. + window->GetWindowState()->set_bounds_changed_by_user(true); + parent->AddChild(out_window); + EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); + + // Make sure we always make more than 1/3 of the window edge visible even + // if the initial bounds intersects with display. + window_bounds.SetRect(-150, -150, 200, 200); + bounds = window_bounds; + bounds.Intersect(root_window_bounds); + + // Make sure that the initial bounds' visible area is less than 26% + // so that the auto adjustment logic kicks in. + ASSERT_LT(bounds.width(), out_window->GetBounds().width() * 0.26); + ASSERT_LT(bounds.height(), out_window->GetBounds().height() * 0.26); + ASSERT_TRUE(window_bounds.Intersects(root_window_bounds)); + + std::unique_ptr<WindowOwner> partially_out_window_owner( + CreateTestWindow(window_bounds)); + WmWindow* partially_out_window = partially_out_window_owner->window(); + EXPECT_EQ(window_bounds.size(), partially_out_window->GetBounds().size()); + bounds = partially_out_window->GetBounds(); + bounds.Intersect(root_window_bounds); + EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); + + // Make sure the window whose 30% width/height is bigger than display + // will be placed correctly. + window_bounds.SetRect(-1900, -1900, 3000, 3000); + std::unique_ptr<WindowOwner> window_bigger_than_display_owner( + CreateTestWindow(window_bounds)); + WmWindow* window_bigger_than_display = + window_bigger_than_display_owner->window(); + EXPECT_GE(root_window_bounds.width(), + window_bigger_than_display->GetBounds().width()); + EXPECT_GE(root_window_bounds.height(), + window_bigger_than_display->GetBounds().height()); + + bounds = window_bigger_than_display->GetBounds(); + bounds.Intersect(root_window_bounds); + EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); +} + +// Verifies the size of a window is enforced to be smaller than the work area. +TEST_F(WorkspaceLayoutManagerTest, SizeToWorkArea) { + // Normal window bounds shouldn't be changed. + gfx::Size work_area( + display::Screen::GetScreen()->GetPrimaryDisplay().work_area().size()); + const gfx::Rect window_bounds(100, 101, work_area.width() + 1, + work_area.height() + 2); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(window_bounds)); + WmWindow* window = window_owner->window(); + // TODO: fix. This test verifies that when a window is added the bounds are + // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes + // from NativeWidgetAura), which means this test now fails for aura-mus. + if (aura::Env::GetInstance()->mode() != aura::Env::Mode::MUS) { + EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), + window->GetBounds().ToString()); + } + + // Directly setting the bounds triggers a slightly different code path. Verify + // that too. + window->SetBounds(window_bounds); + EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), + window->GetBounds().ToString()); +} + +TEST_F(WorkspaceLayoutManagerTest, NotifyFullscreenChanges) { + TestShellObserver observer; + std::unique_ptr<WindowOwner> window1_owner( + CreateTestWindow(gfx::Rect(1, 2, 30, 40))); + WmWindow* window1 = window1_owner->window(); + std::unique_ptr<WindowOwner> window2_owner( + CreateTestWindow(gfx::Rect(1, 2, 30, 40))); + WmWindow* window2 = window2_owner->window(); + wm::WindowState* window_state1 = window1->GetWindowState(); + wm::WindowState* window_state2 = window2->GetWindowState(); + window_state2->Activate(); + + const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN); + window_state2->OnWMEvent(&toggle_fullscreen_event); + EXPECT_EQ(1, observer.call_count()); + EXPECT_TRUE(observer.is_fullscreen()); + + // When window1 moves to the front the fullscreen state should change. + window_state1->Activate(); + EXPECT_EQ(2, observer.call_count()); + EXPECT_FALSE(observer.is_fullscreen()); + + // It should change back if window2 becomes active again. + window_state2->Activate(); + EXPECT_EQ(3, observer.call_count()); + EXPECT_TRUE(observer.is_fullscreen()); + + window_state2->OnWMEvent(&toggle_fullscreen_event); + EXPECT_EQ(4, observer.call_count()); + EXPECT_FALSE(observer.is_fullscreen()); + + window_state2->OnWMEvent(&toggle_fullscreen_event); + EXPECT_EQ(5, observer.call_count()); + EXPECT_TRUE(observer.is_fullscreen()); + + // Closing the window should change the fullscreen state. + window2_owner.reset(); + EXPECT_EQ(6, observer.call_count()); + EXPECT_FALSE(observer.is_fullscreen()); +} + +// For crbug.com/673803, snapped window may not adjust snapped bounds on work +// area changed properly if window's layer is doing animation. We should use +// GetTargetBounds to check if snapped bounds need to be changed. +TEST_F(WorkspaceLayoutManagerTest, + SnappedWindowMayNotAdjustBoundsOnWorkAreaChanged) { + UpdateDisplay("300x400"); + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(10, 20, 100, 200))); + WmWindow* window = window_owner->window(); + wm::WindowState* window_state = window->GetWindowState(); + gfx::Insets insets(0, 0, 50, 0); + WmShell::Get()->SetDisplayWorkAreaInsets(window, insets); + const wm::WMEvent snap_left(wm::WM_EVENT_SNAP_LEFT); + window_state->OnWMEvent(&snap_left); + EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType()); + const gfx::Rect kWorkAreaBounds = + display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); + gfx::Rect expected_bounds = + gfx::Rect(kWorkAreaBounds.x(), kWorkAreaBounds.y(), + kWorkAreaBounds.width() / 2, kWorkAreaBounds.height()); + EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString()); + + ui::ScopedAnimationDurationScaleMode test_duration_mode( + ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); + // The following two SetDisplayWorkAreaInsets calls simulate the case of + // crbug.com/673803 that work area first becomes fullscreen and then returns + // to the original state. + WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets(0, 0, 0, 0)); + ui::LayerAnimator* animator = window->GetLayer()->GetAnimator(); + EXPECT_TRUE(animator->is_animating()); + WmShell::Get()->SetDisplayWorkAreaInsets(window, insets); + animator->StopAnimating(); + EXPECT_FALSE(animator->is_animating()); + EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString()); +} + +// Do not adjust window bounds to ensure minimum visibility for transient +// windows (crbug.com/624806). +TEST_F(WorkspaceLayoutManagerTest, + DoNotAdjustTransientWindowBoundsToEnsureMinimumVisibility) { + UpdateDisplay("300x400"); + WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, + ui::LAYER_TEXTURED)); + WmWindow* window = window_owner.window(); + window->SetBounds(gfx::Rect(10, 0, 100, 200)); + ParentWindowInPrimaryRootWindow(window); + window->Show(); + + std::unique_ptr<WindowOwner> window2_owner( + CreateTestWindow(gfx::Rect(10, 0, 40, 20))); + WmWindow* window2 = window2_owner->window(); + AddTransientChild(window, window2); + window2->Show(); + + gfx::Rect expected_bounds = window2->GetBounds(); + WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets(50, 0, 0, 0)); + EXPECT_EQ(expected_bounds.ToString(), window2->GetBounds().ToString()); +} + +// Following "Solo" tests were originally written for BaseLayoutManager. +using WorkspaceLayoutManagerSoloTest = AshTest; + +// Tests normal->maximize->normal. +TEST_F(WorkspaceLayoutManagerSoloTest, Maximize) { + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); + WmWindow* window = window_owner->window(); + window->SetShowState(ui::SHOW_STATE_MAXIMIZED); + // Maximized window fills the work area, not the whole display. + EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), + window->GetBounds().ToString()); + window->SetShowState(ui::SHOW_STATE_NORMAL); + EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString()); +} + +// Tests normal->minimize->normal. +TEST_F(WorkspaceLayoutManagerSoloTest, Minimize) { + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); + WmWindow* window = window_owner->window(); + window->SetShowState(ui::SHOW_STATE_MINIMIZED); + EXPECT_FALSE(window->IsVisible()); + EXPECT_TRUE(window->GetWindowState()->IsMinimized()); + EXPECT_EQ(bounds, window->GetBounds()); + window->SetShowState(ui::SHOW_STATE_NORMAL); + EXPECT_TRUE(window->IsVisible()); + EXPECT_FALSE(window->GetWindowState()->IsMinimized()); + EXPECT_EQ(bounds, window->GetBounds()); +} + +// A aura::WindowObserver which sets the focus when the window becomes visible. +class FocusDuringUnminimizeWindowObserver : public aura::WindowObserver { + public: + FocusDuringUnminimizeWindowObserver() + : window_(nullptr), show_state_(ui::SHOW_STATE_END) {} + ~FocusDuringUnminimizeWindowObserver() override { SetWindow(nullptr); } + + void SetWindow(WmWindow* window) { + if (window_) + window_->aura_window()->RemoveObserver(this); + window_ = window; + if (window_) + window_->aura_window()->AddObserver(this); + } + + // aura::WindowObserver: + void OnWindowVisibilityChanged(aura::Window* window, bool visible) override { + if (window_) { + if (visible) + window_->SetFocused(); + show_state_ = window_->GetShowState(); + } + } + + ui::WindowShowState GetShowStateAndReset() { + ui::WindowShowState ret = show_state_; + show_state_ = ui::SHOW_STATE_END; + return ret; + } + + private: + WmWindow* window_; + ui::WindowShowState show_state_; + + DISALLOW_COPY_AND_ASSIGN(FocusDuringUnminimizeWindowObserver); +}; + +// Make sure that the window's show state is correct in +// WindowObserver::OnWindowTargetVisibilityChanged(), and setting focus in this +// callback doesn't cause DCHECK error. See crbug.com/168383. +TEST_F(WorkspaceLayoutManagerSoloTest, FocusDuringUnminimize) { + FocusDuringUnminimizeWindowObserver observer; + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(100, 100, 100, 100))); + WmWindow* window = window_owner->window(); + observer.SetWindow(window); + window->SetShowState(ui::SHOW_STATE_MINIMIZED); + EXPECT_FALSE(window->IsVisible()); + EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, observer.GetShowStateAndReset()); + window->Show(); + EXPECT_TRUE(window->IsVisible()); + EXPECT_EQ(ui::SHOW_STATE_NORMAL, observer.GetShowStateAndReset()); + observer.SetWindow(nullptr); +} + +// Tests maximized window size during root window resize. +TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeRootWindowResize) { + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); + WmWindow* window = window_owner->window(); + window->SetShowState(ui::SHOW_STATE_MAXIMIZED); + gfx::Rect initial_work_area_bounds = + wm::GetMaximizedWindowBoundsInParent(window); + EXPECT_EQ(initial_work_area_bounds.ToString(), + window->GetBounds().ToString()); + // Enlarge the root window. We should still match the work area size. + UpdateDisplay("900x700"); + EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), + window->GetBounds().ToString()); + EXPECT_NE(initial_work_area_bounds.ToString(), + wm::GetMaximizedWindowBoundsInParent(window).ToString()); +} + +// Tests normal->fullscreen->normal. +TEST_F(WorkspaceLayoutManagerSoloTest, Fullscreen) { + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); + WmWindow* window = window_owner->window(); + window->SetShowState(ui::SHOW_STATE_FULLSCREEN); + // Fullscreen window fills the whole display. + EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(), + window->GetBounds().ToString()); + window->SetShowState(ui::SHOW_STATE_NORMAL); + EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString()); +} + +// Tests that fullscreen window causes always_on_top windows to stack below. +TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenSuspendsAlwaysOnTop) { + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> fullscreen_window_owner( + CreateTestWindow(bounds)); + WmWindow* fullscreen_window = fullscreen_window_owner->window(); + std::unique_ptr<WindowOwner> always_on_top_window1_owner( + CreateTestWindow(bounds)); + WmWindow* always_on_top_window1 = always_on_top_window1_owner->window(); + std::unique_ptr<WindowOwner> always_on_top_window2_owner( + CreateTestWindow(bounds)); + WmWindow* always_on_top_window2 = always_on_top_window2_owner->window(); + always_on_top_window1->SetAlwaysOnTop(true); + always_on_top_window2->SetAlwaysOnTop(true); + // Making a window fullscreen temporarily suspends always on top state. + fullscreen_window->SetShowState(ui::SHOW_STATE_FULLSCREEN); + EXPECT_FALSE(always_on_top_window1->IsAlwaysOnTop()); + EXPECT_FALSE(always_on_top_window2->IsAlwaysOnTop()); + EXPECT_NE(nullptr, wm::GetWindowForFullscreenMode(fullscreen_window)); + + // Adding a new always-on-top window is not affected by fullscreen. + std::unique_ptr<WindowOwner> always_on_top_window3_owner( + CreateTestWindow(bounds)); + WmWindow* always_on_top_window3 = always_on_top_window3_owner->window(); + always_on_top_window3->SetAlwaysOnTop(true); + EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop()); + + // Making fullscreen window normal restores always on top windows. + fullscreen_window->SetShowState(ui::SHOW_STATE_NORMAL); + EXPECT_TRUE(always_on_top_window1->IsAlwaysOnTop()); + EXPECT_TRUE(always_on_top_window2->IsAlwaysOnTop()); + EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop()); + EXPECT_EQ(nullptr, wm::GetWindowForFullscreenMode(fullscreen_window)); +} + +// Similary, pinned window causes always_on_top_ windows to stack below. +TEST_F(WorkspaceLayoutManagerSoloTest, PinnedSuspendsAlwaysOnTop) { + // TODO: mash doesn't support pinning yet http://crbug.com/622486. + if (WmShell::Get()->IsRunningInMash()) + return; + + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> pinned_window_owner(CreateTestWindow(bounds)); + WmWindow* pinned_window = pinned_window_owner->window(); + std::unique_ptr<WindowOwner> always_on_top_window1_owner( + CreateTestWindow(bounds)); + WmWindow* always_on_top_window1 = always_on_top_window1_owner->window(); + std::unique_ptr<WindowOwner> always_on_top_window2_owner( + CreateTestWindow(bounds)); + WmWindow* always_on_top_window2 = always_on_top_window2_owner->window(); + always_on_top_window1->SetAlwaysOnTop(true); + always_on_top_window2->SetAlwaysOnTop(true); + + // Making a window pinned temporarily suspends always on top state. + const bool trusted = false; + pinned_window->SetPinned(trusted); + EXPECT_FALSE(always_on_top_window1->IsAlwaysOnTop()); + EXPECT_FALSE(always_on_top_window2->IsAlwaysOnTop()); + + // Adding a new always-on-top window also is affected by pinned mode. + std::unique_ptr<WindowOwner> always_on_top_window3_owner( + CreateTestWindow(bounds)); + WmWindow* always_on_top_window3 = always_on_top_window3_owner->window(); + always_on_top_window3->SetAlwaysOnTop(true); + EXPECT_FALSE(always_on_top_window3->IsAlwaysOnTop()); + + // Making pinned window normal restores always on top windows. + pinned_window->GetWindowState()->Restore(); + EXPECT_TRUE(always_on_top_window1->IsAlwaysOnTop()); + EXPECT_TRUE(always_on_top_window2->IsAlwaysOnTop()); + EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop()); +} + +// Tests fullscreen window size during root window resize. +TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenRootWindowResize) { + gfx::Rect bounds(100, 100, 200, 200); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); + WmWindow* window = window_owner->window(); + // Fullscreen window fills the whole display. + window->SetShowState(ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(), + window->GetBounds().ToString()); + // Enlarge the root window. We should still match the display size. + UpdateDisplay("800x600"); + EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(), + window->GetBounds().ToString()); +} + +// Tests that when the screen gets smaller the windows aren't bigger than +// the screen. +TEST_F(WorkspaceLayoutManagerSoloTest, RootWindowResizeShrinksWindows) { + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(10, 20, 500, 400))); + WmWindow* window = window_owner->window(); + gfx::Rect work_area = window->GetDisplayNearestWindow().work_area(); + // Invariant: Window is smaller than work area. + EXPECT_LE(window->GetBounds().width(), work_area.width()); + EXPECT_LE(window->GetBounds().height(), work_area.height()); + + // Make the root window narrower than our window. + UpdateDisplay("300x400"); + work_area = window->GetDisplayNearestWindow().work_area(); + EXPECT_LE(window->GetBounds().width(), work_area.width()); + EXPECT_LE(window->GetBounds().height(), work_area.height()); + + // Make the root window shorter than our window. + UpdateDisplay("300x200"); + work_area = window->GetDisplayNearestWindow().work_area(); + EXPECT_LE(window->GetBounds().width(), work_area.width()); + EXPECT_LE(window->GetBounds().height(), work_area.height()); + + // Enlarging the root window does not change the window bounds. + gfx::Rect old_bounds = window->GetBounds(); + UpdateDisplay("800x600"); + EXPECT_EQ(old_bounds.width(), window->GetBounds().width()); + EXPECT_EQ(old_bounds.height(), window->GetBounds().height()); +} + +// Verifies maximizing sets the restore bounds, and restoring +// restores the bounds. +TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeSetsRestoreBounds) { + const gfx::Rect initial_bounds(10, 20, 30, 40); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(initial_bounds)); + WmWindow* window = window_owner->window(); + EXPECT_EQ(initial_bounds, window->GetBounds()); + wm::WindowState* window_state = window->GetWindowState(); + + // Maximize it, which will keep the previous restore bounds. + window->SetShowState(ui::SHOW_STATE_MAXIMIZED); + EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInParent().ToString()); + + // Restore it, which should restore bounds and reset restore bounds. + window->SetShowState(ui::SHOW_STATE_NORMAL); + EXPECT_EQ("10,20 30x40", window->GetBounds().ToString()); + EXPECT_FALSE(window_state->HasRestoreBounds()); +} + +// Verifies maximizing keeps the restore bounds if set. +TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeResetsRestoreBounds) { + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + WmWindow* window = window_owner->window(); + wm::WindowState* window_state = window->GetWindowState(); + window_state->SetRestoreBoundsInParent(gfx::Rect(10, 11, 12, 13)); + + // Maximize it, which will keep the previous restore bounds. + window->SetShowState(ui::SHOW_STATE_MAXIMIZED); + EXPECT_EQ("10,11 12x13", window_state->GetRestoreBoundsInParent().ToString()); +} + +// Verifies that the restore bounds do not get reset when restoring to a +// maximzied state from a minimized state. +TEST_F(WorkspaceLayoutManagerSoloTest, + BoundsAfterRestoringToMaximizeFromMinimize) { + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + WmWindow* window = window_owner->window(); + gfx::Rect bounds(10, 15, 25, 35); + window->SetBounds(bounds); + + wm::WindowState* window_state = window->GetWindowState(); + // Maximize it, which should reset restore bounds. + window_state->Maximize(); + EXPECT_EQ(bounds.ToString(), + window_state->GetRestoreBoundsInParent().ToString()); + // Minimize the window. The restore bounds should not change. + window_state->Minimize(); + EXPECT_EQ(bounds.ToString(), + window_state->GetRestoreBoundsInParent().ToString()); + + // Show the window again. The window should be maximized, and the restore + // bounds should not change. + window->Show(); + EXPECT_EQ(bounds.ToString(), + window_state->GetRestoreBoundsInParent().ToString()); + EXPECT_TRUE(window_state->IsMaximized()); + + window_state->Restore(); + EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString()); +} + +// Verify if the window is not resized during screen lock. See: crbug.com/173127 +TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) { + test::TestSessionStateDelegate::SetCanLockScreen(true); + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + WmWindow* window = window_owner->window(); + // window with AlwaysOnTop will be managed by BaseLayoutManager. + window->SetAlwaysOnTop(true); + window->Show(); + + WmShelf* shelf = GetPrimaryShelf(); + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + + window->SetBounds(wm::GetMaximizedWindowBoundsInParent(window)); + gfx::Rect window_bounds = window->GetBounds(); + EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), + window_bounds.ToString()); + + // The window size should not get touched while we are in lock screen. + WmShell::Get()->GetSessionStateDelegate()->LockScreen(); + ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager(); + shelf_layout_manager->UpdateVisibilityState(); + EXPECT_EQ(window_bounds.ToString(), window->GetBounds().ToString()); + + // Coming out of the lock screen the window size should still remain. + WmShell::Get()->GetSessionStateDelegate()->UnlockScreen(); + shelf_layout_manager->UpdateVisibilityState(); + EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), + window_bounds.ToString()); + EXPECT_EQ(window_bounds.ToString(), window->GetBounds().ToString()); +} + +// Following tests are written to test the backdrop functionality. + +namespace { + +WorkspaceLayoutManager* GetWorkspaceLayoutManager(WmWindow* container) { + return static_cast<WorkspaceLayoutManager*>(container->GetLayoutManager()); +} + +class WorkspaceLayoutManagerBackdropTest : public AshTest { + public: + WorkspaceLayoutManagerBackdropTest() : default_container_(nullptr) {} + ~WorkspaceLayoutManagerBackdropTest() override {} + + void SetUp() override { + AshTest::SetUp(); + UpdateDisplay("800x600"); + default_container_ = + WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer( + kShellWindowId_DefaultContainer); + } + + // Turn the top window back drop on / off. + void ShowTopWindowBackdrop(bool show) { + std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> backdrop; + if (show) + backdrop.reset(new WorkspaceBackdropDelegate(default_container_)); + GetWorkspaceLayoutManager(default_container_) + ->SetMaximizeBackdropDelegate(std::move(backdrop)); + // Closing and / or opening can be a delayed operation. + base::RunLoop().RunUntilIdle(); + } + + // Return the default container. + WmWindow* default_container() { return default_container_; } + + // Return the order of windows (top most first) as they are in the default + // container. If the window is visible it will be a big letter, otherwise a + // small one. The backdrop will be an X and unknown windows will be shown as + // '!'. + std::string GetWindowOrderAsString(WmWindow* backdrop, + WmWindow* wa, + WmWindow* wb, + WmWindow* wc) { + std::string result; + WmWindow::Windows children = default_container()->GetChildren(); + for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) { + if (!result.empty()) + result += ","; + if (children[i] == wa) + result += children[i]->IsVisible() ? "A" : "a"; + else if (children[i] == wb) + result += children[i]->IsVisible() ? "B" : "b"; + else if (children[i] == wc) + result += children[i]->IsVisible() ? "C" : "c"; + else if (children[i] == backdrop) + result += children[i]->IsVisible() ? "X" : "x"; + else + result += "!"; + } + return result; + } + + private: + // The default container. + WmWindow* default_container_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerBackdropTest); +}; + +} // namespace + +// Check that creating the BackDrop without destroying it does not lead into +// a crash. +TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropCrashTest) { + ShowTopWindowBackdrop(true); +} + +// Verify basic assumptions about the backdrop. +TEST_F(WorkspaceLayoutManagerBackdropTest, BasicBackdropTests) { + // Create a backdrop and see that there is one window (the backdrop) and + // that the size is the same as the default container as well as that it is + // not visible. + ShowTopWindowBackdrop(true); + ASSERT_EQ(1U, default_container()->GetChildren().size()); + EXPECT_FALSE(default_container()->GetChildren()[0]->IsVisible()); + + { + // Add a window and make sure that the backdrop is the second child. + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + WmWindow* window = window_owner->window(); + window->Show(); + ASSERT_EQ(2U, default_container()->GetChildren().size()); + EXPECT_TRUE(default_container()->GetChildren()[0]->IsVisible()); + EXPECT_TRUE(default_container()->GetChildren()[1]->IsVisible()); + EXPECT_EQ(window, default_container()->GetChildren()[1]); + EXPECT_EQ(default_container()->GetBounds().ToString(), + default_container()->GetChildren()[0]->GetBounds().ToString()); + } + + // With the window gone the backdrop should be invisible again. + ASSERT_EQ(1U, default_container()->GetChildren().size()); + EXPECT_FALSE(default_container()->GetChildren()[0]->IsVisible()); + + // Destroying the Backdrop should empty the container. + ShowTopWindowBackdrop(false); + ASSERT_EQ(0U, default_container()->GetChildren().size()); +} + +// Verify that the backdrop gets properly created and placed. +TEST_F(WorkspaceLayoutManagerBackdropTest, VerifyBackdropAndItsStacking) { + std::unique_ptr<WindowOwner> window1_owner( + CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + WmWindow* window1 = window1_owner->window(); + window1->Show(); + + // Get the default container and check that only a single window is in there. + ASSERT_EQ(1U, default_container()->GetChildren().size()); + EXPECT_EQ(window1, default_container()->GetChildren()[0]); + EXPECT_EQ("A", GetWindowOrderAsString(nullptr, window1, nullptr, nullptr)); + + // Create 2 more windows and check that they are also in the container. + std::unique_ptr<WindowOwner> window2_owner( + CreateTestWindow(gfx::Rect(10, 2, 3, 4))); + WmWindow* window2 = window2_owner->window(); + std::unique_ptr<WindowOwner> window3_owner( + CreateTestWindow(gfx::Rect(20, 2, 3, 4))); + WmWindow* window3 = window3_owner->window(); + window2->Show(); + window3->Show(); + + WmWindow* backdrop = nullptr; + EXPECT_EQ("C,B,A", + GetWindowOrderAsString(backdrop, window1, window2, window3)); + + // Turn on the backdrop mode and check that the window shows up where it + // should be (second highest number). + ShowTopWindowBackdrop(true); + backdrop = default_container()->GetChildren()[2]; + EXPECT_EQ("C,X,B,A", + GetWindowOrderAsString(backdrop, window1, window2, window3)); + + // Switch the order of windows and check that it still remains in that + // location. + default_container()->StackChildAtTop(window2); + EXPECT_EQ("B,X,C,A", + GetWindowOrderAsString(backdrop, window1, window2, window3)); + + // Make the top window invisible and check. + window2->Hide(); + EXPECT_EQ("b,C,X,A", + GetWindowOrderAsString(backdrop, window1, window2, window3)); + // Then delete window after window and see that everything is in order. + window1_owner.reset(); + EXPECT_EQ("b,C,X", + GetWindowOrderAsString(backdrop, window1, window2, window3)); + window3_owner.reset(); + EXPECT_EQ("b,x", GetWindowOrderAsString(backdrop, window1, window2, window3)); + ShowTopWindowBackdrop(false); + EXPECT_EQ("b", GetWindowOrderAsString(nullptr, window1, window2, window3)); +} + +// Tests that when hidding the shelf, that the backdrop resizes to fill the +// entire workspace area. +TEST_F(WorkspaceLayoutManagerBackdropTest, ShelfVisibilityChangesBounds) { + WmShelf* shelf = GetPrimaryShelf(); + ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager(); + ShowTopWindowBackdrop(true); + RunAllPendingInMessageLoop(); + + ASSERT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state()); + gfx::Rect initial_bounds = default_container()->GetChildren()[0]->GetBounds(); + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); + shelf_layout_manager->UpdateVisibilityState(); + + // When the shelf is re-shown WorkspaceLayoutManager shrinks all children + // including the backdrop. + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); + shelf_layout_manager->UpdateVisibilityState(); + gfx::Rect reduced_bounds = default_container()->GetChildren()[0]->GetBounds(); + EXPECT_LT(reduced_bounds.height(), initial_bounds.height()); + + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); + shelf_layout_manager->UpdateVisibilityState(); + + EXPECT_GT(default_container()->GetChildren()[0]->GetBounds().height(), + reduced_bounds.height()); +} + +class WorkspaceLayoutManagerKeyboardTest : public AshTest { + public: + WorkspaceLayoutManagerKeyboardTest() : layout_manager_(nullptr) {} + ~WorkspaceLayoutManagerKeyboardTest() override {} + + void SetUp() override { + AshTest::SetUp(); + UpdateDisplay("800x600"); + WmWindow* default_container = + WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer( + kShellWindowId_DefaultContainer); + layout_manager_ = GetWorkspaceLayoutManager(default_container); + } + + void ShowKeyboard() { + layout_manager_->OnKeyboardBoundsChanging(keyboard_bounds_); + restore_work_area_insets_ = + display::Screen::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets(); + WmShell::Get()->SetDisplayWorkAreaInsets( + WmShell::Get()->GetPrimaryRootWindow(), + gfx::Insets(0, 0, keyboard_bounds_.height(), 0)); + } + + void HideKeyboard() { + WmShell::Get()->SetDisplayWorkAreaInsets( + WmShell::Get()->GetPrimaryRootWindow(), restore_work_area_insets_); + layout_manager_->OnKeyboardBoundsChanging(gfx::Rect()); + } + + // Initializes the keyboard bounds using the bottom half of the work area. + void InitKeyboardBounds() { + gfx::Rect work_area( + display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); + keyboard_bounds_.SetRect(work_area.x(), + work_area.y() + work_area.height() / 2, + work_area.width(), work_area.height() / 2); + } + + void EnableNewVKMode() { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(::switches::kUseNewVirtualKeyboardBehavior)) + command_line->AppendSwitch(::switches::kUseNewVirtualKeyboardBehavior); + } + + const gfx::Rect& keyboard_bounds() const { return keyboard_bounds_; } + + private: + gfx::Insets restore_work_area_insets_; + gfx::Rect keyboard_bounds_; + WorkspaceLayoutManager* layout_manager_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerKeyboardTest); +}; + +// Tests that when a child window gains focus the top level window containing it +// is resized to fit the remaining workspace area. +TEST_F(WorkspaceLayoutManagerKeyboardTest, ChildWindowFocused) { + InitKeyboardBounds(); + + gfx::Rect work_area( + display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); + + std::unique_ptr<WindowOwner> parent_window_owner( + CreateToplevelTestWindow(work_area)); + WmWindow* parent_window = parent_window_owner->window(); + std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(work_area)); + WmWindow* window = window_owner->window(); + parent_window->AddChild(window); + + window->Activate(); + + int available_height = + display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height() - + keyboard_bounds().height(); + + gfx::Rect initial_window_bounds(50, 50, 100, 500); + parent_window->SetBounds(initial_window_bounds); + EXPECT_EQ(initial_window_bounds.ToString(), + parent_window->GetBounds().ToString()); + ShowKeyboard(); + EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(), + parent_window->GetBounds().ToString()); + HideKeyboard(); + EXPECT_EQ(initial_window_bounds.ToString(), + parent_window->GetBounds().ToString()); +} + +TEST_F(WorkspaceLayoutManagerKeyboardTest, AdjustWindowForA11yKeyboard) { + InitKeyboardBounds(); + gfx::Rect work_area( + display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); + + std::unique_ptr<WindowOwner> window_owner( + CreateToplevelTestWindow(work_area)); + WmWindow* window = window_owner->window(); + // The additional SetBounds() is needed as the aura-mus case uses Widget, + // which alters the supplied bounds. + window->SetBounds(work_area); + + int available_height = + display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height() - + keyboard_bounds().height(); + + window->Activate(); + + EXPECT_EQ(gfx::Rect(work_area).ToString(), window->GetBounds().ToString()); + ShowKeyboard(); + EXPECT_EQ(gfx::Rect(work_area.origin(), + gfx::Size(work_area.width(), available_height)) + .ToString(), + window->GetBounds().ToString()); + HideKeyboard(); + EXPECT_EQ(gfx::Rect(work_area).ToString(), window->GetBounds().ToString()); + + gfx::Rect small_window_bound(50, 50, 100, 500); + window->SetBounds(small_window_bound); + EXPECT_EQ(small_window_bound.ToString(), window->GetBounds().ToString()); + ShowKeyboard(); + EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(), + window->GetBounds().ToString()); + HideKeyboard(); + EXPECT_EQ(small_window_bound.ToString(), window->GetBounds().ToString()); + + gfx::Rect occluded_window_bounds( + 50, keyboard_bounds().y() + keyboard_bounds().height() / 2, 50, + keyboard_bounds().height() / 2); + window->SetBounds(occluded_window_bounds); + EXPECT_EQ(occluded_window_bounds.ToString(), + occluded_window_bounds.ToString()); + ShowKeyboard(); + EXPECT_EQ( + gfx::Rect(50, keyboard_bounds().y() - keyboard_bounds().height() / 2, + occluded_window_bounds.width(), occluded_window_bounds.height()) + .ToString(), + window->GetBounds().ToString()); + HideKeyboard(); + EXPECT_EQ(occluded_window_bounds.ToString(), window->GetBounds().ToString()); +} + +TEST_F(WorkspaceLayoutManagerKeyboardTest, IgnoreKeyboardBoundsChange) { + InitKeyboardBounds(); + + std::unique_ptr<WindowOwner> window_owner( + CreateTestWindow(keyboard_bounds())); + WmWindow* window = window_owner->window(); + // The additional SetBounds() is needed as the aura-mus case uses Widget, + // which alters the supplied bounds. + window->SetBounds(keyboard_bounds()); + window->GetWindowState()->set_ignore_keyboard_bounds_change(true); + window->Activate(); + + EXPECT_EQ(keyboard_bounds(), window->GetBounds()); + ShowKeyboard(); + EXPECT_EQ(keyboard_bounds(), window->GetBounds()); +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/workspace_types.h b/ash/common/wm/workspace/workspace_types.h new file mode 100644 index 0000000..b51eabcc --- /dev/null +++ b/ash/common/wm/workspace/workspace_types.h
@@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_WORKSPACE_TYPES_H_ +#define ASH_COMMON_WM_WORKSPACE_WORKSPACE_TYPES_H_ + +namespace ash { +namespace wm { + +// Enumeration of the possible window states. +enum WorkspaceWindowState { + // There's a full screen window. + WORKSPACE_WINDOW_STATE_FULL_SCREEN, + + // There's a maximized window. + WORKSPACE_WINDOW_STATE_MAXIMIZED, + + // At least one window overlaps the shelf. + WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF, + + // None of the windows are fullscreen, maximized or touch the shelf. + WORKSPACE_WINDOW_STATE_DEFAULT, +}; + +} // namespace wm +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_WORKSPACE_TYPES_H_
diff --git a/ash/common/wm/workspace/workspace_window_resizer.cc b/ash/common/wm/workspace/workspace_window_resizer.cc new file mode 100644 index 0000000..5f66ec57 --- /dev/null +++ b/ash/common/wm/workspace/workspace_window_resizer.cc
@@ -0,0 +1,1021 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace/workspace_window_resizer.h" + +#include <algorithm> +#include <cmath> +#include <utility> +#include <vector> + +#include "ash/common/ash_switches.h" +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/wm/default_window_resizer.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/dock/docked_window_resizer.h" +#include "ash/common/wm/panels/panel_window_resizer.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm/workspace/phantom_window_controller.h" +#include "ash/common/wm/workspace/two_step_edge_cycler.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "base/memory/ptr_util.h" +#include "base/memory/weak_ptr.h" +#include "ui/base/hit_test.h" +#include "ui/compositor/layer.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" +#include "ui/gfx/transform.h" +#include "ui/wm/public/window_types.h" + +namespace ash { + +std::unique_ptr<WindowResizer> CreateWindowResizer( + WmWindow* window, + const gfx::Point& point_in_parent, + int window_component, + aura::client::WindowMoveSource source) { + DCHECK(window); + wm::WindowState* window_state = window->GetWindowState(); + // No need to return a resizer when the window cannot get resized or when a + // resizer already exists for this window. + if ((!window_state->CanResize() && window_component != HTCAPTION) || + window_state->drag_details()) { + return nullptr; + } + + if (window_component == HTCAPTION && !window_state->can_be_dragged()) + return nullptr; + + // TODO(varkha): The chaining of window resizers causes some of the logic + // to be repeated and the logic flow difficult to control. With some windows + // classes using reparenting during drag operations it becomes challenging to + // implement proper transition from one resizer to another during or at the + // end of the drag. This also causes http://crbug.com/247085. + // It seems the only thing the panel or dock resizer needs to do is notify the + // layout manager when a docked window is being dragged. We should have a + // better way of doing this, perhaps by having a way of observing drags or + // having a generic drag window wrapper which informs a layout manager that a + // drag has started or stopped. + // It may be possible to refactor and eliminate chaining. + std::unique_ptr<WindowResizer> window_resizer; + + if (!window_state->IsNormalOrSnapped() && !window_state->IsDocked()) + return std::unique_ptr<WindowResizer>(); + + int bounds_change = + WindowResizer::GetBoundsChangeForWindowComponent(window_component); + if (bounds_change == WindowResizer::kBoundsChangeDirection_None) + return std::unique_ptr<WindowResizer>(); + + window_state->CreateDragDetails(point_in_parent, window_component, source); + const int parent_shell_window_id = + window->GetParent() ? window->GetParent()->GetShellWindowId() : -1; + if (window->GetParent() && + (parent_shell_window_id == kShellWindowId_DefaultContainer || + parent_shell_window_id == kShellWindowId_DockedContainer || + parent_shell_window_id == kShellWindowId_PanelContainer)) { + window_resizer.reset( + WorkspaceWindowResizer::Create(window_state, std::vector<WmWindow*>())); + } else { + window_resizer.reset(DefaultWindowResizer::Create(window_state)); + } + window_resizer = window->GetShell()->CreateDragWindowResizer( + std::move(window_resizer), window_state); + if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL) + window_resizer.reset( + PanelWindowResizer::Create(window_resizer.release(), window_state)); + if (window_resizer && window->GetParent() && !window->GetTransientParent() && + (parent_shell_window_id == kShellWindowId_DefaultContainer || + parent_shell_window_id == kShellWindowId_DockedContainer || + parent_shell_window_id == kShellWindowId_PanelContainer)) { + window_resizer.reset( + DockedWindowResizer::Create(window_resizer.release(), window_state)); + } + return window_resizer; +} + +namespace { + +// Snapping distance used instead of WorkspaceWindowResizer::kScreenEdgeInset +// when resizing a window using touchscreen. +const int kScreenEdgeInsetForTouchDrag = 32; + +// Current instance for use by the WorkspaceWindowResizerTest. +WorkspaceWindowResizer* instance = NULL; + +// Returns true if the window should stick to the edge. +bool ShouldStickToEdge(int distance_from_edge, int sticky_size) { + return distance_from_edge < sticky_size && + distance_from_edge > -sticky_size * 2; +} + +// Returns the coordinate along the secondary axis to snap to. +int CoordinateAlongSecondaryAxis(SecondaryMagnetismEdge edge, + int leading, + int trailing, + int none) { + switch (edge) { + case SECONDARY_MAGNETISM_EDGE_LEADING: + return leading; + case SECONDARY_MAGNETISM_EDGE_TRAILING: + return trailing; + case SECONDARY_MAGNETISM_EDGE_NONE: + return none; + } + NOTREACHED(); + return none; +} + +// Returns the origin for |src| when magnetically attaching to |attach_to| along +// the edges |edges|. |edges| is a bitmask of the MagnetismEdges. +gfx::Point OriginForMagneticAttach(const gfx::Rect& src, + const gfx::Rect& attach_to, + const MatchedEdge& edge) { + int x = 0, y = 0; + switch (edge.primary_edge) { + case MAGNETISM_EDGE_TOP: + y = attach_to.bottom(); + break; + case MAGNETISM_EDGE_LEFT: + x = attach_to.right(); + break; + case MAGNETISM_EDGE_BOTTOM: + y = attach_to.y() - src.height(); + break; + case MAGNETISM_EDGE_RIGHT: + x = attach_to.x() - src.width(); + break; + } + switch (edge.primary_edge) { + case MAGNETISM_EDGE_TOP: + case MAGNETISM_EDGE_BOTTOM: + x = CoordinateAlongSecondaryAxis(edge.secondary_edge, attach_to.x(), + attach_to.right() - src.width(), + src.x()); + break; + case MAGNETISM_EDGE_LEFT: + case MAGNETISM_EDGE_RIGHT: + y = CoordinateAlongSecondaryAxis(edge.secondary_edge, attach_to.y(), + attach_to.bottom() - src.height(), + src.y()); + break; + } + return gfx::Point(x, y); +} + +// Returns the bounds for a magnetic attach when resizing. |src| is the bounds +// of window being resized, |attach_to| the bounds of the window to attach to +// and |edge| identifies the edge to attach to. +gfx::Rect BoundsForMagneticResizeAttach(const gfx::Rect& src, + const gfx::Rect& attach_to, + const MatchedEdge& edge) { + int x = src.x(); + int y = src.y(); + int w = src.width(); + int h = src.height(); + gfx::Point attach_origin(OriginForMagneticAttach(src, attach_to, edge)); + switch (edge.primary_edge) { + case MAGNETISM_EDGE_LEFT: + x = attach_origin.x(); + w = src.right() - x; + break; + case MAGNETISM_EDGE_RIGHT: + w += attach_origin.x() - src.x(); + break; + case MAGNETISM_EDGE_TOP: + y = attach_origin.y(); + h = src.bottom() - y; + break; + case MAGNETISM_EDGE_BOTTOM: + h += attach_origin.y() - src.y(); + break; + } + switch (edge.primary_edge) { + case MAGNETISM_EDGE_LEFT: + case MAGNETISM_EDGE_RIGHT: + if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_LEADING) { + y = attach_origin.y(); + h = src.bottom() - y; + } else if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_TRAILING) { + h += attach_origin.y() - src.y(); + } + break; + case MAGNETISM_EDGE_TOP: + case MAGNETISM_EDGE_BOTTOM: + if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_LEADING) { + x = attach_origin.x(); + w = src.right() - x; + } else if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_TRAILING) { + w += attach_origin.x() - src.x(); + } + break; + } + return gfx::Rect(x, y, w, h); +} + +// Converts a window component edge to the magnetic edge to snap to. +uint32_t WindowComponentToMagneticEdge(int window_component) { + switch (window_component) { + case HTTOPLEFT: + return MAGNETISM_EDGE_LEFT | MAGNETISM_EDGE_TOP; + case HTTOPRIGHT: + return MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_RIGHT; + case HTBOTTOMLEFT: + return MAGNETISM_EDGE_LEFT | MAGNETISM_EDGE_BOTTOM; + case HTBOTTOMRIGHT: + return MAGNETISM_EDGE_RIGHT | MAGNETISM_EDGE_BOTTOM; + case HTTOP: + return MAGNETISM_EDGE_TOP; + case HTBOTTOM: + return MAGNETISM_EDGE_BOTTOM; + case HTRIGHT: + return MAGNETISM_EDGE_RIGHT; + case HTLEFT: + return MAGNETISM_EDGE_LEFT; + default: + break; + } + return 0; +} + +} // namespace + +// static +const int WorkspaceWindowResizer::kMinOnscreenSize = 20; + +// static +const int WorkspaceWindowResizer::kMinOnscreenHeight = 32; + +// static +const int WorkspaceWindowResizer::kScreenEdgeInset = 8; + +WorkspaceWindowResizer* WorkspaceWindowResizer::GetInstanceForTest() { + return instance; +} + +// Represents the width or height of a window with constraints on its minimum +// and maximum size. 0 represents a lack of a constraint. +class WindowSize { + public: + WindowSize(int size, int min, int max) : size_(size), min_(min), max_(max) { + // Grow the min/max bounds to include the starting size. + if (is_underflowing()) + min_ = size_; + if (is_overflowing()) + max_ = size_; + } + + bool is_at_capacity(bool shrinking) const { + return size_ == (shrinking ? min_ : max_); + } + + int size() const { return size_; } + + bool has_min() const { return min_ != 0; } + + bool has_max() const { return max_ != 0; } + + bool is_valid() const { return !is_overflowing() && !is_underflowing(); } + + bool is_overflowing() const { return has_max() && size_ > max_; } + + bool is_underflowing() const { return has_min() && size_ < min_; } + + // Add |amount| to this WindowSize not exceeding min or max size constraints. + // Returns by how much |size_| + |amount| exceeds the min/max constraints. + int Add(int amount) { + DCHECK(is_valid()); + int new_value = size_ + amount; + + if (has_min() && new_value < min_) { + size_ = min_; + return new_value - min_; + } + + if (has_max() && new_value > max_) { + size_ = max_; + return new_value - max_; + } + + size_ = new_value; + return 0; + } + + private: + int size_; + int min_; + int max_; +}; + +WorkspaceWindowResizer::~WorkspaceWindowResizer() { + if (did_lock_cursor_) + shell_->UnlockCursor(); + + if (instance == this) + instance = NULL; +} + +// static +WorkspaceWindowResizer* WorkspaceWindowResizer::Create( + wm::WindowState* window_state, + const std::vector<WmWindow*>& attached_windows) { + return new WorkspaceWindowResizer(window_state, attached_windows); +} + +void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_parent, + int event_flags) { + last_mouse_location_ = location_in_parent; + + int sticky_size; + if (event_flags & ui::EF_CONTROL_DOWN) { + sticky_size = 0; + } else if ((details().bounds_change & kBoundsChange_Resizes) && + details().source == aura::client::WINDOW_MOVE_SOURCE_TOUCH) { + sticky_size = kScreenEdgeInsetForTouchDrag; + } else { + sticky_size = kScreenEdgeInset; + } + // |bounds| is in |GetTarget()->parent()|'s coordinates. + gfx::Rect bounds = CalculateBoundsForDrag(location_in_parent); + AdjustBoundsForMainWindow(sticky_size, &bounds); + + if (bounds != GetTarget()->GetBounds()) { + if (!did_move_or_resize_) { + if (!details().restore_bounds.IsEmpty()) + window_state()->ClearRestoreBounds(); + RestackWindows(); + } + did_move_or_resize_ = true; + } + + gfx::Point location_in_screen = + GetTarget()->GetParent()->ConvertPointToScreen(location_in_parent); + + WmWindow* root = nullptr; + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestPoint(location_in_screen); + // Track the last screen that the pointer was on to keep the snap phantom + // window there. + if (display.bounds().Contains(location_in_screen)) { + root = + Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow(); + } + if (!attached_windows_.empty()) + LayoutAttachedWindows(&bounds); + if (bounds != GetTarget()->GetBounds()) { + // SetBounds needs to be called to update the layout which affects where the + // phantom window is drawn. Keep track if the window was destroyed during + // the drag and quit early if so. + base::WeakPtr<WorkspaceWindowResizer> resizer( + weak_ptr_factory_.GetWeakPtr()); + GetTarget()->SetBounds(bounds); + if (!resizer) + return; + } + const bool in_original_root = !root || root == GetTarget()->GetRootWindow(); + // Hide a phantom window for snapping if the cursor is in another root window. + if (in_original_root) { + UpdateSnapPhantomWindow(location_in_parent, bounds); + } else { + snap_type_ = SNAP_NONE; + snap_phantom_window_controller_.reset(); + edge_cycler_.reset(); + SetDraggedWindowDocked(false); + } +} + +void WorkspaceWindowResizer::CompleteDrag() { + if (!did_move_or_resize_) + return; + + window_state()->set_bounds_changed_by_user(true); + snap_phantom_window_controller_.reset(); + + // If the window's state type changed over the course of the drag do not snap + // the window. This happens when the user minimizes or maximizes the window + // using a keyboard shortcut while dragging it. + if (window_state()->GetStateType() != details().initial_state_type) + return; + + bool snapped = false; + if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { + if (!window_state()->HasRestoreBounds()) { + gfx::Rect initial_bounds = GetTarget()->GetParent()->ConvertRectToScreen( + details().initial_bounds_in_parent); + window_state()->SetRestoreBoundsInScreen( + details().restore_bounds.IsEmpty() ? initial_bounds + : details().restore_bounds); + } + if (!dock_layout_->is_dragged_window_docked()) { + // TODO(oshima): Add event source type to WMEvent and move + // metrics recording inside WindowState::OnWMEvent. + const wm::WMEvent event(snap_type_ == SNAP_LEFT + ? wm::WM_EVENT_SNAP_LEFT + : wm::WM_EVENT_SNAP_RIGHT); + window_state()->OnWMEvent(&event); + shell_->RecordUserMetricsAction(snap_type_ == SNAP_LEFT + ? UMA_DRAG_MAXIMIZE_LEFT + : UMA_DRAG_MAXIMIZE_RIGHT); + snapped = true; + } + } + + if (!snapped) { + if (window_state()->IsSnapped()) { + // Keep the window snapped if the user resizes the window such that the + // window has valid bounds for a snapped window. Always unsnap the window + // if the user dragged the window via the caption area because doing this + // is slightly less confusing. + if (details().window_component == HTCAPTION || + !AreBoundsValidSnappedBounds(window_state()->GetStateType(), + GetTarget()->GetBounds())) { + // Set the window to WINDOW_STATE_TYPE_NORMAL but keep the + // window at the bounds that the user has moved/resized the + // window to. + window_state()->SaveCurrentBoundsForRestore(); + window_state()->Restore(); + } + } else if (!dock_layout_->is_dragged_window_docked()) { + // The window was not snapped and is not snapped. This is a user + // resize/drag and so the current bounds should be maintained, clearing + // any prior restore bounds. When the window is docked the restore bound + // must be kept so the docked state can be reverted properly. + window_state()->ClearRestoreBounds(); + } + } +} + +void WorkspaceWindowResizer::RevertDrag() { + window_state()->set_bounds_changed_by_user(initial_bounds_changed_by_user_); + snap_phantom_window_controller_.reset(); + + if (!did_move_or_resize_) + return; + + GetTarget()->SetBounds(details().initial_bounds_in_parent); + if (!details().restore_bounds.IsEmpty()) + window_state()->SetRestoreBoundsInScreen(details().restore_bounds); + + if (details().window_component == HTRIGHT) { + int last_x = details().initial_bounds_in_parent.right(); + for (size_t i = 0; i < attached_windows_.size(); ++i) { + gfx::Rect bounds(attached_windows_[i]->GetBounds()); + bounds.set_x(last_x); + bounds.set_width(initial_size_[i]); + attached_windows_[i]->SetBounds(bounds); + last_x = attached_windows_[i]->GetBounds().right(); + } + } else { + int last_y = details().initial_bounds_in_parent.bottom(); + for (size_t i = 0; i < attached_windows_.size(); ++i) { + gfx::Rect bounds(attached_windows_[i]->GetBounds()); + bounds.set_y(last_y); + bounds.set_height(initial_size_[i]); + attached_windows_[i]->SetBounds(bounds); + last_y = attached_windows_[i]->GetBounds().bottom(); + } + } +} + +WorkspaceWindowResizer::WorkspaceWindowResizer( + wm::WindowState* window_state, + const std::vector<WmWindow*>& attached_windows) + : WindowResizer(window_state), + attached_windows_(attached_windows), + shell_(window_state->window()->GetShell()), + did_lock_cursor_(false), + did_move_or_resize_(false), + initial_bounds_changed_by_user_(window_state_->bounds_changed_by_user()), + total_min_(0), + total_initial_size_(0), + snap_type_(SNAP_NONE), + num_mouse_moves_since_bounds_change_(0), + magnetism_window_(NULL), + weak_ptr_factory_(this) { + DCHECK(details().is_resizable); + + // A mousemove should still show the cursor even if the window is + // being moved or resized with touch, so do not lock the cursor. + if (details().source != aura::client::WINDOW_MOVE_SOURCE_TOUCH) { + shell_->LockCursor(); + did_lock_cursor_ = true; + } + + dock_layout_ = DockedWindowLayoutManager::Get(GetTarget()); + + // Only support attaching to the right/bottom. + DCHECK(attached_windows_.empty() || (details().window_component == HTRIGHT || + details().window_component == HTBOTTOM)); + + // TODO: figure out how to deal with window going off the edge. + + // Calculate sizes so that we can maintain the ratios if we need to resize. + int total_available = 0; + for (size_t i = 0; i < attached_windows_.size(); ++i) { + gfx::Size min(attached_windows_[i]->GetMinimumSize()); + int initial_size = + PrimaryAxisSize(attached_windows_[i]->GetBounds().size()); + initial_size_.push_back(initial_size); + // If current size is smaller than the min, use the current size as the min. + // This way we don't snap on resize. + int min_size = std::min(initial_size, + std::max(PrimaryAxisSize(min), kMinOnscreenSize)); + total_min_ += min_size; + total_initial_size_ += initial_size; + total_available += std::max(min_size, initial_size) - min_size; + } + instance = this; +} + +void WorkspaceWindowResizer::LayoutAttachedWindows(gfx::Rect* bounds) { + gfx::Rect work_area(wm::GetDisplayWorkAreaBoundsInParent(GetTarget())); + int initial_size = PrimaryAxisSize(details().initial_bounds_in_parent.size()); + int current_size = PrimaryAxisSize(bounds->size()); + int start = PrimaryAxisCoordinate(bounds->right(), bounds->bottom()); + int end = PrimaryAxisCoordinate(work_area.right(), work_area.bottom()); + + int delta = current_size - initial_size; + int available_size = end - start; + std::vector<int> sizes; + int leftovers = CalculateAttachedSizes(delta, available_size, &sizes); + + // leftovers > 0 means that the attached windows can't grow to compensate for + // the shrinkage of the main window. This line causes the attached windows to + // be moved so they are still flush against the main window, rather than the + // main window being prevented from shrinking. + leftovers = std::min(0, leftovers); + // Reallocate any leftover pixels back into the main window. This is + // necessary when, for example, the main window shrinks, but none of the + // attached windows can grow without exceeding their max size constraints. + // Adding the pixels back to the main window effectively prevents the main + // window from resizing too far. + if (details().window_component == HTRIGHT) + bounds->set_width(bounds->width() + leftovers); + else + bounds->set_height(bounds->height() + leftovers); + + DCHECK_EQ(attached_windows_.size(), sizes.size()); + int last = PrimaryAxisCoordinate(bounds->right(), bounds->bottom()); + for (size_t i = 0; i < attached_windows_.size(); ++i) { + gfx::Rect attached_bounds(attached_windows_[i]->GetBounds()); + if (details().window_component == HTRIGHT) { + attached_bounds.set_x(last); + attached_bounds.set_width(sizes[i]); + } else { + attached_bounds.set_y(last); + attached_bounds.set_height(sizes[i]); + } + attached_windows_[i]->SetBounds(attached_bounds); + last += sizes[i]; + } +} + +int WorkspaceWindowResizer::CalculateAttachedSizes( + int delta, + int available_size, + std::vector<int>* sizes) const { + std::vector<WindowSize> window_sizes; + CreateBucketsForAttached(&window_sizes); + + // How much we need to grow the attached by (collectively). + int grow_attached_by = 0; + if (delta > 0) { + // If the attached windows don't fit when at their initial size, we will + // have to shrink them by how much they overflow. + if (total_initial_size_ >= available_size) + grow_attached_by = available_size - total_initial_size_; + } else { + // If we're shrinking, we grow the attached so the total size remains + // constant. + grow_attached_by = -delta; + } + + int leftover_pixels = 0; + while (grow_attached_by != 0) { + int leftovers = GrowFairly(grow_attached_by, &window_sizes); + if (leftovers == grow_attached_by) { + leftover_pixels = leftovers; + break; + } + grow_attached_by = leftovers; + } + + for (size_t i = 0; i < window_sizes.size(); ++i) + sizes->push_back(window_sizes[i].size()); + + return leftover_pixels; +} + +int WorkspaceWindowResizer::GrowFairly(int pixels, + std::vector<WindowSize>* sizes) const { + bool shrinking = pixels < 0; + std::vector<WindowSize*> nonfull_windows; + for (size_t i = 0; i < sizes->size(); ++i) { + WindowSize& current_window_size = (*sizes)[i]; + if (!current_window_size.is_at_capacity(shrinking)) + nonfull_windows.push_back(¤t_window_size); + } + std::vector<float> ratios; + CalculateGrowthRatios(nonfull_windows, &ratios); + + int remaining_pixels = pixels; + bool add_leftover_pixels_to_last = true; + for (size_t i = 0; i < nonfull_windows.size(); ++i) { + int grow_by = pixels * ratios[i]; + // Put any leftover pixels into the last window. + if (i == nonfull_windows.size() - 1 && add_leftover_pixels_to_last) + grow_by = remaining_pixels; + int remainder = nonfull_windows[i]->Add(grow_by); + int consumed = grow_by - remainder; + remaining_pixels -= consumed; + if (nonfull_windows[i]->is_at_capacity(shrinking) && remainder > 0) { + // Because this window overflowed, some of the pixels in + // |remaining_pixels| aren't there due to rounding errors. Rather than + // unfairly giving all those pixels to the last window, we refrain from + // allocating them so that this function can be called again to distribute + // the pixels fairly. + add_leftover_pixels_to_last = false; + } + } + return remaining_pixels; +} + +void WorkspaceWindowResizer::CalculateGrowthRatios( + const std::vector<WindowSize*>& sizes, + std::vector<float>* out_ratios) const { + DCHECK(out_ratios->empty()); + int total_value = 0; + for (size_t i = 0; i < sizes.size(); ++i) + total_value += sizes[i]->size(); + + for (size_t i = 0; i < sizes.size(); ++i) + out_ratios->push_back((static_cast<float>(sizes[i]->size())) / total_value); +} + +void WorkspaceWindowResizer::CreateBucketsForAttached( + std::vector<WindowSize>* sizes) const { + for (size_t i = 0; i < attached_windows_.size(); i++) { + int initial_size = initial_size_[i]; + int min = PrimaryAxisSize(attached_windows_[i]->GetMinimumSize()); + int max = PrimaryAxisSize(attached_windows_[i]->GetMaximumSize()); + + sizes->push_back(WindowSize(initial_size, min, max)); + } +} + +void WorkspaceWindowResizer::MagneticallySnapToOtherWindows(gfx::Rect* bounds) { + if (UpdateMagnetismWindow(*bounds, kAllMagnetismEdges)) { + gfx::Point point = OriginForMagneticAttach( + GetTarget()->GetParent()->ConvertRectToScreen(*bounds), + magnetism_window_->GetBoundsInScreen(), magnetism_edge_); + point = GetTarget()->GetParent()->ConvertPointFromScreen(point); + bounds->set_origin(point); + } +} + +void WorkspaceWindowResizer::MagneticallySnapResizeToOtherWindows( + gfx::Rect* bounds) { + const uint32_t edges = + WindowComponentToMagneticEdge(details().window_component); + if (UpdateMagnetismWindow(*bounds, edges)) { + *bounds = GetTarget()->GetParent()->ConvertRectFromScreen( + BoundsForMagneticResizeAttach( + GetTarget()->GetParent()->ConvertRectToScreen(*bounds), + magnetism_window_->GetBoundsInScreen(), magnetism_edge_)); + } +} + +bool WorkspaceWindowResizer::UpdateMagnetismWindow(const gfx::Rect& bounds, + uint32_t edges) { + // |bounds| are in coordinates of original window's parent. + gfx::Rect bounds_in_screen = + GetTarget()->GetParent()->ConvertRectToScreen(bounds); + MagnetismMatcher matcher(bounds_in_screen, edges); + + // If we snapped to a window then check it first. That way we don't bounce + // around when close to multiple edges. + if (magnetism_window_) { + if (window_tracker_.Contains(magnetism_window_->aura_window()) && + matcher.ShouldAttach(magnetism_window_->GetBoundsInScreen(), + &magnetism_edge_)) { + return true; + } + window_tracker_.Remove(magnetism_window_->aura_window()); + magnetism_window_ = NULL; + } + + // Avoid magnetically snapping windows that are not resizable. + // TODO(oshima): change this to window.type() == TYPE_NORMAL. + if (!window_state()->CanResize()) + return false; + + for (WmWindow* root_window : shell_->GetAllRootWindows()) { + // Test all children from the desktop in each root window. + const std::vector<WmWindow*> children = + root_window->GetChildByShellWindowId(kShellWindowId_DefaultContainer) + ->GetChildren(); + for (auto i = children.rbegin(); + i != children.rend() && !matcher.AreEdgesObscured(); ++i) { + wm::WindowState* other_state = (*i)->GetWindowState(); + if (other_state->window() == GetTarget() || + !other_state->window()->IsVisible() || + !other_state->IsNormalOrSnapped() || !other_state->CanResize()) { + continue; + } + if (matcher.ShouldAttach(other_state->window()->GetBoundsInScreen(), + &magnetism_edge_)) { + magnetism_window_ = other_state->window(); + window_tracker_.Add(magnetism_window_->aura_window()); + return true; + } + } + } + return false; +} + +void WorkspaceWindowResizer::AdjustBoundsForMainWindow(int sticky_size, + gfx::Rect* bounds) { + gfx::Point last_mouse_location_in_screen = + GetTarget()->GetParent()->ConvertPointToScreen(last_mouse_location_); + display::Display display = + display::Screen::GetScreen()->GetDisplayNearestPoint( + last_mouse_location_in_screen); + gfx::Rect work_area = + GetTarget()->GetParent()->ConvertRectFromScreen(display.work_area()); + if (details().window_component == HTCAPTION) { + // Adjust the bounds to the work area where the mouse cursor is located. + // Always keep kMinOnscreenHeight or the window height (whichever is less) + // on the bottom. + int max_y = + work_area.bottom() - std::min(kMinOnscreenHeight, bounds->height()); + if (bounds->y() > max_y) { + bounds->set_y(max_y); + } else if (bounds->y() <= work_area.y()) { + // Don't allow dragging above the top of the display until the mouse + // cursor reaches the work area above if any. + bounds->set_y(work_area.y()); + } + + if (sticky_size > 0) { + // Possibly stick to edge except when a mouse pointer is outside the + // work area. + if (display.work_area().Contains(last_mouse_location_in_screen)) + StickToWorkAreaOnMove(work_area, sticky_size, bounds); + MagneticallySnapToOtherWindows(bounds); + } + } else if (sticky_size > 0) { + MagneticallySnapResizeToOtherWindows(bounds); + if (!magnetism_window_ && sticky_size > 0) + StickToWorkAreaOnResize(work_area, sticky_size, bounds); + } + + if (attached_windows_.empty()) + return; + + if (details().window_component == HTRIGHT) { + bounds->set_width(std::min(bounds->width(), + work_area.right() - total_min_ - bounds->x())); + } else { + DCHECK_EQ(HTBOTTOM, details().window_component); + bounds->set_height(std::min(bounds->height(), + work_area.bottom() - total_min_ - bounds->y())); + } +} + +bool WorkspaceWindowResizer::StickToWorkAreaOnMove(const gfx::Rect& work_area, + int sticky_size, + gfx::Rect* bounds) const { + const int left_edge = work_area.x(); + const int right_edge = work_area.right(); + const int top_edge = work_area.y(); + const int bottom_edge = work_area.bottom(); + bool updated = false; + if (ShouldStickToEdge(bounds->x() - left_edge, sticky_size)) { + bounds->set_x(left_edge); + updated = true; + } else if (ShouldStickToEdge(right_edge - bounds->right(), sticky_size)) { + bounds->set_x(right_edge - bounds->width()); + updated = true; + } + if (ShouldStickToEdge(bounds->y() - top_edge, sticky_size)) { + bounds->set_y(top_edge); + updated = true; + } else if (ShouldStickToEdge(bottom_edge - bounds->bottom(), sticky_size) && + bounds->height() < (bottom_edge - top_edge)) { + // Only snap to the bottom if the window is smaller than the work area. + // Doing otherwise can lead to window snapping in weird ways as it bounces + // between snapping to top then bottom. + bounds->set_y(bottom_edge - bounds->height()); + updated = true; + } + return updated; +} + +void WorkspaceWindowResizer::StickToWorkAreaOnResize(const gfx::Rect& work_area, + int sticky_size, + gfx::Rect* bounds) const { + const uint32_t edges = + WindowComponentToMagneticEdge(details().window_component); + const int left_edge = work_area.x(); + const int right_edge = work_area.right(); + const int top_edge = work_area.y(); + const int bottom_edge = work_area.bottom(); + if (edges & MAGNETISM_EDGE_TOP && + ShouldStickToEdge(bounds->y() - top_edge, sticky_size)) { + bounds->set_height(bounds->bottom() - top_edge); + bounds->set_y(top_edge); + } + if (edges & MAGNETISM_EDGE_LEFT && + ShouldStickToEdge(bounds->x() - left_edge, sticky_size)) { + bounds->set_width(bounds->right() - left_edge); + bounds->set_x(left_edge); + } + if (edges & MAGNETISM_EDGE_BOTTOM && + ShouldStickToEdge(bottom_edge - bounds->bottom(), sticky_size)) { + bounds->set_height(bottom_edge - bounds->y()); + } + if (edges & MAGNETISM_EDGE_RIGHT && + ShouldStickToEdge(right_edge - bounds->right(), sticky_size)) { + bounds->set_width(right_edge - bounds->x()); + } +} + +int WorkspaceWindowResizer::PrimaryAxisSize(const gfx::Size& size) const { + return PrimaryAxisCoordinate(size.width(), size.height()); +} + +int WorkspaceWindowResizer::PrimaryAxisCoordinate(int x, int y) const { + switch (details().window_component) { + case HTRIGHT: + return x; + case HTBOTTOM: + return y; + default: + NOTREACHED(); + } + return 0; +} + +void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, + const gfx::Rect& bounds) { + if (!did_move_or_resize_ || details().window_component != HTCAPTION) + return; + + SnapType last_type = snap_type_; + snap_type_ = GetSnapType(location); + if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { + snap_phantom_window_controller_.reset(); + edge_cycler_.reset(); + if (snap_type_ == SNAP_NONE) { + SetDraggedWindowDocked(false); + return; + } + } + + DCHECK(snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT); + DockedAlignment desired_alignment = (snap_type_ == SNAP_LEFT) + ? DOCKED_ALIGNMENT_LEFT + : DOCKED_ALIGNMENT_RIGHT; + const bool can_dock = + ash::switches::DockedWindowsEnabled() && + dock_layout_->CanDockWindow(GetTarget(), desired_alignment) && + dock_layout_->GetAlignmentOfWindow(GetTarget()) != DOCKED_ALIGNMENT_NONE; + if (!can_dock) { + // If the window cannot be docked, undock the window. This may change the + // workspace bounds and hence |snap_type_|. + SetDraggedWindowDocked(false); + snap_type_ = GetSnapType(location); + } + const bool can_snap = snap_type_ != SNAP_NONE && window_state()->CanSnap(); + if (!can_snap && !can_dock) { + snap_type_ = SNAP_NONE; + snap_phantom_window_controller_.reset(); + edge_cycler_.reset(); + return; + } + if (!edge_cycler_) { + edge_cycler_.reset(new TwoStepEdgeCycler( + location, snap_type_ == SNAP_LEFT + ? TwoStepEdgeCycler::DIRECTION_LEFT + : TwoStepEdgeCycler::DIRECTION_RIGHT)); + } else { + edge_cycler_->OnMove(location); + } + + // Update phantom window with snapped or docked guide bounds. + // Windows that cannot be snapped or are less wide than kMaxDockWidth can get + // docked without going through a snapping sequence. + gfx::Rect phantom_bounds; + const bool should_dock = + can_dock && (!can_snap || + GetTarget()->GetBounds().width() <= + DockedWindowLayoutManager::kMaxDockWidth || + edge_cycler_->use_second_mode() || + dock_layout_->is_dragged_window_docked()); + if (should_dock) { + SetDraggedWindowDocked(true); + phantom_bounds = GetTarget()->GetParent()->ConvertRectFromScreen( + dock_layout_->dragged_bounds()); + } else { + phantom_bounds = + (snap_type_ == SNAP_LEFT) + ? wm::GetDefaultLeftSnappedWindowBoundsInParent(GetTarget()) + : wm::GetDefaultRightSnappedWindowBoundsInParent(GetTarget()); + } + + if (!snap_phantom_window_controller_) { + snap_phantom_window_controller_.reset( + new PhantomWindowController(GetTarget())); + } + snap_phantom_window_controller_->Show( + GetTarget()->GetParent()->ConvertRectToScreen(phantom_bounds)); +} + +void WorkspaceWindowResizer::RestackWindows() { + if (attached_windows_.empty()) + return; + // Build a map from index in children to window, returning if there is a + // window with a different parent. + using IndexToWindowMap = std::map<size_t, WmWindow*>; + IndexToWindowMap map; + WmWindow* parent = GetTarget()->GetParent(); + const std::vector<WmWindow*> windows(parent->GetChildren()); + map[std::find(windows.begin(), windows.end(), GetTarget()) - + windows.begin()] = GetTarget(); + for (auto i = attached_windows_.begin(); i != attached_windows_.end(); ++i) { + if ((*i)->GetParent() != parent) + return; + size_t index = + std::find(windows.begin(), windows.end(), *i) - windows.begin(); + map[index] = *i; + } + + // Reorder the windows starting at the topmost. + parent->StackChildAtTop(map.rbegin()->second); + for (auto i = map.rbegin(); i != map.rend();) { + WmWindow* window = i->second; + ++i; + if (i != map.rend()) + parent->StackChildBelow(i->second, window); + } +} + +WorkspaceWindowResizer::SnapType WorkspaceWindowResizer::GetSnapType( + const gfx::Point& location) const { + // TODO: this likely only wants total display area, not the area of a single + // display. + gfx::Rect area(wm::GetDisplayWorkAreaBoundsInParent(GetTarget())); + if (details().source == aura::client::WINDOW_MOVE_SOURCE_TOUCH) { + // Increase tolerance for touch-snapping near the screen edges. This is only + // necessary when the work area left or right edge is same as screen edge. + gfx::Rect display_bounds(wm::GetDisplayBoundsInParent(GetTarget())); + int inset_left = 0; + if (area.x() == display_bounds.x()) + inset_left = kScreenEdgeInsetForTouchDrag; + int inset_right = 0; + if (area.right() == display_bounds.right()) + inset_right = kScreenEdgeInsetForTouchDrag; + area.Inset(inset_left, 0, inset_right, 0); + } + if (location.x() <= area.x()) + return SNAP_LEFT; + if (location.x() >= area.right() - 1) + return SNAP_RIGHT; + return SNAP_NONE; +} + +void WorkspaceWindowResizer::SetDraggedWindowDocked(bool should_dock) { + if (should_dock) { + if (!dock_layout_->is_dragged_window_docked()) { + window_state()->set_bounds_changed_by_user(false); + dock_layout_->DockDraggedWindow(GetTarget()); + } + } else { + if (dock_layout_->is_dragged_window_docked()) { + dock_layout_->UndockDraggedWindow(); + window_state()->set_bounds_changed_by_user(true); + } + } +} + +bool WorkspaceWindowResizer::AreBoundsValidSnappedBounds( + wm::WindowStateType snapped_type, + const gfx::Rect& bounds_in_parent) const { + DCHECK(snapped_type == wm::WINDOW_STATE_TYPE_LEFT_SNAPPED || + snapped_type == wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED); + gfx::Rect snapped_bounds = wm::GetDisplayWorkAreaBoundsInParent(GetTarget()); + if (snapped_type == wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED) + snapped_bounds.set_x(snapped_bounds.right() - bounds_in_parent.width()); + snapped_bounds.set_width(bounds_in_parent.width()); + return bounds_in_parent == snapped_bounds; +} + +} // namespace ash
diff --git a/ash/common/wm/workspace/workspace_window_resizer.h b/ash/common/wm/workspace/workspace_window_resizer.h new file mode 100644 index 0000000..03b027d --- /dev/null +++ b/ash/common/wm/workspace/workspace_window_resizer.h
@@ -0,0 +1,230 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_ +#define ASH_COMMON_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_ + +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/workspace/magnetism_matcher.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "ui/aura/window_tracker.h" + +namespace ash { +class DockedWindowLayoutManager; +class PhantomWindowController; +class TwoStepEdgeCycler; +class WindowSize; +class WmShell; + +namespace wm { +class WindowState; +} + +// WindowResizer implementation for workspaces. This enforces that windows are +// not allowed to vertically move or resize outside of the work area. As windows +// are moved outside the work area they are shrunk. We remember the height of +// the window before it was moved so that if the window is again moved up we +// attempt to restore the old height. +class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { + public: + // When dragging an attached window this is the min size we'll make sure is + // visible. In the vertical direction we take the max of this and that from + // the delegate. + static const int kMinOnscreenSize; + + // Min height we'll force on screen when dragging the caption. + // TODO: this should come from a property on the window. + static const int kMinOnscreenHeight; + + // Snap region when dragging close to the edges. That is, as the window gets + // this close to an edge of the screen it snaps to the edge. + static const int kScreenEdgeInset; + + // Distance in pixels that the cursor must move past an edge for a window + // to move or resize beyond that edge. + static const int kStickyDistancePixels; + + ~WorkspaceWindowResizer() override; + + static WorkspaceWindowResizer* Create( + wm::WindowState* window_state, + const std::vector<WmWindow*>& attached_windows); + + // WindowResizer: + void Drag(const gfx::Point& location_in_parent, int event_flags) override; + void CompleteDrag() override; + void RevertDrag() override; + + private: + friend class WorkspaceWindowResizerTest; + + // The edge to which the window should be snapped at the end of the drag. + enum SnapType { SNAP_LEFT, SNAP_RIGHT, SNAP_NONE }; + + WorkspaceWindowResizer(wm::WindowState* window_state, + const std::vector<WmWindow*>& attached_windows); + + // Lays out the attached windows. |bounds| is the bounds of the main window. + void LayoutAttachedWindows(gfx::Rect* bounds); + + // Calculates the new sizes of the attached windows, given that the main + // window has been resized (along the primary axis) by |delta|. + // |available_size| is the maximum length of the space that the attached + // windows are allowed to occupy (ie: the distance between the right/bottom + // edge of the primary window and the right/bottom of the desktop area). + // Populates |sizes| with the desired sizes of the attached windows, and + // returns the number of pixels that couldn't be allocated to the attached + // windows (due to min/max size constraints). + // Note the return value can be positive or negative, a negative value + // indicating that that many pixels couldn't be removed from the attached + // windows. + int CalculateAttachedSizes(int delta, + int available_size, + std::vector<int>* sizes) const; + + // Divides |amount| evenly between |sizes|. If |amount| is negative it + // indicates how many pixels |sizes| should be shrunk by. + // Returns how many pixels failed to be allocated/removed from |sizes|. + int GrowFairly(int amount, std::vector<WindowSize>* sizes) const; + + // Calculate the ratio of pixels that each WindowSize in |sizes| should + // receive when growing or shrinking. + void CalculateGrowthRatios(const std::vector<WindowSize*>& sizes, + std::vector<float>* out_ratios) const; + + // Adds a WindowSize to |sizes| for each attached window. + void CreateBucketsForAttached(std::vector<WindowSize>* sizes) const; + + // If possible snaps the window to a neary window. Updates |bounds| if there + // was a close enough window. + void MagneticallySnapToOtherWindows(gfx::Rect* bounds); + + // If possible snaps the resize to a neary window. Updates |bounds| if there + // was a close enough window. + void MagneticallySnapResizeToOtherWindows(gfx::Rect* bounds); + + // Finds the neareset window to magentically snap to. Updates + // |magnetism_window_| and |magnetism_edge_| appropriately. |edges| is a + // bitmask of the MagnetismEdges to match again. Returns true if a match is + // found. + bool UpdateMagnetismWindow(const gfx::Rect& bounds, uint32_t edges); + + // Adjusts the bounds of the window: magnetically snapping, ensuring the + // window has enough on screen... |snap_size| is the distance from an edge of + // the work area before the window is snapped. A value of 0 results in no + // snapping. + void AdjustBoundsForMainWindow(int snap_size, gfx::Rect* bounds); + + // Stick the window bounds to the work area during a move. + bool StickToWorkAreaOnMove(const gfx::Rect& work_area, + int sticky_size, + gfx::Rect* bounds) const; + + // Stick the window bounds to the work area during a resize. + void StickToWorkAreaOnResize(const gfx::Rect& work_area, + int sticky_size, + gfx::Rect* bounds) const; + + // Returns a coordinate along the primary axis. Used to share code for + // left/right multi window resize and top/bottom resize. + int PrimaryAxisSize(const gfx::Size& size) const; + int PrimaryAxisCoordinate(int x, int y) const; + + // Updates the bounds of the phantom window for window snapping. + void UpdateSnapPhantomWindow(const gfx::Point& location, + const gfx::Rect& bounds); + + // Restacks the windows z-order position so that one of the windows is at the + // top of the z-order, and the rest directly underneath it. + void RestackWindows(); + + // Returns the edge to which the window should be snapped to if the user does + // no more dragging. SNAP_NONE is returned if the window should not be + // snapped. + SnapType GetSnapType(const gfx::Point& location) const; + + // Returns true if |bounds_in_parent| are valid bounds for snapped state type + // |snapped_type|. + bool AreBoundsValidSnappedBounds(wm::WindowStateType snapped_type, + const gfx::Rect& bounds_in_parent) const; + + // Docks or undocks the dragged window. + void SetDraggedWindowDocked(bool should_dock); + + wm::WindowState* window_state() { return window_state_; } + + const std::vector<WmWindow*> attached_windows_; + + WmShell* shell_; + + // Returns the currently used instance for test. + static WorkspaceWindowResizer* GetInstanceForTest(); + + bool did_lock_cursor_; + + // Set to true once Drag() is invoked and the bounds of the window change. + bool did_move_or_resize_; + + // True if the window initially had |bounds_changed_by_user_| set in state. + bool initial_bounds_changed_by_user_; + + // The initial size of each of the windows in |attached_windows_| along the + // primary axis. + std::vector<int> initial_size_; + + // Sum of the minimum sizes of the attached windows. + int total_min_; + + // Sum of the sizes in |initial_size_|. + int total_initial_size_; + + // Gives a previews of where the the window will end up. Only used if there + // is a grid and the caption is being dragged. + std::unique_ptr<PhantomWindowController> snap_phantom_window_controller_; + + // Used to determine whether the window should be snapped or docked when + // the user drags a window to the edge of the screen. + std::unique_ptr<TwoStepEdgeCycler> edge_cycler_; + + // The edge to which the window should be snapped to at the end of the drag. + SnapType snap_type_; + + // Number of mouse moves since the last bounds change. Only used for phantom + // placement to track when the mouse is moved while pushed against the edge of + // the screen. + int num_mouse_moves_since_bounds_change_; + + // The mouse location passed to Drag(). + gfx::Point last_mouse_location_; + + // Window the drag has magnetically attached to. + WmWindow* magnetism_window_; + + // Used to verify |magnetism_window_| is still valid. + aura::WindowTracker window_tracker_; + + // If |magnetism_window_| is non-NULL this indicates how the two windows + // should attach. + MatchedEdge magnetism_edge_; + + // Dock container window layout manager. + DockedWindowLayoutManager* dock_layout_; + + // Used to determine if this has been deleted during a drag such as when a tab + // gets dragged into another browser window. + base::WeakPtrFactory<WorkspaceWindowResizer> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizer); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_
diff --git a/ash/common/wm/workspace_controller.cc b/ash/common/wm/workspace_controller.cc new file mode 100644 index 0000000..09f742b --- /dev/null +++ b/ash/common/wm/workspace_controller.cc
@@ -0,0 +1,134 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/common/wm/workspace_controller.h" + +#include <utility> + +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/fullscreen_window_finder.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_window_animations.h" +#include "ash/common/wm/workspace/workspace_event_handler.h" +#include "ash/common/wm/workspace/workspace_layout_manager.h" +#include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/common/wm_window.h" +#include "ash/public/cpp/shell_window_ids.h" +#include "ash/root_window_controller.h" +#include "base/memory/ptr_util.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" + +namespace ash { +namespace { + +// Amount of time to pause before animating anything. Only used during initial +// animation (when logging in). +const int kInitialPauseTimeMS = 750; + +// The duration of the animation that occurs on first login. +const int kInitialAnimationDurationMS = 200; + +} // namespace + +WorkspaceController::WorkspaceController(WmWindow* viewport) + : viewport_(viewport), + event_handler_(WmShell::Get()->CreateWorkspaceEventHandler(viewport)), + layout_manager_(new WorkspaceLayoutManager(viewport)) { + viewport_->aura_window()->AddObserver(this); + viewport_->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); + viewport_->SetLayoutManager(base::WrapUnique(layout_manager_)); +} + +WorkspaceController::~WorkspaceController() { + if (!viewport_) + return; + + viewport_->aura_window()->RemoveObserver(this); + viewport_->SetLayoutManager(nullptr); +} + +wm::WorkspaceWindowState WorkspaceController::GetWindowState() const { + if (!viewport_ || !viewport_->GetRootWindowController()->HasShelf()) + return wm::WORKSPACE_WINDOW_STATE_DEFAULT; + + const WmWindow* fullscreen = wm::GetWindowForFullscreenMode(viewport_); + if (fullscreen && !fullscreen->GetWindowState()->ignored_by_shelf()) + return wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN; + + // These are the container ids of containers which may contain windows that + // may overlap the launcher shelf and affect its transparency. + const int kWindowContainerIds[] = { + kShellWindowId_DefaultContainer, kShellWindowId_DockedContainer, + }; + const gfx::Rect shelf_bounds(WmShelf::ForWindow(viewport_)->GetIdealBounds()); + bool window_overlaps_launcher = false; + for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) { + WmWindow* container = viewport_->GetRootWindow()->GetChildByShellWindowId( + kWindowContainerIds[i]); + for (WmWindow* window : container->GetChildren()) { + wm::WindowState* window_state = window->GetWindowState(); + if (window_state->ignored_by_shelf() || + (window->GetLayer() && !window->GetLayer()->GetTargetVisibility())) { + continue; + } + if (window_state->IsMaximized()) + return wm::WORKSPACE_WINDOW_STATE_MAXIMIZED; + window_overlaps_launcher |= window->GetBounds().Intersects(shelf_bounds); + } + } + + // Check if there are visible docked windows in the same display. + DockedWindowLayoutManager* dock = DockedWindowLayoutManager::Get(viewport_); + const bool docked_area_visible = dock && !dock->docked_bounds().IsEmpty(); + return (window_overlaps_launcher || docked_area_visible) + ? wm::WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF + : wm::WORKSPACE_WINDOW_STATE_DEFAULT; +} + +void WorkspaceController::DoInitialAnimation() { + viewport_->Show(); + + ui::Layer* layer = viewport_->GetLayer(); + layer->SetOpacity(0.0f); + SetTransformForScaleAnimation(layer, LAYER_SCALE_ANIMATION_ABOVE); + + // In order for pause to work we need to stop animations. + layer->GetAnimator()->StopAnimating(); + + { + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + + settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); + layer->GetAnimator()->SchedulePauseForProperties( + base::TimeDelta::FromMilliseconds(kInitialPauseTimeMS), + ui::LayerAnimationElement::TRANSFORM | + ui::LayerAnimationElement::OPACITY | + ui::LayerAnimationElement::BRIGHTNESS | + ui::LayerAnimationElement::VISIBILITY); + settings.SetTweenType(gfx::Tween::EASE_OUT); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kInitialAnimationDurationMS)); + layer->SetTransform(gfx::Transform()); + layer->SetOpacity(1.0f); + } +} + +void WorkspaceController::SetMaximizeBackdropDelegate( + std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate) { + layout_manager_->SetMaximizeBackdropDelegate(std::move(delegate)); +} + +void WorkspaceController::OnWindowDestroying(aura::Window* window) { + DCHECK_EQ(WmWindow::Get(window), viewport_); + viewport_->aura_window()->RemoveObserver(this); + viewport_ = nullptr; + // Destroy |event_handler_| too as it depends upon |window|. + event_handler_.reset(); + layout_manager_ = nullptr; +} + +} // namespace ash
diff --git a/ash/common/wm/workspace_controller.h b/ash/common/wm/workspace_controller.h new file mode 100644 index 0000000..d37fe68 --- /dev/null +++ b/ash/common/wm/workspace_controller.h
@@ -0,0 +1,60 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_COMMON_WM_WORKSPACE_CONTROLLER_H_ +#define ASH_COMMON_WM_WORKSPACE_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/wm/workspace/workspace_types.h" +#include "base/macros.h" +#include "ui/aura/window_observer.h" + +namespace ash { +class WmWindow; +class WorkspaceControllerTestHelper; +class WorkspaceEventHandler; +class WorkspaceLayoutManager; +class WorkspaceLayoutManagerBackdropDelegate; + +// WorkspaceController acts as a central place that ties together all the +// various workspace pieces. +class ASH_EXPORT WorkspaceController : public aura::WindowObserver { + public: + // Installs WorkspaceLayoutManager on |viewport|. + explicit WorkspaceController(WmWindow* viewport); + ~WorkspaceController() override; + + // Returns the current window state. + wm::WorkspaceWindowState GetWindowState() const; + + // Starts the animation that occurs on first login. + void DoInitialAnimation(); + + // Add a delegate which adds a backdrop behind the top window of the default + // workspace. + void SetMaximizeBackdropDelegate( + std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate); + + WorkspaceLayoutManager* layout_manager() { return layout_manager_; } + + private: + friend class WorkspaceControllerTestHelper; + + // aura::WindowObserver: + void OnWindowDestroying(aura::Window* window) override; + + WmWindow* viewport_; + std::unique_ptr<WorkspaceEventHandler> event_handler_; + + // Owned by |viewport_|. + WorkspaceLayoutManager* layout_manager_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceController); +}; + +} // namespace ash + +#endif // ASH_COMMON_WM_WORKSPACE_CONTROLLER_H_
diff --git a/ash/common/wm_shell.cc b/ash/common/wm_shell.cc index 6bbbe0b3..fcd7804a 100644 --- a/ash/common/wm_shell.cc +++ b/ash/common/wm_shell.cc
@@ -6,8 +6,8 @@ #include <utility> -#include "ash/accelerators/accelerator_controller.h" -#include "ash/accelerators/ash_focus_manager_factory.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/ash_focus_manager_factory.h" #include "ash/common/accessibility_delegate.h" #include "ash/common/cast_config_controller.h" #include "ash/common/devtools/ash_devtools_css_agent.h" @@ -19,38 +19,38 @@ #include "ash/common/palette_delegate.h" #include "ash/common/session/session_controller.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/app_list_shelf_item_delegate.h" +#include "ash/common/shelf/shelf_controller.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_window_watcher.h" #include "ash/common/shell_delegate.h" #include "ash/common/shutdown_controller.h" +#include "ash/common/system/brightness_control_delegate.h" +#include "ash/common/system/chromeos/brightness/brightness_controller_chromeos.h" +#include "ash/common/system/chromeos/keyboard_brightness_controller.h" +#include "ash/common/system/chromeos/network/vpn_list.h" +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" +#include "ash/common/system/keyboard_brightness_control_delegate.h" +#include "ash/common/system/locale/locale_notification_controller.h" +#include "ash/common/system/toast/toast_manager.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" #include "ash/common/wallpaper/wallpaper_controller.h" #include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/immersive_context_ash.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm/system_modal_container_layout_manager.h" +#include "ash/common/wm/window_cycle_controller.h" #include "ash/common/wm_activation_observer.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/app_list_shelf_item_delegate.h" -#include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_window_watcher.h" #include "ash/shell.h" -#include "ash/system/brightness/brightness_controller_chromeos.h" -#include "ash/system/brightness_control_delegate.h" -#include "ash/system/keyboard_brightness_control_delegate.h" -#include "ash/system/keyboard_brightness_controller.h" -#include "ash/system/locale/locale_notification_controller.h" -#include "ash/system/network/vpn_list.h" -#include "ash/system/session/logout_confirmation_controller.h" -#include "ash/system/toast/toast_manager.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/wm/immersive_context_ash.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/root_window_finder.h" -#include "ash/wm/system_modal_container_layout_manager.h" -#include "ash/wm/window_cycle_controller.h" #include "base/bind.h" #include "base/logging.h" #include "base/memory/ptr_util.h"
diff --git a/ash/common/wm_shell.h b/ash/common/wm_shell.h index eacc525b..528a61c 100644 --- a/ash/common/wm_shell.h +++ b/ash/common/wm_shell.h
@@ -11,10 +11,10 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/common/metrics/gesture_action_type.h" +#include "ash/common/metrics/user_metrics_action.h" #include "ash/common/session/session_state_observer.h" -#include "ash/metrics/gesture_action_type.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/wm/lock_state_observer.h" +#include "ash/common/wm/lock_state_observer.h" #include "base/observer_list.h" #include "components/ui_devtools/devtools_server.h" #include "ui/base/ui_base_types.h"
diff --git a/ash/common/wm_window.cc b/ash/common/wm_window.cc index 38697a1..cb4018c 100644 --- a/ash/common/wm_window.cc +++ b/ash/common/wm_window.cc
@@ -7,19 +7,19 @@ #include "ash/aura/aura_layout_manager_adapter.h" #include "ash/aura/wm_shell_aura.h" #include "ash/common/ash_constants.h" +#include "ash/common/shelf/shelf_item_types.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_layout_manager.h" #include "ash/common/wm_transient_window_observer.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_item_types.h" #include "ash/shell.h" #include "ash/wm/resize_handle_window_targeter.h" #include "ash/wm/resize_shadow_controller.h" #include "ash/wm/window_animations.h" #include "ash/wm/window_mirror_view.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h"
diff --git a/ash/common/wm_window_unittest.cc b/ash/common/wm_window_unittest.cc index 9b69c0b..2cbe553 100644 --- a/ash/common/wm_window_unittest.cc +++ b/ash/common/wm_window_unittest.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "ash/test/ash_test.h" +#include "ash/common/test/ash_test.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h"
diff --git a/ash/common/wm_window_user_data_unittest.cc b/ash/common/wm_window_user_data_unittest.cc index a8e9695..3c65711 100644 --- a/ash/common/wm_window_user_data_unittest.cc +++ b/ash/common/wm_window_user_data_unittest.cc
@@ -6,10 +6,10 @@ #include <memory> +#include "ash/common/test/ash_test.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/common/wm_window_user_data.h" -#include "ash/test/ash_test.h" #include "base/memory/ptr_util.h" namespace ash {
diff --git a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc index e89c7b3..c388d0ed 100644 --- a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc +++ b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
@@ -8,17 +8,17 @@ #include <vector> #include "ash/common/ash_switches.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/content/shell_content_state.h" #include "ash/shell.h" -#include "ash/system/screen_layout_observer.h" +#include "ash/system/chromeos/screen_layout_observer.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_environment_content.h" #include "ash/test/ash_test_helper.h" #include "ash/test/content/test_shell_content_state.h" #include "ash/test/test_shell_delegate.h" -#include "ash/test/test_system_tray_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/command_line.h" #include "chromeos/accelerometer/accelerometer_reader.h" #include "chromeos/accelerometer/accelerometer_types.h"
diff --git a/ash/content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc b/ash/content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc index a600a8da..1943640 100644 --- a/ash/content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc +++ b/ash/content/keyboard_overlay/keyboard_overlay_delegate_unittest.cc
@@ -4,8 +4,8 @@ #include "ash/content/keyboard_overlay/keyboard_overlay_delegate.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/strings/utf_string_conversions.h"
diff --git a/ash/content/keyboard_overlay/keyboard_overlay_view_unittest.cc b/ash/content/keyboard_overlay/keyboard_overlay_view_unittest.cc index c4e4173..5cd23568 100644 --- a/ash/content/keyboard_overlay/keyboard_overlay_view_unittest.cc +++ b/ash/content/keyboard_overlay/keyboard_overlay_view_unittest.cc
@@ -6,7 +6,7 @@ #include <algorithm> -#include "ash/accelerators/accelerator_table.h" +#include "ash/common/accelerators/accelerator_table.h" #include "ash/content/keyboard_overlay/keyboard_overlay_delegate.h" #include "ash/content/shell_content_state.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/dip_unittest.cc b/ash/dip_unittest.cc index 80c3301..0e1abed3 100644 --- a/ash/dip_unittest.cc +++ b/ash/dip_unittest.cc
@@ -5,8 +5,8 @@ #include <algorithm> #include <vector> -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_properties.h"
diff --git a/ash/display/display_error_observer_chromeos.cc b/ash/display/display_error_observer_chromeos.cc index 32aaf84b..7a10ed1c 100644 --- a/ash/display/display_error_observer_chromeos.cc +++ b/ash/display/display_error_observer_chromeos.cc
@@ -4,9 +4,9 @@ #include "ash/display/display_error_observer_chromeos.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "ash/display/display_util.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/devicetype_utils.h" #include "base/strings/string_number_conversions.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/display/display_error_observer_chromeos_unittest.cc b/ash/display/display_error_observer_chromeos_unittest.cc index 367dba7..cc70e6b 100644 --- a/ash/display/display_error_observer_chromeos_unittest.cc +++ b/ash/display/display_error_observer_chromeos_unittest.cc
@@ -4,10 +4,10 @@ #include "ash/display/display_error_observer_chromeos.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "ash/display/display_util.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/devicetype_utils.h" #include "ash/test/ash_test_base.h" #include "ui/aura/window.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index b8b856c..7f3e87e 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc
@@ -6,6 +6,7 @@ #include "ash/accelerators/accelerator_commands_aura.h" #include "ash/common/ash_switches.h" +#include "ash/common/wm/window_state.h" #include "ash/display/display_configuration_controller.h" #include "ash/display/display_util.h" #include "ash/display/mirror_window_controller.h" @@ -15,7 +16,6 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/test/ash_test_base.h" #include "ash/test/mirror_window_test_api.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/command_line.h" #include "base/format_macros.h"
diff --git a/ash/display/display_util.cc b/ash/display/display_util.cc index 271802a..d022a8a 100644 --- a/ash/display/display_util.cc +++ b/ash/display/display_util.cc
@@ -8,6 +8,7 @@ #include <utility> #include "ash/common/new_window_controller.h" +#include "ash/common/system/system_notifier.h" #include "ash/common/wm_shell.h" #include "ash/display/extended_mouse_warp_controller.h" #include "ash/display/null_mouse_warp_controller.h" @@ -16,7 +17,6 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" #include "base/memory/ptr_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h"
diff --git a/ash/display/resolution_notification_controller.cc b/ash/display/resolution_notification_controller.cc index f8bd15da..9775277 100644 --- a/ash/display/resolution_notification_controller.cc +++ b/ash/display/resolution_notification_controller.cc
@@ -6,10 +6,10 @@ #include <utility> +#include "ash/common/system/system_notifier.h" #include "ash/resources/grit/ash_resources.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/time_format.h"
diff --git a/ash/display/root_window_transformers_unittest.cc b/ash/display/root_window_transformers_unittest.cc index 077186b..fdcc28b 100644 --- a/ash/display/root_window_transformers_unittest.cc +++ b/ash/display/root_window_transformers_unittest.cc
@@ -6,11 +6,11 @@ #include <memory> +#include "ash/common/shelf/shelf_widget.h" #include "ash/display/display_util.h" #include "ash/host/root_window_transformer.h" #include "ash/magnifier/magnification_controller.h" #include "ash/screen_util.h" -#include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/cursor_manager_test_api.h"
diff --git a/ash/display/screen_ash.cc b/ash/display/screen_ash.cc index b743dc7..c6a2847 100644 --- a/ash/display/screen_ash.cc +++ b/ash/display/screen_ash.cc
@@ -4,13 +4,13 @@ #include "ash/display/screen_ash.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" #include "ash/display/window_tree_host_manager.h" #include "ash/root_window_controller.h" #include "ash/root_window_settings.h" -#include "ash/shelf/shelf_widget.h" #include "ash/shell.h" -#include "ash/wm/root_window_finder.h" #include "base/logging.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h"
diff --git a/ash/display/screen_orientation_controller_chromeos.cc b/ash/display/screen_orientation_controller_chromeos.cc index 1a0ce91..1048900 100644 --- a/ash/display/screen_orientation_controller_chromeos.cc +++ b/ash/display/screen_orientation_controller_chromeos.cc
@@ -5,11 +5,11 @@ #include "ash/display/screen_orientation_controller_chromeos.h" #include "ash/common/ash_switches.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/display_configuration_controller.h" #include "ash/shell.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/auto_reset.h" #include "base/command_line.h" #include "chromeos/accelerometer/accelerometer_reader.h"
diff --git a/ash/display/screen_position_controller.cc b/ash/display/screen_position_controller.cc index a11c24a..6481c0f 100644 --- a/ash/display/screen_position_controller.cc +++ b/ash/display/screen_position_controller.cc
@@ -4,13 +4,13 @@ #include "ash/display/screen_position_controller.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/compositor/dip_util.h"
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc index 49d7277..9ed8583 100644 --- a/ash/display/window_tree_host_manager.cc +++ b/ash/display/window_tree_host_manager.cc
@@ -11,6 +11,7 @@ #include <utility> #include "ash/common/ash_switches.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/display/cursor_window_controller.h" #include "ash/display/mirror_window_controller.h" #include "ash/display/root_window_transformers.h" @@ -23,7 +24,6 @@ #include "ash/root_window_controller.h" #include "ash/root_window_settings.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/strings/stringprintf.h"
diff --git a/ash/display/window_tree_host_manager_unittest.cc b/ash/display/window_tree_host_manager_unittest.cc index 5aab608..2f1a3bc 100644 --- a/ash/display/window_tree_host_manager_unittest.cc +++ b/ash/display/window_tree_host_manager_unittest.cc
@@ -6,20 +6,20 @@ #include <memory> +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm_window.h" #include "ash/display/display_util.h" #include "ash/screen_util.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test/cursor_manager_test_api.h" #include "ash/test/test_shell_delegate.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" #include "base/command_line.h" #include "ui/aura/client/focus_change_observer.h" #include "ui/aura/client/focus_client.h"
diff --git a/ash/drag_drop/drag_drop_controller.cc b/ash/drag_drop/drag_drop_controller.cc index 3c16d1fb0..1d07181 100644 --- a/ash/drag_drop/drag_drop_controller.cc +++ b/ash/drag_drop/drag_drop_controller.cc
@@ -6,10 +6,10 @@ #include <utility> +#include "ash/common/drag_drop/drag_image_view.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/drag_drop/drag_drop_tracker.h" -#include "ash/drag_drop/drag_image_view.h" #include "ash/shell.h" #include "base/bind.h" #include "base/message_loop/message_loop.h"
diff --git a/ash/drag_drop/drag_drop_controller_unittest.cc b/ash/drag_drop/drag_drop_controller_unittest.cc index d026fd5..5218187 100644 --- a/ash/drag_drop/drag_drop_controller_unittest.cc +++ b/ash/drag_drop/drag_drop_controller_unittest.cc
@@ -4,8 +4,8 @@ #include "ash/drag_drop/drag_drop_controller.h" +#include "ash/common/drag_drop/drag_image_view.h" #include "ash/drag_drop/drag_drop_tracker.h" -#include "ash/drag_drop/drag_image_view.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/command_line.h"
diff --git a/ash/drag_drop/drag_drop_tracker.cc b/ash/drag_drop/drag_drop_tracker.cc index e64897b..48b877f3 100644 --- a/ash/drag_drop/drag_drop_tracker.cc +++ b/ash/drag_drop/drag_drop_tracker.cc
@@ -4,10 +4,10 @@ #include "ash/drag_drop/drag_drop_tracker.h" +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/root_window_finder.h" #include "ui/aura/client/window_parenting_client.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/drag_drop/drag_image_view.cc b/ash/drag_drop/drag_image_view.cc deleted file mode 100644 index 4cb2beb..0000000 --- a/ash/drag_drop/drag_image_view.cc +++ /dev/null
@@ -1,208 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/drag_drop/drag_image_view.h" - -#include <memory> - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "skia/ext/image_operations.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/display/display.h" -#include "ui/gfx/canvas.h" -#include "ui/resources/grit/ui_resources.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { -using views::Widget; - -std::unique_ptr<Widget> CreateDragWidget(WmWindow* root_window) { - std::unique_ptr<Widget> drag_widget(new Widget); - Widget::InitParams params; - params.type = Widget::InitParams::TYPE_TOOLTIP; - params.name = "DragWidget"; - params.keep_on_top = true; - params.accept_events = false; - params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.shadow_type = Widget::InitParams::SHADOW_TYPE_NONE; - params.opacity = Widget::InitParams::TRANSLUCENT_WINDOW; - root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - drag_widget.get(), kShellWindowId_DragImageAndTooltipContainer, ¶ms); - drag_widget->Init(params); - drag_widget->SetOpacity(1.f); - return drag_widget; -} - -} // namespace - -DragImageView::DragImageView(WmWindow* root_window, - ui::DragDropTypes::DragEventSource event_source) - : drag_event_source_(event_source), - touch_drag_operation_(ui::DragDropTypes::DRAG_NONE) { - DCHECK(root_window); - widget_ = CreateDragWidget(root_window); - widget_->SetContentsView(this); - widget_->SetAlwaysOnTop(true); - - // We are owned by the DragDropController. - set_owned_by_client(); -} - -DragImageView::~DragImageView() { - widget_->Hide(); -} - -void DragImageView::SetBoundsInScreen(const gfx::Rect& bounds) { - drag_image_size_ = bounds.size(); - widget_->SetBounds(bounds); -} - -void DragImageView::SetScreenPosition(const gfx::Point& position) { - widget_->SetBounds( - gfx::Rect(position, widget_->GetWindowBoundsInScreen().size())); -} - -gfx::Rect DragImageView::GetBoundsInScreen() const { - return widget_->GetWindowBoundsInScreen(); -} - -void DragImageView::SetWidgetVisible(bool visible) { - if (visible != widget_->IsVisible()) { - if (visible) - widget_->Show(); - else - widget_->Hide(); - } -} - -void DragImageView::SetTouchDragOperationHintOff() { - // Simply set the drag type to non-touch so that no hint is drawn. - drag_event_source_ = ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE; - - // This disables the drag hint image. This should reduce the widget size if - // the drag image is smaller than the drag hint image, so we set new bounds. - gfx::Rect new_bounds = GetBoundsInScreen(); - new_bounds.set_size(drag_image_size_); - SetBoundsInScreen(new_bounds); - SchedulePaint(); -} - -void DragImageView::SetTouchDragOperation(int operation) { - if (touch_drag_operation_ == operation) - return; - touch_drag_operation_ = operation; - SchedulePaint(); -} - -void DragImageView::SetTouchDragOperationHintPosition( - const gfx::Point& position) { - if (touch_drag_operation_indicator_position_ == position) - return; - touch_drag_operation_indicator_position_ = position; - SchedulePaint(); -} - -void DragImageView::SetOpacity(float visibility) { - DCHECK_GE(visibility, 0.0f); - DCHECK_LE(visibility, 1.0f); - widget_->SetOpacity(visibility); -} - -void DragImageView::OnPaint(gfx::Canvas* canvas) { - if (GetImage().isNull()) - return; - - // |drag_image_size_| is in DIP. - // ImageSkia::size() also returns the size in DIP. - if (GetImage().size() == drag_image_size_) { - canvas->DrawImageInt(GetImage(), 0, 0); - } else { - WmWindow* window = WmWindow::Get(widget_->GetNativeWindow()); - const float device_scale = - window->GetDisplayNearestWindow().device_scale_factor(); - // The drag image already has device scale factor applied. But - // |drag_image_size_| is in DIP units. - gfx::Size drag_image_size_pixels = - gfx::ScaleToRoundedSize(drag_image_size_, device_scale); - gfx::ImageSkiaRep image_rep = GetImage().GetRepresentation(device_scale); - if (image_rep.is_null()) - return; - SkBitmap scaled = skia::ImageOperations::Resize( - image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3, - drag_image_size_pixels.width(), drag_image_size_pixels.height()); - gfx::ImageSkia image_skia(gfx::ImageSkiaRep(scaled, device_scale)); - canvas->DrawImageInt(image_skia, 0, 0); - } - - gfx::Image* drag_hint = DragHint(); - if (!ShouldDrawDragHint() || drag_hint->IsEmpty()) - return; - - // Make sure drag hint image is positioned within the widget. - gfx::Size drag_hint_size = drag_hint->Size(); - gfx::Point drag_hint_position = touch_drag_operation_indicator_position_; - drag_hint_position.Offset(-drag_hint_size.width() / 2, 0); - gfx::Rect drag_hint_bounds(drag_hint_position, drag_hint_size); - - gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size(); - drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size)); - - // Draw image. - canvas->DrawImageInt(*(drag_hint->ToImageSkia()), drag_hint_bounds.x(), - drag_hint_bounds.y()); -} - -gfx::Image* DragImageView::DragHint() const { - // Select appropriate drag hint. - gfx::Image* drag_hint = - &ui::ResourceBundle::GetSharedInstance().GetImageNamed( - IDR_TOUCH_DRAG_TIP_NODROP); - if (touch_drag_operation_ & ui::DragDropTypes::DRAG_COPY) { - drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( - IDR_TOUCH_DRAG_TIP_COPY); - } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_MOVE) { - drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( - IDR_TOUCH_DRAG_TIP_MOVE); - } else if (touch_drag_operation_ & ui::DragDropTypes::DRAG_LINK) { - drag_hint = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( - IDR_TOUCH_DRAG_TIP_LINK); - } - return drag_hint; -} - -bool DragImageView::ShouldDrawDragHint() const { - return drag_event_source_ == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH; -} - -gfx::Size DragImageView::GetMinimumSize() const { - gfx::Size minimum_size = drag_image_size_; - if (ShouldDrawDragHint()) - minimum_size.SetToMax(DragHint()->Size()); - return minimum_size; -} - -void DragImageView::Layout() { - View::Layout(); - - // Only consider resizing the widget for the drag hint image if we are in a - // touch initiated drag. - gfx::Image* drag_hint = DragHint(); - if (!ShouldDrawDragHint() || drag_hint->IsEmpty()) - return; - - gfx::Size drag_hint_size = drag_hint->Size(); - - // Enlarge widget if required to fit the drag hint image. - gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size(); - if (drag_hint_size.width() > widget_size.width() || - drag_hint_size.height() > widget_size.height()) { - widget_size.SetToMax(drag_hint_size); - widget_->SetSize(widget_size); - } -} - -} // namespace ash
diff --git a/ash/drag_drop/drag_image_view.h b/ash/drag_drop/drag_image_view.h deleted file mode 100644 index be1830e..0000000 --- a/ash/drag_drop/drag_image_view.h +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_DRAG_DROP_DRAG_IMAGE_VIEW_H_ -#define ASH_DRAG_DROP_DRAG_IMAGE_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/controls/image_view.h" - -namespace gfx { -class Image; -} - -namespace views { -class Widget; -} - -namespace ash { - -class WmWindow; - -// This class allows to show a (native) view always on top of everything. It -// does this by creating a widget and setting the content as the given view. The -// caller can then use this object to freely move / drag it around on the -// desktop in screen coordinates. -class ASH_EXPORT DragImageView : public views::ImageView { - public: - // |root_window| is the root window on which to create the drag image widget. - // |source| is the event source that started this drag drop operation (touch - // or mouse). It is used to determine attributes of the drag image such as - // whether to show drag operation hint on top of the image. - DragImageView(WmWindow* root_window, - ui::DragDropTypes::DragEventSource source); - ~DragImageView() override; - - // Sets the bounds of the native widget in screen - // coordinates. - // TODO(oshima): Looks like this is root window's - // coordinate. Change this to screen's coordinate. - void SetBoundsInScreen(const gfx::Rect& bounds); - - // Sets the position of the native widget. - void SetScreenPosition(const gfx::Point& position); - - // Gets the image position in screen coordinates. - gfx::Rect GetBoundsInScreen() const; - - // Sets the visibility of the native widget. - void SetWidgetVisible(bool visible); - - // For touch drag drop, we show a hint corresponding to the drag operation - // (since no mouse cursor is visible). These functions set the hint - // parameters. - void SetTouchDragOperationHintOff(); - - // |operation| is a bit field indicating allowable drag operations from - // ui::DragDropTypes::DragOperation. - void SetTouchDragOperation(int operation); - void SetTouchDragOperationHintPosition(const gfx::Point& position); - - // Sets the |opacity| of the image view between 0.0 and 1.0. - void SetOpacity(float opacity); - - gfx::Size GetMinimumSize() const override; - - private: - gfx::Image* DragHint() const; - // Drag hint images are only drawn when the input source is touch. - bool ShouldDrawDragHint() const; - - // Overridden from views::ImageView. - void OnPaint(gfx::Canvas* canvas) override; - - // Overridden from views::view - void Layout() override; - - std::unique_ptr<views::Widget> widget_; - - // Save the requested drag image size. We may need to display a drag hint - // image, which potentially expands |widget_|'s size. That drag hint image - // may be disabled (e.g. during the drag cancel animation). In that case, - // we need to know the originally requested size to render the drag image. - gfx::Size drag_image_size_; - - ui::DragDropTypes::DragEventSource drag_event_source_; - - // Bitmask of ui::DragDropTypes::DragOperation values. - int touch_drag_operation_; - gfx::Point touch_drag_operation_indicator_position_; - - DISALLOW_COPY_AND_ASSIGN(DragImageView); -}; - -} // namespace ash - -#endif // ASH_DRAG_DROP_DRAG_IMAGE_VIEW_H_
diff --git a/ash/drag_drop/drag_image_view_unittest.cc b/ash/drag_drop/drag_image_view_unittest.cc deleted file mode 100644 index 6fa0bd3..0000000 --- a/ash/drag_drop/drag_image_view_unittest.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/drag_drop/drag_image_view.h" - -#include "ash/test/ash_test.h" -#include "ui/base/dragdrop/drag_drop_types.h" - -namespace ash { -namespace test { - -using DragDropImageTest = AshTest; - -TEST_F(DragDropImageTest, SetBoundsConsidersDragHintForTouch) { - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow()); - DragImageView drag_image_view( - window_owner->window(), - ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_TOUCH); - - gfx::Size minimum_size = drag_image_view.GetMinimumSize(); - gfx::Point new_pos(5, 5); - - if (!minimum_size.IsEmpty()) { - // Expect that the view is at least the size of the drag hint image. - gfx::Rect small_bounds(0, 0, 1, 1); - drag_image_view.SetBoundsInScreen(small_bounds); - EXPECT_EQ(gfx::Rect(minimum_size), drag_image_view.GetBoundsInScreen()); - - // Expect that we can change the position without affecting the bounds. - drag_image_view.SetScreenPosition(new_pos); - EXPECT_EQ(gfx::Rect(new_pos, minimum_size), - drag_image_view.GetBoundsInScreen()); - } - - // Expect that we can resize the view normally. - gfx::Rect large_bounds(0, 0, minimum_size.width() + 1, - minimum_size.height() + 1); - drag_image_view.SetBoundsInScreen(large_bounds); - EXPECT_EQ(large_bounds, drag_image_view.GetBoundsInScreen()); - // Expect that we can change the position without affecting the bounds. - drag_image_view.SetScreenPosition(new_pos); - EXPECT_EQ(gfx::Rect(new_pos, large_bounds.size()), - drag_image_view.GetBoundsInScreen()); -} - -TEST_F(DragDropImageTest, SetBoundsIgnoresDragHintForMouse) { - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow()); - DragImageView drag_image_view( - window_owner->window(), - ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_MOUSE); - - // Expect no drag hint image. - gfx::Rect small_bounds(0, 0, 1, 1); - drag_image_view.SetBoundsInScreen(small_bounds); - EXPECT_EQ(small_bounds, drag_image_view.GetBoundsInScreen()); - EXPECT_EQ(drag_image_view.GetMinimumSize(), - drag_image_view.GetBoundsInScreen().size()); - - gfx::Point new_pos(5, 5); - // Expect that we can change the position without affecting the bounds. - drag_image_view.SetScreenPosition(new_pos); - EXPECT_EQ(gfx::Rect(new_pos, small_bounds.size()), - drag_image_view.GetBoundsInScreen()); - - // Expect that we can resize the view. - gfx::Rect large_bounds(0, 0, 100, 100); - drag_image_view.SetBoundsInScreen(large_bounds); - EXPECT_EQ(large_bounds, drag_image_view.GetBoundsInScreen()); - // Expect that we can change the position without affecting the bounds. - drag_image_view.SetScreenPosition(new_pos); - EXPECT_EQ(gfx::Rect(new_pos, large_bounds.size()), - drag_image_view.GetBoundsInScreen()); -} - -} // namespace test -} // namespace ash
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc index 62c1b9f..8dc73cba 100644 --- a/ash/extended_desktop_unittest.cc +++ b/ash/extended_desktop_unittest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/root_window_finder.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" #include "base/strings/string_util.h"
diff --git a/ash/first_run/first_run_helper_impl.cc b/ash/first_run/first_run_helper_impl.cc index af9c7fef..321351c7 100644 --- a/ash/first_run/first_run_helper_impl.cc +++ b/ash/first_run/first_run_helper_impl.cc
@@ -4,14 +4,14 @@ #include "ash/first_run/first_run_helper_impl.h" +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "base/logging.h" #include "ui/app_list/views/app_list_view.h" #include "ui/aura/window.h"
diff --git a/ash/focus_cycler_unittest.cc b/ash/focus_cycler_unittest.cc index 5166b718..0780939 100644 --- a/ash/focus_cycler_unittest.cc +++ b/ash/focus_cycler_unittest.cc
@@ -6,12 +6,12 @@ #include <memory> +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/status_area_widget_delegate.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/status_area_widget_delegate.h" -#include "ash/system/tray/system_tray.h" #include "ash/test/ash_test_base.h" #include "ash/test/status_area_widget_test_helper.h" #include "ash/wm/window_util.h"
diff --git a/ash/frame/caption_buttons/caption_button_types.h b/ash/frame/caption_buttons/caption_button_types.h deleted file mode 100644 index ece7d8e9c..0000000 --- a/ash/frame/caption_buttons/caption_button_types.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_ -#define ASH_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_ - -namespace ash { - -// These are the icon types that a caption button can have. The size button's -// action (SnapType) can be different from its icon. -enum CaptionButtonIcon { - CAPTION_BUTTON_ICON_MINIMIZE, - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, - CAPTION_BUTTON_ICON_CLOSE, - CAPTION_BUTTON_ICON_LEFT_SNAPPED, - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - CAPTION_BUTTON_ICON_BACK, - CAPTION_BUTTON_ICON_LOCATION, - CAPTION_BUTTON_ICON_COUNT -}; - -} // namespace ash - -#endif // ASH_FRAME_CAPTION_BUTTONS_CAPTION_BUTTON_TYPES_H_
diff --git a/ash/frame/caption_buttons/frame_caption_button.cc b/ash/frame/caption_buttons/frame_caption_button.cc deleted file mode 100644 index 9879443..0000000 --- a/ash/frame/caption_buttons/frame_caption_button.cc +++ /dev/null
@@ -1,191 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/caption_buttons/frame_caption_button.h" - -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/animation/throb_animation.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" - -namespace ash { - -namespace { - -// The duration of the crossfade animation when swapping the button's images. -const int kSwapImagesAnimationDurationMs = 200; - -// The duration of the fade out animation of the old icon during a crossfade -// animation as a ratio of |kSwapImagesAnimationDurationMs|. -const float kFadeOutRatio = 0.5f; - -// The alpha to draw inactive icons with. -const float kInactiveIconAlpha = 0.2f; - -// The colors and alpha values used for the button background hovered and -// pressed states. -// TODO(tdanderson|estade): Request these colors from ThemeProvider. -const int kHoveredAlpha = 0x14; -const int kPressedAlpha = 0x24; - -} // namespace - -// static -const char FrameCaptionButton::kViewClassName[] = "FrameCaptionButton"; - -FrameCaptionButton::FrameCaptionButton(views::ButtonListener* listener, - CaptionButtonIcon icon) - : CustomButton(listener), - icon_(icon), - paint_as_active_(false), - use_light_images_(false), - alpha_(255), - swap_images_animation_(new gfx::SlideAnimation(this)) { - set_animate_on_state_change(true); - swap_images_animation_->Reset(1); - - // Do not flip the gfx::Canvas passed to the OnPaint() method. The snap left - // and snap right button icons should not be flipped. The other icons are - // horizontally symmetrical. -} - -FrameCaptionButton::~FrameCaptionButton() {} - -void FrameCaptionButton::SetImage(CaptionButtonIcon icon, - Animate animate, - const gfx::VectorIcon& icon_definition) { - gfx::ImageSkia new_icon_image = gfx::CreateVectorIcon( - icon_definition, - use_light_images_ ? SK_ColorWHITE : gfx::kChromeIconGrey); - - // The early return is dependent on |animate| because callers use SetImage() - // with ANIMATE_NO to progress the crossfade animation to the end. - if (icon == icon_ && - (animate == ANIMATE_YES || !swap_images_animation_->is_animating()) && - new_icon_image.BackedBySameObjectAs(icon_image_)) { - return; - } - - if (animate == ANIMATE_YES) - crossfade_icon_image_ = icon_image_; - - icon_ = icon; - icon_definition_ = &icon_definition; - icon_image_ = new_icon_image; - - if (animate == ANIMATE_YES) { - swap_images_animation_->Reset(0); - swap_images_animation_->SetSlideDuration(kSwapImagesAnimationDurationMs); - swap_images_animation_->Show(); - } else { - swap_images_animation_->Reset(1); - } - PreferredSizeChanged(); - SchedulePaint(); -} - -bool FrameCaptionButton::IsAnimatingImageSwap() const { - return swap_images_animation_->is_animating(); -} - -void FrameCaptionButton::SetAlpha(int alpha) { - if (alpha_ != alpha) { - alpha_ = alpha; - SchedulePaint(); - } -} - -gfx::Size FrameCaptionButton::GetPreferredSize() const { - return size_; -} - -const char* FrameCaptionButton::GetClassName() const { - return kViewClassName; -} - -void FrameCaptionButton::OnPaint(gfx::Canvas* canvas) { - SkAlpha bg_alpha = SK_AlphaTRANSPARENT; - if (hover_animation().is_animating()) - bg_alpha = hover_animation().CurrentValueBetween(0, kHoveredAlpha); - else if (state() == STATE_HOVERED) - bg_alpha = kHoveredAlpha; - else if (state() == STATE_PRESSED) - bg_alpha = kPressedAlpha; - - if (bg_alpha != SK_AlphaTRANSPARENT) { - canvas->DrawColor(SkColorSetA( - use_light_images_ ? SK_ColorWHITE : SK_ColorBLACK, bg_alpha)); - } - - int icon_alpha = swap_images_animation_->CurrentValueBetween(0, 255); - int crossfade_icon_alpha = 0; - if (icon_alpha < static_cast<int>(kFadeOutRatio * 255)) - crossfade_icon_alpha = static_cast<int>(255 - icon_alpha / kFadeOutRatio); - - if (crossfade_icon_alpha > 0 && !crossfade_icon_image_.isNull()) { - gfx::Canvas icon_canvas(icon_image_.size(), canvas->image_scale(), false); - cc::PaintFlags flags; - flags.setAlpha(icon_alpha); - icon_canvas.DrawImageInt(icon_image_, 0, 0, flags); - - flags.setAlpha(crossfade_icon_alpha); - flags.setBlendMode(SkBlendMode::kPlus); - icon_canvas.DrawImageInt(crossfade_icon_image_, 0, 0, flags); - - PaintCentered(canvas, gfx::ImageSkia(icon_canvas.ExtractImageRep()), - alpha_); - } else { - if (!swap_images_animation_->is_animating()) - icon_alpha = alpha_; - PaintCentered(canvas, icon_image_, icon_alpha); - } -} - -void FrameCaptionButton::OnGestureEvent(ui::GestureEvent* event) { - // CustomButton does not become pressed when the user drags off and then back - // onto the button. Make FrameCaptionButton pressed in this case because this - // behavior is more consistent with AlternateFrameSizeButton. - if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || - event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { - if (HitTestPoint(event->location())) { - SetState(STATE_PRESSED); - RequestFocus(); - event->StopPropagation(); - } else { - SetState(STATE_NORMAL); - } - } else if (event->type() == ui::ET_GESTURE_SCROLL_END) { - if (HitTestPoint(event->location())) { - SetState(STATE_HOVERED); - NotifyClick(*event); - event->StopPropagation(); - } - } - CustomButton::OnGestureEvent(event); -} - -void FrameCaptionButton::PaintCentered(gfx::Canvas* canvas, - const gfx::ImageSkia& to_center, - int alpha) { - if (!paint_as_active_) { - // Paint icons as active when they are hovered over or pressed. - double inactive_alpha = kInactiveIconAlpha; - if (hover_animation().is_animating()) { - inactive_alpha = - hover_animation().CurrentValueBetween(inactive_alpha, 1.0f); - } else if (state() == STATE_PRESSED || state() == STATE_HOVERED) { - inactive_alpha = 1.0f; - } - alpha *= inactive_alpha; - } - - cc::PaintFlags flags; - flags.setAlpha(alpha); - canvas->DrawImageInt(to_center, (width() - to_center.width()) / 2, - (height() - to_center.height()) / 2, flags); -} - -} // namespace ash
diff --git a/ash/frame/caption_buttons/frame_caption_button.h b/ash/frame/caption_buttons/frame_caption_button.h deleted file mode 100644 index 0d296a8..0000000 --- a/ash/frame/caption_buttons/frame_caption_button.h +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_ -#define ASH_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/frame/caption_buttons/caption_button_types.h" -#include "base/macros.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/controls/button/custom_button.h" - -namespace gfx { -class SlideAnimation; -struct VectorIcon; -} - -namespace ash { - -// Base class for the window caption buttons (minimize, maximize, restore, -// close). -class ASH_EXPORT FrameCaptionButton : public views::CustomButton { - public: - enum Animate { ANIMATE_YES, ANIMATE_NO }; - - static const char kViewClassName[]; - - FrameCaptionButton(views::ButtonListener* listener, CaptionButtonIcon icon); - ~FrameCaptionButton() override; - - // Sets the image to use to paint the button. If |animate| is ANIMATE_YES, - // the button crossfades to the new visuals. If the image matches the one - // currently used by the button and |animate| is ANIMATE_NO, the crossfade - // animation is progressed to the end. - void SetImage(CaptionButtonIcon icon, - Animate animate, - const gfx::VectorIcon& icon_image); - - // Returns true if the button is crossfading to new visuals set in - // SetImage(). - bool IsAnimatingImageSwap() const; - - // Sets the alpha to use for painting. Used to animate visibility changes. - void SetAlpha(int alpha); - - // views::View overrides: - gfx::Size GetPreferredSize() const override; - const char* GetClassName() const override; - void OnPaint(gfx::Canvas* canvas) override; - - void set_paint_as_active(bool paint_as_active) { - paint_as_active_ = paint_as_active; - } - - void set_use_light_images(bool light) { use_light_images_ = light; } - - CaptionButtonIcon icon() const { return icon_; } - - void set_size(const gfx::Size& size) { size_ = size; } - - protected: - // views::CustomButton override: - void OnGestureEvent(ui::GestureEvent* event) override; - - private: - // Paints |to_center| centered within the button with |alpha|. - void PaintCentered(gfx::Canvas* canvas, - const gfx::ImageSkia& to_center, - int alpha); - - // The button's current icon. - CaptionButtonIcon icon_; - - // The size of the button. - gfx::Size size_; - - // Whether the button should be painted as active. - bool paint_as_active_; - - // Whether to paint in a lighter color (for use on dark backgrounds). - bool use_light_images_; - - // Current alpha to use for painting. - int alpha_; - - // The image id (kept for the purposes of testing) and image used to paint the - // button's icon. - const gfx::VectorIcon* icon_definition_ = nullptr; - gfx::ImageSkia icon_image_; - - // The icon image to crossfade from. - gfx::ImageSkia crossfade_icon_image_; - - // Crossfade animation started when the button's images are changed by - // SetImage(). - std::unique_ptr<gfx::SlideAnimation> swap_images_animation_; - - DISALLOW_COPY_AND_ASSIGN(FrameCaptionButton); -}; - -} // namespace ash - -#endif // ASH_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_H_
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/frame/caption_buttons/frame_caption_button_container_view.cc deleted file mode 100644 index 63a97dd..0000000 --- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc +++ /dev/null
@@ -1,412 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" - -#include <cmath> -#include <map> - -#include "ash/common/wm_shell.h" -#include "ash/frame/caption_buttons/frame_caption_button.h" -#include "ash/frame/caption_buttons/frame_size_button.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ui/base/hit_test.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/animation/tween.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/vector_icon_types.h" -#include "ui/strings/grit/ui_strings.h" // Accessibility names -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { - -namespace { - -// Duration of the animation of the position of |minimize_button_|. -const int kPositionAnimationDurationMs = 500; - -// Duration of the animation of the alpha of |size_button_|. -const int kAlphaAnimationDurationMs = 250; - -// Delay during |maximize_mode_animation_| hide to wait before beginning to -// animate the position of |minimize_button_|. -const int kHidePositionDelayMs = 100; - -// Duration of |maximize_mode_animation_| hiding. -// Hiding size button 250 -// |------------------------| -// Delay 100 Slide minimize button 500 -// |---------|-------------------------------------------------| -const int kHideAnimationDurationMs = - kHidePositionDelayMs + kPositionAnimationDurationMs; - -// Delay during |maximize_mode_animation_| show to wait before beginning to -// animate the alpha of |size_button_|. -const int kShowAnimationAlphaDelayMs = 100; - -// Duration of |maximize_mode_animation_| showing. -// Slide minimize button 500 -// |-------------------------------------------------| -// Delay 100 Show size button 250 -// |---------|-----------------------| -const int kShowAnimationDurationMs = kPositionAnimationDurationMs; - -// Value of |maximize_mode_animation_| showing to begin animating alpha of -// |size_button_|. -float SizeButtonShowStartValue() { - return static_cast<float>(kShowAnimationAlphaDelayMs) / - kShowAnimationDurationMs; -} - -// Amount of |maximize_mode_animation_| showing to animate the alpha of -// |size_button_|. -float SizeButtonShowDuration() { - return static_cast<float>(kAlphaAnimationDurationMs) / - kShowAnimationDurationMs; -} - -// Amount of |maximize_mode_animation_| hiding to animate the alpha of -// |size_button_|. -float SizeButtonHideDuration() { - return static_cast<float>(kAlphaAnimationDurationMs) / - kHideAnimationDurationMs; -} - -// Value of |maximize_mode_animation_| hiding to begin animating the position of -// |minimize_button_|. -float HidePositionStartValue() { - return 1.0f - - static_cast<float>(kHidePositionDelayMs) / kHideAnimationDurationMs; -} - -// Converts |point| from |src| to |dst| and hittests against |dst|. -bool ConvertPointToViewAndHitTest(const views::View* src, - const views::View* dst, - const gfx::Point& point) { - gfx::Point converted(point); - views::View::ConvertPointToTarget(src, dst, &converted); - return dst->HitTestPoint(converted); -} - -// Bounds animation values to the range 0.0 - 1.0. Allows for mapping of offset -// animations to the expected range so that gfx::Tween::CalculateValue() can be -// used. -double CapAnimationValue(double value) { - return std::min(1.0, std::max(0.0, value)); -} - -} // namespace - -// static -const char FrameCaptionButtonContainerView::kViewClassName[] = - "FrameCaptionButtonContainerView"; - -FrameCaptionButtonContainerView::FrameCaptionButtonContainerView( - views::Widget* frame) - : frame_(frame), - minimize_button_(NULL), - size_button_(NULL), - close_button_(NULL) { - bool size_button_visibility = ShouldSizeButtonBeVisible(); - maximize_mode_animation_.reset(new gfx::SlideAnimation(this)); - maximize_mode_animation_->SetTweenType(gfx::Tween::LINEAR); - - // Ensure animation tracks visibility of size button. - if (size_button_visibility) - maximize_mode_animation_->Reset(1.0f); - - // Insert the buttons left to right. - minimize_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_MINIMIZE); - minimize_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MINIMIZE)); - minimize_button_->SetVisible(frame_->widget_delegate()->CanMinimize()); - AddChildView(minimize_button_); - - size_button_ = new FrameSizeButton(this, frame, this); - size_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE)); - size_button_->SetVisible(size_button_visibility); - AddChildView(size_button_); - - close_button_ = new FrameCaptionButton(this, CAPTION_BUTTON_ICON_CLOSE); - close_button_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); - AddChildView(close_button_); -} - -FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {} - -void FrameCaptionButtonContainerView::TestApi::EndAnimations() { - container_view_->maximize_mode_animation_->End(); -} - -void FrameCaptionButtonContainerView::SetButtonImage( - CaptionButtonIcon icon, - const gfx::VectorIcon& icon_definition) { - button_icon_map_[icon] = &icon_definition; - - FrameCaptionButton* buttons[] = {minimize_button_, size_button_, - close_button_}; - for (size_t i = 0; i < arraysize(buttons); ++i) { - if (buttons[i]->icon() == icon) - buttons[i]->SetImage(icon, FrameCaptionButton::ANIMATE_NO, - icon_definition); - } -} - -void FrameCaptionButtonContainerView::SetPaintAsActive(bool paint_as_active) { - minimize_button_->set_paint_as_active(paint_as_active); - size_button_->set_paint_as_active(paint_as_active); - close_button_->set_paint_as_active(paint_as_active); -} - -void FrameCaptionButtonContainerView::SetUseLightImages(bool light) { - minimize_button_->set_use_light_images(light); - size_button_->set_use_light_images(light); - close_button_->set_use_light_images(light); -} - -void FrameCaptionButtonContainerView::ResetWindowControls() { - SetButtonsToNormal(ANIMATE_NO); -} - -int FrameCaptionButtonContainerView::NonClientHitTest( - const gfx::Point& point) const { - if (close_button_->visible() && - ConvertPointToViewAndHitTest(this, close_button_, point)) { - return HTCLOSE; - } else if (size_button_->visible() && - ConvertPointToViewAndHitTest(this, size_button_, point)) { - return HTMAXBUTTON; - } else if (minimize_button_->visible() && - ConvertPointToViewAndHitTest(this, minimize_button_, point)) { - return HTMINBUTTON; - } - return HTNOWHERE; -} - -void FrameCaptionButtonContainerView::UpdateSizeButtonVisibility() { - bool visible = ShouldSizeButtonBeVisible(); - if (visible) { - size_button_->SetVisible(true); - maximize_mode_animation_->SetSlideDuration(kShowAnimationDurationMs); - maximize_mode_animation_->Show(); - } else { - maximize_mode_animation_->SetSlideDuration(kHideAnimationDurationMs); - maximize_mode_animation_->Hide(); - } -} - -void FrameCaptionButtonContainerView::SetButtonSize(const gfx::Size& size) { - minimize_button_->set_size(size); - size_button_->set_size(size); - close_button_->set_size(size); -} - -gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() const { - int width = 0; - for (int i = 0; i < child_count(); ++i) { - const views::View* child = child_at(i); - if (child->visible()) - width += child_at(i)->GetPreferredSize().width(); - } - return gfx::Size(width, close_button_->GetPreferredSize().height()); -} - -void FrameCaptionButtonContainerView::Layout() { - int x = 0; - for (int i = 0; i < child_count(); ++i) { - views::View* child = child_at(i); - if (!child->visible()) - continue; - - gfx::Size size = child->GetPreferredSize(); - child->SetBounds(x, 0, size.width(), size.height()); - x += size.width(); - } - if (maximize_mode_animation_->is_animating()) { - AnimationProgressed(maximize_mode_animation_.get()); - } -} - -const char* FrameCaptionButtonContainerView::GetClassName() const { - return kViewClassName; -} - -void FrameCaptionButtonContainerView::AnimationEnded( - const gfx::Animation* animation) { - // Ensure that position is calculated at least once. - AnimationProgressed(animation); - - double current_value = maximize_mode_animation_->GetCurrentValue(); - if (current_value == 0.0) { - size_button_->SetVisible(false); - PreferredSizeChanged(); - } -} - -void FrameCaptionButtonContainerView::AnimationProgressed( - const gfx::Animation* animation) { - double current_value = animation->GetCurrentValue(); - int size_alpha = 0; - int minimize_x = 0; - if (maximize_mode_animation_->IsShowing()) { - double scaled_value = - CapAnimationValue((current_value - SizeButtonShowStartValue()) / - SizeButtonShowDuration()); - double tweened_value_alpha = - gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value); - size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 0, 255); - - double tweened_value_slide = - gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, current_value); - minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_slide, - size_button_->x(), 0); - } else { - double scaled_value_alpha = - CapAnimationValue((1.0f - current_value) / SizeButtonHideDuration()); - double tweened_value_alpha = - gfx::Tween::CalculateValue(gfx::Tween::EASE_IN, scaled_value_alpha); - size_alpha = gfx::Tween::LinearIntValueBetween(tweened_value_alpha, 255, 0); - - double scaled_value_position = CapAnimationValue( - (HidePositionStartValue() - current_value) / HidePositionStartValue()); - double tweened_value_position = - gfx::Tween::CalculateValue(gfx::Tween::EASE_OUT, scaled_value_position); - minimize_x = gfx::Tween::LinearIntValueBetween(tweened_value_position, 0, - size_button_->x()); - } - size_button_->SetAlpha(size_alpha); - minimize_button_->SetX(minimize_x); -} - -void FrameCaptionButtonContainerView::SetButtonIcon(FrameCaptionButton* button, - CaptionButtonIcon icon, - Animate animate) { - // The early return is dependant on |animate| because callers use - // SetButtonIcon() with ANIMATE_NO to progress |button|'s crossfade animation - // to the end. - if (button->icon() == icon && - (animate == ANIMATE_YES || !button->IsAnimatingImageSwap())) { - return; - } - - FrameCaptionButton::Animate fcb_animate = - (animate == ANIMATE_YES) ? FrameCaptionButton::ANIMATE_YES - : FrameCaptionButton::ANIMATE_NO; - auto it = button_icon_map_.find(icon); - if (it != button_icon_map_.end()) - button->SetImage(icon, fcb_animate, *it->second); -} - -bool FrameCaptionButtonContainerView::ShouldSizeButtonBeVisible() const { - return !WmShell::Get() - ->maximize_mode_controller() - ->IsMaximizeModeWindowManagerEnabled() && - frame_->widget_delegate()->CanMaximize(); -} - -void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - // Abort any animations of the button icons. - SetButtonsToNormal(ANIMATE_NO); - - UserMetricsAction action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE; - if (sender == minimize_button_) { - frame_->Minimize(); - } else if (sender == size_button_) { - if (frame_->IsFullscreen()) { // Can be clicked in immersive fullscreen. - frame_->Restore(); - action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN; - } else if (frame_->IsMaximized()) { - frame_->Restore(); - action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE; - } else { - frame_->Maximize(); - action = UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE; - } - - if (event.IsGestureEvent()) - WmShell::Get()->RecordGestureAction(GESTURE_FRAMEMAXIMIZE_TAP); - } else if (sender == close_button_) { - frame_->Close(); - action = UMA_WINDOW_CLOSE_BUTTON_CLICK; - } else { - return; - } - WmShell::Get()->RecordUserMetricsAction(action); -} - -bool FrameCaptionButtonContainerView::IsMinimizeButtonVisible() const { - return minimize_button_->visible(); -} - -void FrameCaptionButtonContainerView::SetButtonsToNormal(Animate animate) { - SetButtonIcons(CAPTION_BUTTON_ICON_MINIMIZE, CAPTION_BUTTON_ICON_CLOSE, - animate); - minimize_button_->SetState(views::Button::STATE_NORMAL); - size_button_->SetState(views::Button::STATE_NORMAL); - close_button_->SetState(views::Button::STATE_NORMAL); -} - -void FrameCaptionButtonContainerView::SetButtonIcons( - CaptionButtonIcon minimize_button_icon, - CaptionButtonIcon close_button_icon, - Animate animate) { - SetButtonIcon(minimize_button_, minimize_button_icon, animate); - SetButtonIcon(close_button_, close_button_icon, animate); -} - -const FrameCaptionButton* FrameCaptionButtonContainerView::GetButtonClosestTo( - const gfx::Point& position_in_screen) const { - // Since the buttons all have the same size, the closest button is the button - // with the center point closest to |position_in_screen|. - // TODO(pkotwicz): Make the caption buttons not overlap. - gfx::Point position(position_in_screen); - views::View::ConvertPointFromScreen(this, &position); - - FrameCaptionButton* buttons[] = {minimize_button_, size_button_, - close_button_}; - int min_squared_distance = INT_MAX; - FrameCaptionButton* closest_button = NULL; - for (size_t i = 0; i < arraysize(buttons); ++i) { - FrameCaptionButton* button = buttons[i]; - if (!button->visible()) - continue; - - gfx::Point center_point = button->GetLocalBounds().CenterPoint(); - views::View::ConvertPointToTarget(button, this, ¢er_point); - int squared_distance = static_cast<int>( - pow(static_cast<double>(position.x() - center_point.x()), 2) + - pow(static_cast<double>(position.y() - center_point.y()), 2)); - if (squared_distance < min_squared_distance) { - min_squared_distance = squared_distance; - closest_button = button; - } - } - return closest_button; -} - -void FrameCaptionButtonContainerView::SetHoveredAndPressedButtons( - const FrameCaptionButton* to_hover, - const FrameCaptionButton* to_press) { - FrameCaptionButton* buttons[] = {minimize_button_, size_button_, - close_button_}; - for (size_t i = 0; i < arraysize(buttons); ++i) { - FrameCaptionButton* button = buttons[i]; - views::Button::ButtonState new_state = views::Button::STATE_NORMAL; - if (button == to_hover) - new_state = views::Button::STATE_HOVERED; - else if (button == to_press) - new_state = views::Button::STATE_PRESSED; - button->SetState(new_state); - } -} - -} // namespace ash
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.h b/ash/frame/caption_buttons/frame_caption_button_container_view.h deleted file mode 100644 index 4c59001..0000000 --- a/ash/frame/caption_buttons/frame_caption_button_container_view.h +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ -#define ASH_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_ - -#include <map> - -#include "ash/ash_export.h" -#include "ash/frame/caption_buttons/frame_size_button_delegate.h" -#include "base/macros.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" - -namespace gfx { -class SlideAnimation; -struct VectorIcon; -} - -namespace views { -class Widget; -} - -namespace ash { - -// Container view for the frame caption buttons. It performs the appropriate -// action when a caption button is clicked. -class ASH_EXPORT FrameCaptionButtonContainerView - : public views::View, - public views::ButtonListener, - public FrameSizeButtonDelegate, - public gfx::AnimationDelegate { - public: - static const char kViewClassName[]; - - // |frame| is the views::Widget that the caption buttons act on. - explicit FrameCaptionButtonContainerView(views::Widget* frame); - ~FrameCaptionButtonContainerView() override; - - // For testing. - class ASH_EXPORT TestApi { - public: - explicit TestApi(FrameCaptionButtonContainerView* container_view) - : container_view_(container_view) {} - - void EndAnimations(); - - FrameCaptionButton* minimize_button() const { - return container_view_->minimize_button_; - } - - FrameCaptionButton* size_button() const { - return container_view_->size_button_; - } - - FrameCaptionButton* close_button() const { - return container_view_->close_button_; - } - - private: - FrameCaptionButtonContainerView* container_view_; - - DISALLOW_COPY_AND_ASSIGN(TestApi); - }; - - // Sets the id of the vector image to paint the button for |icon|. The - // FrameCaptionButtonContainerView will keep track of the image to use for - // |icon| even if none of the buttons currently use |icon|. - void SetButtonImage(CaptionButtonIcon icon, - const gfx::VectorIcon& icon_definition); - - // Sets whether the buttons should be painted as active. Does not schedule - // a repaint. - void SetPaintAsActive(bool paint_as_active); - - // Sets whether the buttons should be painted in a lighter color (for use on - // dark backgrounds). - void SetUseLightImages(bool light); - - // Tell the window controls to reset themselves to the normal state. - void ResetWindowControls(); - - // Determines the window HT* code for the caption button at |point|. Returns - // HTNOWHERE if |point| is not over any of the caption buttons. |point| must - // be in the coordinates of the FrameCaptionButtonContainerView. - int NonClientHitTest(const gfx::Point& point) const; - - // Updates the size button's visibility based on whether |frame_| can be - // maximized and if maximize mode is enabled. A parent view should relayout - // to reflect the change in visibility. - void UpdateSizeButtonVisibility(); - - // Sets the size of the buttons in this container. - void SetButtonSize(const gfx::Size& size); - - // views::View: - gfx::Size GetPreferredSize() const override; - void Layout() override; - const char* GetClassName() const override; - - // gfx::AnimationDelegate: - void AnimationEnded(const gfx::Animation* animation) override; - void AnimationProgressed(const gfx::Animation* animation) override; - - private: - friend class FrameCaptionButtonContainerViewTest; - - // Sets |button|'s icon to |icon|. If |animate| is ANIMATE_YES, the button - // will crossfade to the new icon. If |animate| is ANIMATE_NO and - // |icon| == |button|->icon(), the crossfade animation is progressed to the - // end. - void SetButtonIcon(FrameCaptionButton* button, - CaptionButtonIcon icon, - Animate animate); - - // Returns true if maximize mode is not enabled, and |frame_| widget delegate - // can be maximized. - bool ShouldSizeButtonBeVisible() const; - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // FrameSizeButtonDelegate: - bool IsMinimizeButtonVisible() const override; - void SetButtonsToNormal(Animate animate) override; - void SetButtonIcons(CaptionButtonIcon minimize_button_icon, - CaptionButtonIcon close_button_icon, - Animate animate) override; - const FrameCaptionButton* GetButtonClosestTo( - const gfx::Point& position_in_screen) const override; - void SetHoveredAndPressedButtons(const FrameCaptionButton* to_hover, - const FrameCaptionButton* to_press) override; - - // The widget that the buttons act on. - views::Widget* frame_; - - // The buttons. In the normal button style, at most one of |minimize_button_| - // and |size_button_| is visible. - FrameCaptionButton* minimize_button_; - FrameCaptionButton* size_button_; - FrameCaptionButton* close_button_; - - // Mapping of the image needed to paint a button for each of the values of - // CaptionButtonIcon. - std::map<CaptionButtonIcon, const gfx::VectorIcon*> button_icon_map_; - - // Animation that affects the position of |minimize_button_| and the - // visibility of |size_button_|. - std::unique_ptr<gfx::SlideAnimation> maximize_mode_animation_; - - DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerView); -}; - -} // namespace ash - -#endif // ASH_FRAME_CAPTION_BUTTONS_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc deleted file mode 100644 index f2be7fee..0000000 --- a/ash/frame/caption_buttons/frame_caption_button_container_view_unittest.cc +++ /dev/null
@@ -1,204 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" - -#include "ash/common/ash_layout_constants.h" -#include "ash/common/wm_shell.h" -#include "ash/frame/caption_buttons/frame_caption_button.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/test/ash_test_base.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { - -namespace { - -class TestWidgetDelegate : public views::WidgetDelegateView { - public: - TestWidgetDelegate(bool can_maximize, bool can_minimize) - : can_maximize_(can_maximize), can_minimize_(can_minimize) {} - ~TestWidgetDelegate() override {} - - bool CanMaximize() const override { return can_maximize_; } - - bool CanMinimize() const override { return can_minimize_; } - - private: - bool can_maximize_; - bool can_minimize_; - - DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); -}; - -} // namespace - -class FrameCaptionButtonContainerViewTest : public ash::test::AshTestBase { - public: - enum MaximizeAllowed { MAXIMIZE_ALLOWED, MAXIMIZE_DISALLOWED }; - - enum MinimizeAllowed { MINIMIZE_ALLOWED, MINIMIZE_DISALLOWED }; - - FrameCaptionButtonContainerViewTest() {} - - ~FrameCaptionButtonContainerViewTest() override {} - - // Creates a widget which allows maximizing based on |maximize_allowed|. - // The caller takes ownership of the returned widget. - views::Widget* CreateTestWidget(MaximizeAllowed maximize_allowed, - MinimizeAllowed minimize_allowed) - WARN_UNUSED_RESULT { - views::Widget* widget = new views::Widget; - views::Widget::InitParams params; - params.delegate = - new TestWidgetDelegate(maximize_allowed == MAXIMIZE_ALLOWED, - minimize_allowed == MINIMIZE_ALLOWED); - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.context = CurrentContext(); - widget->Init(params); - return widget; - } - - // Sets arbitrary images for the icons and assign the default caption button - // size to the buttons in |container|. - void InitContainer(FrameCaptionButtonContainerView* container) { - container->SetButtonSize( - GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); - for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) { - container->SetButtonImage(static_cast<CaptionButtonIcon>(icon), - ash::kWindowControlCloseIcon); - } - } - - // Tests that |leftmost| and |rightmost| are at |container|'s edges. - bool CheckButtonsAtEdges(FrameCaptionButtonContainerView* container, - const ash::FrameCaptionButton& leftmost, - const ash::FrameCaptionButton& rightmost) { - gfx::Rect expected(container->GetPreferredSize()); - - gfx::Rect container_size(container->GetPreferredSize()); - if (leftmost.y() == rightmost.y() && - leftmost.height() == rightmost.height() && - leftmost.x() == expected.x() && leftmost.y() == expected.y() && - leftmost.height() == expected.height() && - rightmost.bounds().right() == expected.right()) { - return true; - } - - LOG(ERROR) << "Buttons " << leftmost.bounds().ToString() << " " - << rightmost.bounds().ToString() << " not at edges of " - << expected.ToString(); - return false; - } - - private: - DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerViewTest); -}; - -// Test how the allowed actions affect which caption buttons are visible. -TEST_F(FrameCaptionButtonContainerViewTest, ButtonVisibility) { - // All the buttons should be visible when minimizing and maximizing are - // allowed. - FrameCaptionButtonContainerView container1( - CreateTestWidget(MAXIMIZE_ALLOWED, MINIMIZE_ALLOWED)); - InitContainer(&container1); - container1.Layout(); - FrameCaptionButtonContainerView::TestApi t1(&container1); - EXPECT_TRUE(t1.minimize_button()->visible()); - EXPECT_TRUE(t1.size_button()->visible()); - EXPECT_TRUE(t1.close_button()->visible()); - EXPECT_TRUE(CheckButtonsAtEdges(&container1, *t1.minimize_button(), - *t1.close_button())); - - // The minimize button should be visible when minimizing is allowed but - // maximizing is disallowed. - FrameCaptionButtonContainerView container2( - CreateTestWidget(MAXIMIZE_DISALLOWED, MINIMIZE_ALLOWED)); - InitContainer(&container2); - container2.Layout(); - FrameCaptionButtonContainerView::TestApi t2(&container2); - EXPECT_TRUE(t2.minimize_button()->visible()); - EXPECT_FALSE(t2.size_button()->visible()); - EXPECT_TRUE(t2.close_button()->visible()); - EXPECT_TRUE(CheckButtonsAtEdges(&container2, *t2.minimize_button(), - *t2.close_button())); - - // Neither the minimize button nor the size button should be visible when - // neither minimizing nor maximizing are allowed. - FrameCaptionButtonContainerView container3( - CreateTestWidget(MAXIMIZE_DISALLOWED, MINIMIZE_DISALLOWED)); - InitContainer(&container3); - container3.Layout(); - FrameCaptionButtonContainerView::TestApi t3(&container3); - EXPECT_FALSE(t3.minimize_button()->visible()); - EXPECT_FALSE(t3.size_button()->visible()); - EXPECT_TRUE(t3.close_button()->visible()); - EXPECT_TRUE( - CheckButtonsAtEdges(&container3, *t3.close_button(), *t3.close_button())); -} - -// Tests that the layout animations trigered by button visibility result in the -// correct placement of the buttons. -TEST_F(FrameCaptionButtonContainerViewTest, - TestUpdateSizeButtonVisibilityAnimation) { - FrameCaptionButtonContainerView container( - CreateTestWidget(MAXIMIZE_ALLOWED, MINIMIZE_ALLOWED)); - InitContainer(&container); - container.SetBoundsRect(gfx::Rect(container.GetPreferredSize())); - container.Layout(); - - FrameCaptionButtonContainerView::TestApi test(&container); - gfx::Rect initial_minimize_button_bounds = test.minimize_button()->bounds(); - gfx::Rect initial_size_button_bounds = test.size_button()->bounds(); - gfx::Rect initial_close_button_bounds = test.close_button()->bounds(); - gfx::Rect initial_container_bounds = container.bounds(); - - ASSERT_EQ(initial_size_button_bounds.x(), - initial_minimize_button_bounds.right()); - ASSERT_EQ(initial_close_button_bounds.x(), - initial_size_button_bounds.right()); - - // Hidden size button should result in minimize button animating to the - // right. The size button should not be visible, but should not have moved. - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - container.UpdateSizeButtonVisibility(); - test.EndAnimations(); - // Parent needs to layout in response to size change. - container.Layout(); - - EXPECT_TRUE(test.minimize_button()->visible()); - EXPECT_FALSE(test.size_button()->visible()); - EXPECT_TRUE(test.close_button()->visible()); - gfx::Rect minimize_button_bounds = test.minimize_button()->bounds(); - gfx::Rect close_button_bounds = test.close_button()->bounds(); - EXPECT_EQ(close_button_bounds.x(), minimize_button_bounds.right()); - EXPECT_EQ(initial_size_button_bounds, test.size_button()->bounds()); - EXPECT_EQ(initial_close_button_bounds.size(), close_button_bounds.size()); - EXPECT_LT(container.GetPreferredSize().width(), - initial_container_bounds.width()); - - // Revealing the size button should cause the minimize button to return to its - // original position. - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - container.UpdateSizeButtonVisibility(); - // Calling code needs to layout in response to size change. - container.Layout(); - test.EndAnimations(); - EXPECT_TRUE(test.minimize_button()->visible()); - EXPECT_TRUE(test.size_button()->visible()); - EXPECT_TRUE(test.close_button()->visible()); - EXPECT_EQ(initial_minimize_button_bounds, test.minimize_button()->bounds()); - EXPECT_EQ(initial_size_button_bounds, test.size_button()->bounds()); - EXPECT_EQ(initial_close_button_bounds, test.close_button()->bounds()); - EXPECT_EQ(container.GetPreferredSize().width(), - initial_container_bounds.width()); -} - -} // namespace ash
diff --git a/ash/frame/caption_buttons/frame_size_button.cc b/ash/frame/caption_buttons/frame_size_button.cc deleted file mode 100644 index 7fa8612a..0000000 --- a/ash/frame/caption_buttons/frame_size_button.cc +++ /dev/null
@@ -1,270 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/caption_buttons/frame_size_button.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace/phantom_window_controller.h" -#include "base/i18n/rtl.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -namespace { - -// The default delay between the user pressing the size button and the buttons -// adjacent to the size button morphing into buttons for snapping left and -// right. -const int kSetButtonsToSnapModeDelayMs = 150; - -// The amount that a user can overshoot one of the caption buttons while in -// "snap mode" and keep the button hovered/pressed. -const int kMaxOvershootX = 200; -const int kMaxOvershootY = 50; - -// Returns true if a mouse drag while in "snap mode" at |location_in_screen| -// would hover/press |button| or keep it hovered/pressed. -bool HitTestButton(const FrameCaptionButton* button, - const gfx::Point& location_in_screen) { - gfx::Rect expanded_bounds_in_screen = button->GetBoundsInScreen(); - if (button->state() == views::Button::STATE_HOVERED || - button->state() == views::Button::STATE_PRESSED) { - expanded_bounds_in_screen.Inset(-kMaxOvershootX, -kMaxOvershootY); - } - return expanded_bounds_in_screen.Contains(location_in_screen); -} - -} // namespace - -FrameSizeButton::FrameSizeButton(views::ButtonListener* listener, - views::Widget* frame, - FrameSizeButtonDelegate* delegate) - : FrameCaptionButton(listener, CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE), - frame_(frame), - delegate_(delegate), - set_buttons_to_snap_mode_delay_ms_(kSetButtonsToSnapModeDelayMs), - in_snap_mode_(false), - snap_type_(SNAP_NONE) {} - -FrameSizeButton::~FrameSizeButton() {} - -bool FrameSizeButton::OnMousePressed(const ui::MouseEvent& event) { - // The minimize and close buttons are set to snap left and right when snapping - // is enabled. Do not enable snapping if the minimize button is not visible. - // The close button is always visible. - if (IsTriggerableEvent(event) && !in_snap_mode_ && - delegate_->IsMinimizeButtonVisible()) { - StartSetButtonsToSnapModeTimer(event); - } - FrameCaptionButton::OnMousePressed(event); - return true; -} - -bool FrameSizeButton::OnMouseDragged(const ui::MouseEvent& event) { - UpdateSnapType(event); - // By default a FrameCaptionButton reverts to STATE_NORMAL once the mouse - // leaves its bounds. Skip FrameCaptionButton's handling when - // |in_snap_mode_| == true because we want different behavior. - if (!in_snap_mode_) - FrameCaptionButton::OnMouseDragged(event); - return true; -} - -void FrameSizeButton::OnMouseReleased(const ui::MouseEvent& event) { - if (!IsTriggerableEvent(event) || !CommitSnap(event)) - FrameCaptionButton::OnMouseReleased(event); -} - -void FrameSizeButton::OnMouseCaptureLost() { - SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); - FrameCaptionButton::OnMouseCaptureLost(); -} - -void FrameSizeButton::OnMouseMoved(const ui::MouseEvent& event) { - // Ignore any synthetic mouse moves during a drag. - if (!in_snap_mode_) - FrameCaptionButton::OnMouseMoved(event); -} - -void FrameSizeButton::OnGestureEvent(ui::GestureEvent* event) { - if (event->details().touch_points() > 1) { - SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); - return; - } - - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - StartSetButtonsToSnapModeTimer(*event); - // Go through FrameCaptionButton's handling so that the button gets pressed. - FrameCaptionButton::OnGestureEvent(event); - return; - } - - if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || - event->type() == ui::ET_GESTURE_SCROLL_UPDATE) { - UpdateSnapType(*event); - event->SetHandled(); - return; - } - - if (event->type() == ui::ET_GESTURE_TAP || - event->type() == ui::ET_GESTURE_SCROLL_END || - event->type() == ui::ET_SCROLL_FLING_START || - event->type() == ui::ET_GESTURE_END) { - if (CommitSnap(*event)) { - event->SetHandled(); - return; - } - } - - FrameCaptionButton::OnGestureEvent(event); -} - -void FrameSizeButton::StartSetButtonsToSnapModeTimer( - const ui::LocatedEvent& event) { - set_buttons_to_snap_mode_timer_event_location_ = event.location(); - if (set_buttons_to_snap_mode_delay_ms_ == 0) { - AnimateButtonsToSnapMode(); - } else { - set_buttons_to_snap_mode_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(set_buttons_to_snap_mode_delay_ms_), - this, &FrameSizeButton::AnimateButtonsToSnapMode); - } -} - -void FrameSizeButton::AnimateButtonsToSnapMode() { - SetButtonsToSnapMode(FrameSizeButtonDelegate::ANIMATE_YES); -} - -void FrameSizeButton::SetButtonsToSnapMode( - FrameSizeButtonDelegate::Animate animate) { - in_snap_mode_ = true; - - // When using a right-to-left layout the close button is left of the size - // button and the minimize button is right of the size button. - if (base::i18n::IsRTL()) { - delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - CAPTION_BUTTON_ICON_LEFT_SNAPPED, animate); - } else { - delegate_->SetButtonIcons(CAPTION_BUTTON_ICON_LEFT_SNAPPED, - CAPTION_BUTTON_ICON_RIGHT_SNAPPED, animate); - } -} - -void FrameSizeButton::UpdateSnapType(const ui::LocatedEvent& event) { - if (!in_snap_mode_) { - // Set the buttons adjacent to the size button to snap left and right early - // if the user drags past the drag threshold. - // |set_buttons_to_snap_mode_timer_| is checked to avoid entering the snap - // mode as a result of an unsupported drag type (e.g. only the right mouse - // button is pressed). - gfx::Vector2d delta(event.location() - - set_buttons_to_snap_mode_timer_event_location_); - if (!set_buttons_to_snap_mode_timer_.IsRunning() || - !views::View::ExceededDragThreshold(delta)) { - return; - } - AnimateButtonsToSnapMode(); - } - - gfx::Point event_location_in_screen(event.location()); - views::View::ConvertPointToScreen(this, &event_location_in_screen); - const FrameCaptionButton* to_hover = - GetButtonToHover(event_location_in_screen); - bool press_size_button = - to_hover || HitTestButton(this, event_location_in_screen); - - if (to_hover) { - // Progress the minimize and close icon morph animations to the end if they - // are in progress. - SetButtonsToSnapMode(FrameSizeButtonDelegate::ANIMATE_NO); - } - - delegate_->SetHoveredAndPressedButtons(to_hover, - press_size_button ? this : NULL); - - snap_type_ = SNAP_NONE; - if (to_hover) { - switch (to_hover->icon()) { - case CAPTION_BUTTON_ICON_LEFT_SNAPPED: - snap_type_ = SNAP_LEFT; - break; - case CAPTION_BUTTON_ICON_RIGHT_SNAPPED: - snap_type_ = SNAP_RIGHT; - break; - case CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE: - case CAPTION_BUTTON_ICON_MINIMIZE: - case CAPTION_BUTTON_ICON_CLOSE: - case CAPTION_BUTTON_ICON_BACK: - case CAPTION_BUTTON_ICON_LOCATION: - case CAPTION_BUTTON_ICON_COUNT: - NOTREACHED(); - break; - } - } - - if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { - WmWindow* window = WmWindow::Get(frame_->GetNativeWindow()); - if (!phantom_window_controller_.get()) - phantom_window_controller_.reset(new PhantomWindowController(window)); - gfx::Rect phantom_bounds_in_parent = - (snap_type_ == SNAP_LEFT) - ? wm::GetDefaultLeftSnappedWindowBoundsInParent(window) - : wm::GetDefaultRightSnappedWindowBoundsInParent(window); - phantom_window_controller_->Show( - window->GetParent()->ConvertRectToScreen(phantom_bounds_in_parent)); - } else { - phantom_window_controller_.reset(); - } -} - -const FrameCaptionButton* FrameSizeButton::GetButtonToHover( - const gfx::Point& event_location_in_screen) const { - const FrameCaptionButton* closest_button = - delegate_->GetButtonClosestTo(event_location_in_screen); - if ((closest_button->icon() == CAPTION_BUTTON_ICON_LEFT_SNAPPED || - closest_button->icon() == CAPTION_BUTTON_ICON_RIGHT_SNAPPED) && - HitTestButton(closest_button, event_location_in_screen)) { - return closest_button; - } - return NULL; -} - -bool FrameSizeButton::CommitSnap(const ui::LocatedEvent& event) { - // The position of |event| may be different than the position of the previous - // event. - UpdateSnapType(event); - - if (in_snap_mode_ && (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT)) { - WmWindow* window = WmWindow::Get(frame_->GetNativeWindow()); - wm::WindowState* window_state = window->GetWindowState(); - const wm::WMEvent snap_event(snap_type_ == SNAP_LEFT - ? wm::WM_EVENT_SNAP_LEFT - : wm::WM_EVENT_SNAP_RIGHT); - window_state->OnWMEvent(&snap_event); - WmShell::Get()->RecordUserMetricsAction( - snap_type_ == SNAP_LEFT ? UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT - : UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT); - SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_NO); - return true; - } - SetButtonsToNormalMode(FrameSizeButtonDelegate::ANIMATE_YES); - return false; -} - -void FrameSizeButton::SetButtonsToNormalMode( - FrameSizeButtonDelegate::Animate animate) { - in_snap_mode_ = false; - snap_type_ = SNAP_NONE; - set_buttons_to_snap_mode_timer_.Stop(); - delegate_->SetButtonsToNormal(animate); - phantom_window_controller_.reset(); -} - -} // namespace ash
diff --git a/ash/frame/caption_buttons/frame_size_button.h b/ash/frame/caption_buttons/frame_size_button.h deleted file mode 100644 index bebca5a..0000000 --- a/ash/frame/caption_buttons/frame_size_button.h +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ -#define ASH_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/frame/caption_buttons/frame_caption_button.h" -#include "ash/frame/caption_buttons/frame_size_button_delegate.h" -#include "base/macros.h" -#include "base/timer/timer.h" - -namespace views { -class Widget; -} - -namespace ash { -class FrameSizeButtonDelegate; -class PhantomWindowController; - -// The maximize/restore button. -// When the mouse is pressed over the size button or the size button is touched: -// - The minimize and close buttons are set to snap left and snap right -// respectively. -// - The size button stays pressed while the mouse is over the buttons to snap -// left and to snap right. The button underneath the mouse is hovered. -// When the drag terminates, the action for the button underneath the mouse -// is executed. For the sake of simplicity, the size button is the event -// handler for a click starting on the size button and the entire drag. -class ASH_EXPORT FrameSizeButton : public FrameCaptionButton { - public: - FrameSizeButton(views::ButtonListener* listener, - views::Widget* frame, - FrameSizeButtonDelegate* delegate); - - ~FrameSizeButton() override; - - // views::CustomButton overrides: - bool OnMousePressed(const ui::MouseEvent& event) override; - bool OnMouseDragged(const ui::MouseEvent& event) override; - void OnMouseReleased(const ui::MouseEvent& event) override; - void OnMouseCaptureLost() override; - void OnMouseMoved(const ui::MouseEvent& event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - - void set_delay_to_set_buttons_to_snap_mode(int delay_ms) { - set_buttons_to_snap_mode_delay_ms_ = delay_ms; - } - - private: - enum SnapType { SNAP_LEFT, SNAP_RIGHT, SNAP_NONE }; - - // Starts |set_buttons_to_snap_mode_timer_|. - void StartSetButtonsToSnapModeTimer(const ui::LocatedEvent& event); - - // Animates the buttons adjacent to the size button to snap left and right. - void AnimateButtonsToSnapMode(); - - // Sets the buttons adjacent to the size button to snap left and right. - // Passing in ANIMATE_NO progresses the animation (if any) to the end. - void SetButtonsToSnapMode(FrameSizeButtonDelegate::Animate animate); - - // Updates |snap_type_|, whether the size button is pressed and whether any - // other buttons are hovered. - void UpdateSnapType(const ui::LocatedEvent& event); - - // Returns the button which should be hovered (if any) while in "snap mode" - // for |event_location_in_screen|. - const FrameCaptionButton* GetButtonToHover( - const gfx::Point& event_location_in_screen) const; - - // Snaps |frame_| according to |snap_type_|. Returns true if |frame_| was - // snapped. - bool CommitSnap(const ui::LocatedEvent& event); - - // Sets the buttons adjacent to the size button to minimize and close again. - // Clears any state set while snapping was enabled. |animate| indicates - // whether the buttons should animate back to their original icons. - void SetButtonsToNormalMode(FrameSizeButtonDelegate::Animate animate); - - // Widget that the size button acts on. - views::Widget* frame_; - - // Not owned. - FrameSizeButtonDelegate* delegate_; - - // Location of the event which started |set_buttons_to_snap_mode_timer_| in - // view coordinates. - gfx::Point set_buttons_to_snap_mode_timer_event_location_; - - // The delay between the user pressing the size button and the buttons - // adjacent to the size button morphing into buttons for snapping left and - // right. - int set_buttons_to_snap_mode_delay_ms_; - - base::OneShotTimer set_buttons_to_snap_mode_timer_; - - // Whether the buttons adjacent to the size button snap the window left and - // right. - bool in_snap_mode_; - - // The action to execute when the drag/click is ended. If - // |snap_type_| == SNAP_NONE, the size button's default action is run when the - // drag/click is ended. - SnapType snap_type_; - - // Displays a preview of how the window's bounds will change as a result of - // snapping the window left or right. The preview is only visible if the snap - // left or snap right button is pressed. - std::unique_ptr<PhantomWindowController> phantom_window_controller_; - - DISALLOW_COPY_AND_ASSIGN(FrameSizeButton); -}; - -} // namespace ash - -#endif // ASH_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_H_
diff --git a/ash/frame/caption_buttons/frame_size_button_delegate.h b/ash/frame/caption_buttons/frame_size_button_delegate.h deleted file mode 100644 index 87ee688..0000000 --- a/ash/frame/caption_buttons/frame_size_button_delegate.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ -#define ASH_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_ - -#include "ash/ash_export.h" -#include "ash/frame/caption_buttons/caption_button_types.h" - -namespace gfx { -class Point; -} - -namespace ash { -class FrameCaptionButton; - -// Delegate interface for FrameSizeButton. -class ASH_EXPORT FrameSizeButtonDelegate { - public: - enum Animate { ANIMATE_YES, ANIMATE_NO }; - - // Returns whether the minimize button is visible. - virtual bool IsMinimizeButtonVisible() const = 0; - - // Reset the caption button views::Button::ButtonState back to normal. If - // |animate| is ANIMATE_YES, the buttons will crossfade back to their - // original icons. - virtual void SetButtonsToNormal(Animate animate) = 0; - - // Sets the minimize and close button icons. The buttons will crossfade to - // their new icons if |animate| is ANIMATE_YES. - virtual void SetButtonIcons(CaptionButtonIcon minimize_button_icon, - CaptionButtonIcon close_button_icon, - Animate animate) = 0; - - // Returns the button closest to |position_in_screen|. - virtual const FrameCaptionButton* GetButtonClosestTo( - const gfx::Point& position_in_screen) const = 0; - - // Sets |to_hover| and |to_pressed| to STATE_HOVERED and STATE_PRESSED - // respectively. All other buttons are to set to STATE_NORMAL. - virtual void SetHoveredAndPressedButtons( - const FrameCaptionButton* to_hover, - const FrameCaptionButton* to_press) = 0; - - protected: - virtual ~FrameSizeButtonDelegate() {} -}; - -} // namespace ash - -#endif // ASH_FRAME_CAPTION_BUTTONS_FRAME_SIZE_BUTTON_DELEGATE_H_
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc index 9742dbf..e7bfe7b4 100644 --- a/ash/frame/caption_buttons/frame_size_button_unittest.cc +++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/frame/caption_buttons/frame_size_button.h" +#include "ash/common/frame/caption_buttons/frame_size_button.h" #include "ash/common/ash_layout_constants.h" -#include "ash/frame/caption_buttons/frame_caption_button.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/caption_buttons/frame_caption_button.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/wm/window_state.h" #include "ash/resources/grit/ash_resources.h" #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/i18n/rtl.h" #include "ui/aura/window.h"
diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc deleted file mode 100644 index a41420ff..0000000 --- a/ash/frame/custom_frame_view_ash.cc +++ /dev/null
@@ -1,362 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/custom_frame_view_ash.h" - -#include <algorithm> -#include <vector> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/frame_border_hit_test.h" -#include "ash/frame/header_view.h" -#include "ash/shared/immersive_fullscreen_controller.h" -#include "ash/shared/immersive_fullscreen_controller_delegate.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_delegate.h" -#include "ash/wm/window_state_observer.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/window.h" -#include "ui/aura/window_observer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/rect_conversions.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/view.h" -#include "ui/views/view_targeter.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { - -namespace { - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAshWindowStateDelegate - -// Handles a user's fullscreen request (Shift+F4/F4). Puts the window into -// immersive fullscreen if immersive fullscreen is enabled for non-browser -// windows. -class CustomFrameViewAshWindowStateDelegate : public wm::WindowStateDelegate, - public wm::WindowStateObserver, - public aura::WindowObserver { - public: - CustomFrameViewAshWindowStateDelegate(wm::WindowState* window_state, - CustomFrameViewAsh* custom_frame_view, - bool enable_immersive) - : window_state_(nullptr) { - // Add a window state observer to exit fullscreen properly in case - // fullscreen is exited without going through - // WindowState::ToggleFullscreen(). This is the case when exiting - // immersive fullscreen via the "Restore" window control. - // TODO(pkotwicz): This is a hack. Remove ASAP. http://crbug.com/319048 - window_state_ = window_state; - window_state_->AddObserver(this); - window_state_->window()->aura_window()->AddObserver(this); - - if (!enable_immersive) - return; - - immersive_fullscreen_controller_ = - WmShell::Get()->CreateImmersiveFullscreenController(); - if (immersive_fullscreen_controller_) { - custom_frame_view->InitImmersiveFullscreenControllerForView( - immersive_fullscreen_controller_.get()); - } - } - ~CustomFrameViewAshWindowStateDelegate() override { - if (window_state_) { - window_state_->RemoveObserver(this); - window_state_->window()->aura_window()->RemoveObserver(this); - } - } - - private: - // Overridden from wm::WindowStateDelegate: - bool ToggleFullscreen(wm::WindowState* window_state) override { - bool enter_fullscreen = !window_state->IsFullscreen(); - if (enter_fullscreen) - window_state_->window()->SetShowState(ui::SHOW_STATE_FULLSCREEN); - else - window_state->Restore(); - if (immersive_fullscreen_controller_) { - immersive_fullscreen_controller_->SetEnabled( - ImmersiveFullscreenController::WINDOW_TYPE_OTHER, enter_fullscreen); - } - return true; - } - // Overridden from aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override { - window_state_->RemoveObserver(this); - window->RemoveObserver(this); - window_state_ = nullptr; - } - // Overridden from wm::WindowStateObserver: - void OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) override { - if (!window_state->IsFullscreen() && !window_state->IsMinimized() && - immersive_fullscreen_controller_ && - immersive_fullscreen_controller_->IsEnabled()) { - immersive_fullscreen_controller_->SetEnabled( - ImmersiveFullscreenController::WINDOW_TYPE_OTHER, false); - } - } - - wm::WindowState* window_state_; - std::unique_ptr<ImmersiveFullscreenController> - immersive_fullscreen_controller_; - - DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshWindowStateDelegate); -}; - -} // namespace - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh::OverlayView - -// View which takes up the entire widget and contains the HeaderView. HeaderView -// is a child of OverlayView to avoid creating a larger texture than necessary -// when painting the HeaderView to its own layer. -class CustomFrameViewAsh::OverlayView : public views::View, - public views::ViewTargeterDelegate { - public: - explicit OverlayView(HeaderView* header_view); - ~OverlayView() override; - - // views::View: - void Layout() override; - - private: - // views::ViewTargeterDelegate: - bool DoesIntersectRect(const views::View* target, - const gfx::Rect& rect) const override; - - HeaderView* header_view_; - - DISALLOW_COPY_AND_ASSIGN(OverlayView); -}; - -CustomFrameViewAsh::OverlayView::OverlayView(HeaderView* header_view) - : header_view_(header_view) { - AddChildView(header_view); - SetEventTargeter( - std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); -} - -CustomFrameViewAsh::OverlayView::~OverlayView() {} - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh::OverlayView, views::View overrides: - -void CustomFrameViewAsh::OverlayView::Layout() { - // Layout |header_view_| because layout affects the result of - // GetPreferredOnScreenHeight(). - header_view_->Layout(); - - int onscreen_height = header_view_->GetPreferredOnScreenHeight(); - if (onscreen_height == 0) { - header_view_->SetVisible(false); - } else { - int height = header_view_->GetPreferredHeight(); - header_view_->SetBounds(0, onscreen_height - height, width(), height); - header_view_->SetVisible(true); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh::OverlayView, views::ViewTargeterDelegate overrides: - -bool CustomFrameViewAsh::OverlayView::DoesIntersectRect( - const views::View* target, - const gfx::Rect& rect) const { - CHECK_EQ(target, this); - // Grab events in the header view. Return false for other events so that they - // can be handled by the client view. - return header_view_->HitTestRect(rect); -} - -//////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh, public: - -// static -const char CustomFrameViewAsh::kViewClassName[] = "CustomFrameViewAsh"; - -CustomFrameViewAsh::CustomFrameViewAsh( - views::Widget* frame, - ImmersiveFullscreenControllerDelegate* immersive_delegate, - bool enable_immersive) - : frame_(frame), - header_view_(new HeaderView(frame)), - immersive_delegate_(immersive_delegate ? immersive_delegate - : header_view_) { - WmWindow* frame_window = WmWindow::Get(frame->GetNativeWindow()); - frame_window->InstallResizeHandleWindowTargeter(nullptr); - // |header_view_| is set as the non client view's overlay view so that it can - // overlay the web contents in immersive fullscreen. - frame->non_client_view()->SetOverlayView(new OverlayView(header_view_)); - frame_window->aura_window()->SetProperty( - aura::client::kTopViewColor, header_view_->GetInactiveFrameColor()); - - // A delegate for a more complex way of fullscreening the window may already - // be set. This is the case for packaged apps. - wm::WindowState* window_state = frame_window->GetWindowState(); - if (!window_state->HasDelegate()) { - window_state->SetDelegate(std::unique_ptr<wm::WindowStateDelegate>( - new CustomFrameViewAshWindowStateDelegate(window_state, this, - enable_immersive))); - } -} - -CustomFrameViewAsh::~CustomFrameViewAsh() {} - -void CustomFrameViewAsh::InitImmersiveFullscreenControllerForView( - ImmersiveFullscreenController* immersive_fullscreen_controller) { - immersive_fullscreen_controller->Init(immersive_delegate_, frame_, - header_view_); -} - -void CustomFrameViewAsh::SetFrameColors(SkColor active_frame_color, - SkColor inactive_frame_color) { - header_view_->SetFrameColors(active_frame_color, inactive_frame_color); - WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow()); - frame_window->aura_window()->SetProperty( - aura::client::kTopViewColor, header_view_->GetInactiveFrameColor()); -} - -//////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh, views::NonClientFrameView overrides: - -gfx::Rect CustomFrameViewAsh::GetBoundsForClientView() const { - gfx::Rect client_bounds = bounds(); - client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); - return client_bounds; -} - -gfx::Rect CustomFrameViewAsh::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const { - gfx::Rect window_bounds = client_bounds; - window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); - return window_bounds; -} - -int CustomFrameViewAsh::NonClientHitTest(const gfx::Point& point) { - return FrameBorderNonClientHitTest( - this, header_view_->caption_button_container(), point); -} - -void CustomFrameViewAsh::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) { - // No window masks in Aura. -} - -void CustomFrameViewAsh::ResetWindowControls() { - header_view_->ResetWindowControls(); -} - -void CustomFrameViewAsh::UpdateWindowIcon() {} - -void CustomFrameViewAsh::UpdateWindowTitle() { - header_view_->SchedulePaintForTitle(); -} - -void CustomFrameViewAsh::SizeConstraintsChanged() { - header_view_->SizeConstraintsChanged(); -} - -void CustomFrameViewAsh::ActivationChanged(bool active) { - // The icons differ between active and inactive. - header_view_->SchedulePaint(); -} - -//////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh, views::View overrides: - -gfx::Size CustomFrameViewAsh::GetPreferredSize() const { - gfx::Size pref = frame_->client_view()->GetPreferredSize(); - gfx::Rect bounds(0, 0, pref.width(), pref.height()); - return frame_->non_client_view() - ->GetWindowBoundsForClientBounds(bounds) - .size(); -} - -void CustomFrameViewAsh::Layout() { - views::NonClientFrameView::Layout(); - WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow()); - frame_window->aura_window()->SetProperty(aura::client::kTopViewInset, - NonClientTopBorderHeight()); -} - -const char* CustomFrameViewAsh::GetClassName() const { - return kViewClassName; -} - -gfx::Size CustomFrameViewAsh::GetMinimumSize() const { - gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize()); - return gfx::Size( - std::max(header_view_->GetMinimumWidth(), min_client_view_size.width()), - NonClientTopBorderHeight() + min_client_view_size.height()); -} - -gfx::Size CustomFrameViewAsh::GetMaximumSize() const { - gfx::Size max_client_size(frame_->client_view()->GetMaximumSize()); - int width = 0; - int height = 0; - - if (max_client_size.width() > 0) - width = std::max(header_view_->GetMinimumWidth(), max_client_size.width()); - if (max_client_size.height() > 0) - height = NonClientTopBorderHeight() + max_client_size.height(); - - return gfx::Size(width, height); -} - -void CustomFrameViewAsh::SchedulePaintInRect(const gfx::Rect& r) { - // We may end up here before |header_view_| has been added to the Widget. - if (header_view_->GetWidget()) { - // The HeaderView is not a child of CustomFrameViewAsh. Redirect the paint - // to HeaderView instead. - gfx::RectF to_paint(r); - views::View::ConvertRectToTarget(this, header_view_, &to_paint); - header_view_->SchedulePaintInRect(gfx::ToEnclosingRect(to_paint)); - } else { - views::NonClientFrameView::SchedulePaintInRect(r); - } -} - -void CustomFrameViewAsh::VisibilityChanged(views::View* starting_from, - bool is_visible) { - if (is_visible) - header_view_->UpdateAvatarIcon(); -} - -views::View* CustomFrameViewAsh::GetHeaderView() { - return header_view_; -} - -const views::View* CustomFrameViewAsh::GetAvatarIconViewForTest() const { - return header_view_->avatar_icon(); -} - -//////////////////////////////////////////////////////////////////////////////// -// CustomFrameViewAsh, private: - -// views::NonClientFrameView: -bool CustomFrameViewAsh::DoesIntersectRect(const views::View* target, - const gfx::Rect& rect) const { - CHECK_EQ(target, this); - // NonClientView hit tests the NonClientFrameView first instead of going in - // z-order. Return false so that events get to the OverlayView. - return false; -} - -FrameCaptionButtonContainerView* -CustomFrameViewAsh::GetFrameCaptionButtonContainerViewForTest() { - return header_view_->caption_button_container(); -} - -int CustomFrameViewAsh::NonClientTopBorderHeight() const { - return frame_->IsFullscreen() ? 0 : header_view_->GetPreferredHeight(); -} - -} // namespace ash
diff --git a/ash/frame/custom_frame_view_ash.h b/ash/frame/custom_frame_view_ash.h deleted file mode 100644 index c012c05..0000000 --- a/ash/frame/custom_frame_view_ash.h +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_CUSTOM_FRAME_VIEW_ASH_H_ -#define ASH_FRAME_CUSTOM_FRAME_VIEW_ASH_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/views/window/non_client_view.h" - -namespace views { -class Widget; -} - -namespace ash { - -class FrameCaptionButtonContainerView; -class HeaderView; -class ImmersiveFullscreenController; -class ImmersiveFullscreenControllerDelegate; - -// A NonClientFrameView used for packaged apps, dialogs and other non-browser -// windows. It supports immersive fullscreen. When in immersive fullscreen, the -// client view takes up the entire widget and the window header is an overlay. -// The window header overlay slides onscreen when the user hovers the mouse at -// the top of the screen. See also views::CustomFrameView and -// BrowserNonClientFrameViewAsh. -class ASH_EXPORT CustomFrameViewAsh : public views::NonClientFrameView { - public: - // Internal class name. - static const char kViewClassName[]; - - // |enable_immersive| controls whether ImmersiveFullscreenController is - // created for the CustomFrameViewAsh; if true and a WindowStateDelegate has - // not been set on the WindowState associated with |frame|, then an - // ImmersiveFullscreenController is created. - // If ImmersiveFullscreenControllerDelegate is not supplied, HeaderView is - // used as the ImmersiveFullscreenControllerDelegate. - explicit CustomFrameViewAsh( - views::Widget* frame, - ImmersiveFullscreenControllerDelegate* immersive_delegate = nullptr, - bool enable_immersive = true); - ~CustomFrameViewAsh() override; - - // Inits |immersive_fullscreen_controller| so that the controller reveals - // and hides |header_view_| in immersive fullscreen. - // CustomFrameViewAsh does not take ownership of - // |immersive_fullscreen_controller|. - void InitImmersiveFullscreenControllerForView( - ImmersiveFullscreenController* immersive_fullscreen_controller); - - // Sets the active and inactive frame colors. Note the inactive frame color - // will have some transparency added when the frame is drawn. - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - - // views::NonClientFrameView: - gfx::Rect GetBoundsForClientView() const override; - gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const override; - int NonClientHitTest(const gfx::Point& point) override; - void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override; - void ResetWindowControls() override; - void UpdateWindowIcon() override; - void UpdateWindowTitle() override; - void SizeConstraintsChanged() override; - void ActivationChanged(bool active) override; - - // views::View: - gfx::Size GetPreferredSize() const override; - void Layout() override; - const char* GetClassName() const override; - gfx::Size GetMinimumSize() const override; - gfx::Size GetMaximumSize() const override; - void SchedulePaintInRect(const gfx::Rect& r) override; - void VisibilityChanged(views::View* starting_from, bool is_visible) override; - - // Get the view of the header. - views::View* GetHeaderView(); - - const views::View* GetAvatarIconViewForTest() const; - - private: - class OverlayView; - friend class TestWidgetConstraintsDelegate; - - // views::NonClientFrameView: - bool DoesIntersectRect(const views::View* target, - const gfx::Rect& rect) const override; - - // Returns the container for the minimize/maximize/close buttons that is held - // by the HeaderView. Used in testing. - FrameCaptionButtonContainerView* GetFrameCaptionButtonContainerViewForTest(); - - // Height from top of window to top of client area. - int NonClientTopBorderHeight() const; - - // Not owned. - views::Widget* frame_; - - // View which contains the title and window controls. - HeaderView* header_view_; - - ImmersiveFullscreenControllerDelegate* immersive_delegate_; - - DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAsh); -}; - -} // namespace ash - -#endif // ASH_FRAME_CUSTOM_FRAME_VIEW_ASH_H_
diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc deleted file mode 100644 index 27c7e272..0000000 --- a/ash/frame/custom_frame_view_ash_unittest.cc +++ /dev/null
@@ -1,227 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/custom_frame_view_ash.h" - -#include <memory> - -#include "ash/common/ash_layout_constants.h" -#include "ash/common/wm_shell.h" -#include "ash/frame/caption_buttons/frame_caption_button.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/image/image_unittest_util.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { - -// A views::WidgetDelegate which uses a CustomFrameViewAsh. -class TestWidgetDelegate : public views::WidgetDelegateView { - public: - TestWidgetDelegate() {} - ~TestWidgetDelegate() override {} - - views::NonClientFrameView* CreateNonClientFrameView( - views::Widget* widget) override { - custom_frame_view_ = new CustomFrameViewAsh(widget); - return custom_frame_view_; - } - - CustomFrameViewAsh* custom_frame_view() const { return custom_frame_view_; } - - private: - // Not owned. - CustomFrameViewAsh* custom_frame_view_; - - DISALLOW_COPY_AND_ASSIGN(TestWidgetDelegate); -}; - -class TestWidgetConstraintsDelegate : public TestWidgetDelegate { - public: - TestWidgetConstraintsDelegate() {} - ~TestWidgetConstraintsDelegate() override {} - - // views::View: - gfx::Size GetMinimumSize() const override { return minimum_size_; } - - gfx::Size GetMaximumSize() const override { return maximum_size_; } - - views::View* GetContentsView() override { - // Set this instance as the contents view so that the maximum and minimum - // size constraints will be used. - return this; - } - - // views::WidgetDelegate: - bool CanMaximize() const override { return true; } - - bool CanMinimize() const override { return true; } - - void set_minimum_size(const gfx::Size& min_size) { minimum_size_ = min_size; } - - void set_maximum_size(const gfx::Size& max_size) { maximum_size_ = max_size; } - - const gfx::Rect& GetFrameCaptionButtonContainerViewBounds() { - return custom_frame_view() - ->GetFrameCaptionButtonContainerViewForTest() - ->bounds(); - } - - void EndFrameCaptionButtonContainerViewAnimations() { - FrameCaptionButtonContainerView::TestApi test( - custom_frame_view()->GetFrameCaptionButtonContainerViewForTest()); - test.EndAnimations(); - } - - int GetTitleBarHeight() const { - return custom_frame_view()->NonClientTopBorderHeight(); - } - - private: - gfx::Size minimum_size_; - gfx::Size maximum_size_; - - DISALLOW_COPY_AND_ASSIGN(TestWidgetConstraintsDelegate); -}; - -class CustomFrameViewAshTest : public test::AshTestBase { - public: - CustomFrameViewAshTest() {} - ~CustomFrameViewAshTest() override {} - - protected: - std::unique_ptr<views::Widget> CreateWidget(TestWidgetDelegate* delegate) { - std::unique_ptr<views::Widget> widget(new views::Widget); - views::Widget::InitParams params; - params.delegate = delegate; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = gfx::Rect(0, 0, 100, 100); - params.context = CurrentContext(); - widget->Init(params); - return widget; - } - - test::TestSessionStateDelegate* GetTestSessionStateDelegate() { - return static_cast<test::TestSessionStateDelegate*>( - WmShell::Get()->GetSessionStateDelegate()); - } - - private: - DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAshTest); -}; - -// Verifies the client view is not placed at a y location of 0. -TEST_F(CustomFrameViewAshTest, ClientViewCorrectlyPlaced) { - std::unique_ptr<views::Widget> widget(CreateWidget(new TestWidgetDelegate)); - widget->Show(); - EXPECT_NE(0, widget->client_view()->bounds().y()); -} - -// Test that the height of the header is correct upon initially displaying -// the widget. -TEST_F(CustomFrameViewAshTest, HeaderHeight) { - TestWidgetDelegate* delegate = new TestWidgetDelegate; - - std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); - widget->Show(); - - // The header should have enough room for the window controls. The - // header/content separator line overlays the window controls. - EXPECT_EQ( - GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON).height(), - delegate->custom_frame_view()->GetHeaderView()->height()); -} - -// Verify that CustomFrameViewAsh returns the correct minimum and maximum frame -// sizes when the client view does not specify any size constraints. -TEST_F(CustomFrameViewAshTest, NoSizeConstraints) { - TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; - std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); - - CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); - gfx::Size min_frame_size = custom_frame_view->GetMinimumSize(); - gfx::Size max_frame_size = custom_frame_view->GetMaximumSize(); - - EXPECT_EQ(delegate->GetTitleBarHeight(), min_frame_size.height()); - - // A width and height constraint of 0 denotes unbounded. - EXPECT_EQ(0, max_frame_size.width()); - EXPECT_EQ(0, max_frame_size.height()); -} - -// Verify that CustomFrameViewAsh returns the correct minimum and maximum frame -// sizes when the client view specifies size constraints. -TEST_F(CustomFrameViewAshTest, MinimumAndMaximumSize) { - gfx::Size min_client_size(500, 500); - gfx::Size max_client_size(800, 800); - TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; - delegate->set_minimum_size(min_client_size); - delegate->set_maximum_size(max_client_size); - std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); - - CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); - gfx::Size min_frame_size = custom_frame_view->GetMinimumSize(); - gfx::Size max_frame_size = custom_frame_view->GetMaximumSize(); - - EXPECT_EQ(min_client_size.width(), min_frame_size.width()); - EXPECT_EQ(max_client_size.width(), max_frame_size.width()); - EXPECT_EQ(min_client_size.height() + delegate->GetTitleBarHeight(), - min_frame_size.height()); - EXPECT_EQ(max_client_size.height() + delegate->GetTitleBarHeight(), - max_frame_size.height()); -} - -// Verify that CustomFrameViewAsh updates the avatar icon based on the -// state of the SessionStateDelegate after visibility change. -TEST_F(CustomFrameViewAshTest, AvatarIcon) { - TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; - std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); - - CustomFrameViewAsh* custom_frame_view = delegate->custom_frame_view(); - EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest()); - - // Avatar image becomes available. - GetTestSessionStateDelegate()->SetUserImage( - gfx::test::CreateImage(27, 27).AsImageSkia()); - widget->Hide(); - widget->Show(); - EXPECT_TRUE(custom_frame_view->GetAvatarIconViewForTest()); - - // Avatar image is gone; the ImageView for the avatar icon should be - // removed. - GetTestSessionStateDelegate()->SetUserImage(gfx::ImageSkia()); - widget->Hide(); - widget->Show(); - EXPECT_FALSE(custom_frame_view->GetAvatarIconViewForTest()); -} - -// The visibility of the size button is updated when maximize mode is toggled. -// Verify that the layout of the HeaderView is updated for the size button's -// new visibility. -TEST_F(CustomFrameViewAshTest, HeaderViewNotifiedOfChildSizeChange) { - TestWidgetConstraintsDelegate* delegate = new TestWidgetConstraintsDelegate; - std::unique_ptr<views::Widget> widget(CreateWidget(delegate)); - - const gfx::Rect initial = - delegate->GetFrameCaptionButtonContainerViewBounds(); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - delegate->EndFrameCaptionButtonContainerViewAnimations(); - const gfx::Rect maximize_mode_bounds = - delegate->GetFrameCaptionButtonContainerViewBounds(); - EXPECT_GT(initial.width(), maximize_mode_bounds.width()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - delegate->EndFrameCaptionButtonContainerViewAnimations(); - const gfx::Rect after_restore = - delegate->GetFrameCaptionButtonContainerViewBounds(); - EXPECT_EQ(initial, after_restore); -} - -} // namespace ash
diff --git a/ash/frame/default_header_painter.cc b/ash/frame/default_header_painter.cc deleted file mode 100644 index de78dbb8..0000000 --- a/ash/frame/default_header_painter.cc +++ /dev/null
@@ -1,322 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/default_header_painter.h" - -#include "ash/common/ash_layout_constants.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/header_painter_util.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "base/debug/leak_annotations.h" -#include "base/logging.h" // DCHECK -#include "third_party/skia/include/core/SkPath.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_utils.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/gfx/skia_util.h" -#include "ui/views/view.h" -#include "ui/views/widget/native_widget_aura.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -using views::Widget; - -namespace { - -// Color for the window title text. -const SkColor kTitleTextColor = SkColorSetRGB(40, 40, 40); -// Color of the active window header/content separator line. -const SkColor kHeaderContentSeparatorColor = SkColorSetRGB(150, 150, 152); -// Color of the inactive window header/content separator line. -const SkColor kHeaderContentSeparatorInactiveColor = - SkColorSetRGB(180, 180, 182); -// The default color of the frame. -const SkColor kDefaultFrameColor = SkColorSetRGB(242, 242, 242); -// Duration of crossfade animation for activating and deactivating frame. -const int kActivationCrossfadeDurationMs = 200; - -// Tiles an image into an area, rounding the top corners. -void TileRoundRect(gfx::Canvas* canvas, - const cc::PaintFlags& flags, - const gfx::Rect& bounds, - int corner_radius) { - SkRect rect = gfx::RectToSkRect(bounds); - const SkScalar corner_radius_scalar = SkIntToScalar(corner_radius); - SkScalar radii[8] = {corner_radius_scalar, - corner_radius_scalar, // top-left - corner_radius_scalar, - corner_radius_scalar, // top-right - 0, - 0, // bottom-right - 0, - 0}; // bottom-left - SkPath path; - path.addRoundRect(rect, radii, SkPath::kCW_Direction); - canvas->DrawPath(path, flags); -} - -// Returns the FontList to use for the title. -const gfx::FontList& GetTitleFontList() { - static const gfx::FontList* title_font_list = - new gfx::FontList(views::NativeWidgetAura::GetWindowTitleFontList()); - ANNOTATE_LEAKING_OBJECT_PTR(title_font_list); - return *title_font_list; -} - -} // namespace - -namespace ash { - -/////////////////////////////////////////////////////////////////////////////// -// DefaultHeaderPainter, public: - -DefaultHeaderPainter::DefaultHeaderPainter() - : frame_(NULL), - view_(NULL), - left_header_view_(NULL), - active_frame_color_(kDefaultFrameColor), - inactive_frame_color_(kDefaultFrameColor), - caption_button_container_(NULL), - painted_height_(0), - mode_(MODE_INACTIVE), - initial_paint_(true), - activation_animation_(new gfx::SlideAnimation(this)) {} - -DefaultHeaderPainter::~DefaultHeaderPainter() {} - -void DefaultHeaderPainter::Init( - views::Widget* frame, - views::View* header_view, - FrameCaptionButtonContainerView* caption_button_container) { - DCHECK(frame); - DCHECK(header_view); - DCHECK(caption_button_container); - frame_ = frame; - view_ = header_view; - caption_button_container_ = caption_button_container; - caption_button_container_->SetButtonSize( - GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON)); - UpdateAllButtonImages(); -} - -int DefaultHeaderPainter::GetMinimumHeaderWidth() const { - // Ensure we have enough space for the window icon and buttons. We allow - // the title string to collapse to zero width. - return GetTitleBounds().x() + - caption_button_container_->GetMinimumSize().width(); -} - -void DefaultHeaderPainter::PaintHeader(gfx::Canvas* canvas, Mode mode) { - Mode old_mode = mode_; - mode_ = mode; - - if (mode_ != old_mode) { - UpdateAllButtonImages(); - if (!initial_paint_ && HeaderPainterUtil::CanAnimateActivation(frame_)) { - activation_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); - if (mode_ == MODE_ACTIVE) - activation_animation_->Show(); - else - activation_animation_->Hide(); - } else { - if (mode_ == MODE_ACTIVE) - activation_animation_->Reset(1); - else - activation_animation_->Reset(0); - } - initial_paint_ = false; - } - - int corner_radius = (frame_->IsMaximized() || frame_->IsFullscreen()) - ? 0 - : HeaderPainterUtil::GetTopCornerRadiusWhenRestored(); - - cc::PaintFlags flags; - int active_alpha = activation_animation_->CurrentValueBetween(0, 255); - flags.setColor(color_utils::AlphaBlend(active_frame_color_, - inactive_frame_color_, active_alpha)); - flags.setAntiAlias(true); - TileRoundRect(canvas, flags, GetLocalBounds(), corner_radius); - - if (!frame_->IsMaximized() && !frame_->IsFullscreen() && - mode_ == MODE_INACTIVE && !UsesCustomFrameColors()) { - PaintHighlightForInactiveRestoredWindow(canvas); - } - if (frame_->widget_delegate()->ShouldShowWindowTitle()) - PaintTitleBar(canvas); - if (!UsesCustomFrameColors()) - PaintHeaderContentSeparator(canvas); -} - -void DefaultHeaderPainter::LayoutHeader() { - caption_button_container_->SetUseLightImages(ShouldUseLightImages()); - UpdateSizeButtonImages(); - caption_button_container_->Layout(); - - gfx::Size caption_button_container_size = - caption_button_container_->GetPreferredSize(); - caption_button_container_->SetBounds( - view_->width() - caption_button_container_size.width(), 0, - caption_button_container_size.width(), - caption_button_container_size.height()); - - if (left_header_view_) { - // Vertically center the left header view with respect to the caption button - // container. - // Floor when computing the center of |caption_button_container_|. - gfx::Size size = left_header_view_->GetPreferredSize(); - int icon_offset_y = - caption_button_container_->height() / 2 - size.height() / 2; - left_header_view_->SetBounds(HeaderPainterUtil::GetLeftViewXInset(), - icon_offset_y, size.width(), size.height()); - } - - // The header/content separator line overlays the caption buttons. - SetHeaderHeightForPainting(caption_button_container_->height()); -} - -int DefaultHeaderPainter::GetHeaderHeight() const { - return caption_button_container_->height(); -} - -int DefaultHeaderPainter::GetHeaderHeightForPainting() const { - return painted_height_; -} - -void DefaultHeaderPainter::SetHeaderHeightForPainting(int height) { - painted_height_ = height; -} - -void DefaultHeaderPainter::SchedulePaintForTitle() { - view_->SchedulePaintInRect(GetTitleBounds()); -} - -void DefaultHeaderPainter::SetFrameColors(SkColor active_frame_color, - SkColor inactive_frame_color) { - active_frame_color_ = active_frame_color; - inactive_frame_color_ = inactive_frame_color; - UpdateAllButtonImages(); -} - -SkColor DefaultHeaderPainter::GetActiveFrameColor() const { - return active_frame_color_; -} - -SkColor DefaultHeaderPainter::GetInactiveFrameColor() const { - return inactive_frame_color_; -} - -void DefaultHeaderPainter::UpdateLeftHeaderView(views::View* left_header_view) { - left_header_view_ = left_header_view; -} - -/////////////////////////////////////////////////////////////////////////////// -// gfx::AnimationDelegate overrides: - -void DefaultHeaderPainter::AnimationProgressed( - const gfx::Animation* animation) { - view_->SchedulePaintInRect(GetLocalBounds()); -} - -/////////////////////////////////////////////////////////////////////////////// -// DefaultHeaderPainter, private: - -void DefaultHeaderPainter::PaintHighlightForInactiveRestoredWindow( - gfx::Canvas* canvas) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia top_edge = - *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_TOP); - gfx::ImageSkia left_edge = - *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_LEFT); - gfx::ImageSkia right_edge = - *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_RIGHT); - gfx::ImageSkia bottom_edge = - *rb.GetImageSkiaNamed(IDR_AURA_WINDOW_HEADER_SHADE_INACTIVE_BOTTOM); - - int left_edge_width = left_edge.width(); - int right_edge_width = right_edge.width(); - canvas->DrawImageInt(left_edge, 0, 0); - canvas->DrawImageInt(right_edge, view_->width() - right_edge_width, 0); - canvas->TileImageInt(top_edge, left_edge_width, 0, - view_->width() - left_edge_width - right_edge_width, - top_edge.height()); - - DCHECK_EQ(left_edge.height(), right_edge.height()); - int bottom = left_edge.height(); - int bottom_height = bottom_edge.height(); - canvas->TileImageInt(bottom_edge, left_edge_width, bottom - bottom_height, - view_->width() - left_edge_width - right_edge_width, - bottom_height); -} - -void DefaultHeaderPainter::PaintTitleBar(gfx::Canvas* canvas) { - // The window icon is painted by its own views::View. - gfx::Rect title_bounds = GetTitleBounds(); - title_bounds.set_x(view_->GetMirroredXForRect(title_bounds)); - canvas->DrawStringRectWithFlags( - frame_->widget_delegate()->GetWindowTitle(), GetTitleFontList(), - kTitleTextColor, title_bounds, gfx::Canvas::NO_SUBPIXEL_RENDERING); -} - -void DefaultHeaderPainter::PaintHeaderContentSeparator(gfx::Canvas* canvas) { - gfx::ScopedCanvas scoped_canvas(canvas); - const float scale = canvas->UndoDeviceScaleFactor(); - gfx::RectF rect(0, painted_height_ * scale - 1, view_->width() * scale, 1); - cc::PaintFlags flags; - flags.setColor((mode_ == MODE_ACTIVE) ? kHeaderContentSeparatorColor - : kHeaderContentSeparatorInactiveColor); - canvas->sk_canvas()->drawRect(gfx::RectFToSkRect(rect), flags); -} - -bool DefaultHeaderPainter::ShouldUseLightImages() { - return color_utils::IsDark(mode_ == MODE_INACTIVE ? inactive_frame_color_ - : active_frame_color_); -} - -void DefaultHeaderPainter::UpdateAllButtonImages() { - caption_button_container_->SetUseLightImages(ShouldUseLightImages()); - caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_MINIMIZE, - kWindowControlMinimizeIcon); - - UpdateSizeButtonImages(); - - caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_CLOSE, - kWindowControlCloseIcon); - - caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_LEFT_SNAPPED, - kWindowControlLeftSnappedIcon); - - caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_RIGHT_SNAPPED, - kWindowControlRightSnappedIcon); -} - -void DefaultHeaderPainter::UpdateSizeButtonImages() { - const gfx::VectorIcon& icon = frame_->IsMaximized() || frame_->IsFullscreen() - ? kWindowControlRestoreIcon - : kWindowControlMaximizeIcon; - caption_button_container_->SetButtonImage( - CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, icon); -} - -gfx::Rect DefaultHeaderPainter::GetLocalBounds() const { - return gfx::Rect(view_->width(), painted_height_); -} - -gfx::Rect DefaultHeaderPainter::GetTitleBounds() const { - return HeaderPainterUtil::GetTitleBounds( - left_header_view_, caption_button_container_, GetTitleFontList()); -} - -bool DefaultHeaderPainter::UsesCustomFrameColors() const { - return active_frame_color_ != kDefaultFrameColor || - inactive_frame_color_ != kDefaultFrameColor; -} - -} // namespace ash
diff --git a/ash/frame/default_header_painter.h b/ash/frame/default_header_painter.h deleted file mode 100644 index c6f715f..0000000 --- a/ash/frame/default_header_painter.h +++ /dev/null
@@ -1,121 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_DEFAULT_HEADER_PAINTER_H_ -#define ASH_FRAME_DEFAULT_HEADER_PAINTER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/frame/header_painter.h" -#include "base/compiler_specific.h" // override -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/animation/animation_delegate.h" - -namespace gfx { -class Rect; -class SlideAnimation; -} -namespace views { -class View; -class Widget; -} - -namespace ash { -class FrameCaptionButtonContainerView; - -// Helper class for painting the default window header. -class ASH_EXPORT DefaultHeaderPainter : public HeaderPainter, - public gfx::AnimationDelegate { - public: - DefaultHeaderPainter(); - ~DefaultHeaderPainter() override; - - // DefaultHeaderPainter does not take ownership of any of the parameters. - void Init(views::Widget* frame, - views::View* header_view, - FrameCaptionButtonContainerView* caption_button_container); - - // HeaderPainter overrides: - int GetMinimumHeaderWidth() const override; - void PaintHeader(gfx::Canvas* canvas, Mode mode) override; - void LayoutHeader() override; - int GetHeaderHeight() const override; - int GetHeaderHeightForPainting() const override; - void SetHeaderHeightForPainting(int height) override; - void SchedulePaintForTitle() override; - - // Sets the left header view for the header. Passing NULL removes the view. - void UpdateLeftHeaderView(views::View* left_header_view); - - // Sets the active and inactive frame colors. Note the inactive frame color - // will have some transparency added when the frame is drawn. - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - SkColor GetActiveFrameColor() const; - SkColor GetInactiveFrameColor() const; - - private: - FRIEND_TEST_ALL_PREFIXES(DefaultHeaderPainterTest, TitleIconAlignment); - FRIEND_TEST_ALL_PREFIXES(DefaultHeaderPainterTest, LightIcons); - - // gfx::AnimationDelegate override: - void AnimationProgressed(const gfx::Animation* animation) override; - - // Paints highlight around the edge of the header for inactive restored - // windows. - void PaintHighlightForInactiveRestoredWindow(gfx::Canvas* canvas); - - // Paints the title bar, primarily the title string. - void PaintTitleBar(gfx::Canvas* canvas); - - // Paints the header/content separator. - void PaintHeaderContentSeparator(gfx::Canvas* canvas); - - // Whether light caption images should be used. This is the case when the - // background of the frame is dark. - bool ShouldUseLightImages(); - - // Update all the images in the caption buttons. - void UpdateAllButtonImages(); - - // Updates the size button's images. - void UpdateSizeButtonImages(); - - // Returns the header bounds in the coordinates of |view_|. The header is - // assumed to be positioned at the top left corner of |view_| and to have the - // same width as |view_|. - gfx::Rect GetLocalBounds() const; - - // Returns the bounds for the title. - gfx::Rect GetTitleBounds() const; - - // Returns whether the frame uses custom frame coloring. - bool UsesCustomFrameColors() const; - - views::Widget* frame_; - views::View* view_; - views::View* left_header_view_; // May be NULL. - SkColor active_frame_color_; - SkColor inactive_frame_color_; - FrameCaptionButtonContainerView* caption_button_container_; - - // The height of the header to paint. - int painted_height_; - - // Whether the header should be painted as active. - Mode mode_; - - // Whether the header is painted for the first time. - bool initial_paint_; - - std::unique_ptr<gfx::SlideAnimation> activation_animation_; - - DISALLOW_COPY_AND_ASSIGN(DefaultHeaderPainter); -}; - -} // namespace ash - -#endif // ASH_FRAME_DEFAULT_HEADER_PAINTER_H_
diff --git a/ash/frame/default_header_painter_unittest.cc b/ash/frame/default_header_painter_unittest.cc deleted file mode 100644 index 083a8c0..0000000 --- a/ash/frame/default_header_painter_unittest.cc +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/default_header_painter.h" - -#include <memory> - -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/test/ash_test_base.h" -#include "ui/views/test/test_views.h" -#include "ui/views/widget/widget.h" -#include "ui/views/window/non_client_view.h" - -using ash::HeaderPainter; -using views::NonClientFrameView; -using views::Widget; - -namespace ash { - -using DefaultHeaderPainterTest = test::AshTestBase; - -// Ensure the title text is vertically aligned with the window icon. -TEST_F(DefaultHeaderPainterTest, TitleIconAlignment) { - std::unique_ptr<Widget> w = CreateTestWidget( - nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); - ash::FrameCaptionButtonContainerView container(w.get()); - views::StaticSizedView window_icon(gfx::Size(16, 16)); - window_icon.SetBounds(0, 0, 16, 16); - w->SetBounds(gfx::Rect(0, 0, 500, 500)); - w->Show(); - - DefaultHeaderPainter painter; - painter.Init(w.get(), w->non_client_view()->frame_view(), &container); - painter.UpdateLeftHeaderView(&window_icon); - painter.LayoutHeader(); - gfx::Rect title_bounds = painter.GetTitleBounds(); - EXPECT_EQ(window_icon.bounds().CenterPoint().y(), - title_bounds.CenterPoint().y()); -} - -// Ensure the light icons are used when appropriate. -TEST_F(DefaultHeaderPainterTest, LightIcons) { - std::unique_ptr<Widget> w = CreateTestWidget( - nullptr, kShellWindowId_DefaultContainer, gfx::Rect(1, 2, 3, 4)); - ash::FrameCaptionButtonContainerView container(w.get()); - views::StaticSizedView window_icon(gfx::Size(16, 16)); - window_icon.SetBounds(0, 0, 16, 16); - w->SetBounds(gfx::Rect(0, 0, 500, 500)); - w->Show(); - - DefaultHeaderPainter painter; - painter.Init(w.get(), w->non_client_view()->frame_view(), &container); - - // Check by default light icons are not used. - painter.mode_ = HeaderPainter::MODE_ACTIVE; - EXPECT_FALSE(painter.ShouldUseLightImages()); - painter.mode_ = HeaderPainter::MODE_INACTIVE; - EXPECT_FALSE(painter.ShouldUseLightImages()); - - // Check that setting dark colors should use light icons. - painter.SetFrameColors(SkColorSetRGB(0, 0, 0), SkColorSetRGB(0, 0, 0)); - painter.mode_ = HeaderPainter::MODE_ACTIVE; - EXPECT_TRUE(painter.ShouldUseLightImages()); - painter.mode_ = HeaderPainter::MODE_INACTIVE; - EXPECT_TRUE(painter.ShouldUseLightImages()); - - // Check that inactive and active colors are used properly. - painter.SetFrameColors(SkColorSetRGB(0, 0, 0), SkColorSetRGB(255, 255, 255)); - painter.mode_ = HeaderPainter::MODE_ACTIVE; - EXPECT_TRUE(painter.ShouldUseLightImages()); - painter.mode_ = HeaderPainter::MODE_INACTIVE; - EXPECT_FALSE(painter.ShouldUseLightImages()); - - // Check not so light or dark colors. - painter.SetFrameColors(SkColorSetRGB(70, 70, 70), - SkColorSetRGB(200, 200, 200)); - painter.mode_ = HeaderPainter::MODE_ACTIVE; - EXPECT_TRUE(painter.ShouldUseLightImages()); - painter.mode_ = HeaderPainter::MODE_INACTIVE; - EXPECT_FALSE(painter.ShouldUseLightImages()); -} - -} // namespace ash
diff --git a/ash/frame/frame_border_hit_test.cc b/ash/frame/frame_border_hit_test.cc deleted file mode 100644 index 58cb7ff1..0000000 --- a/ash/frame/frame_border_hit_test.cc +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/frame_border_hit_test.h" - -#include "ash/common/ash_constants.h" -#include "ash/common/wm_shell.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ui/base/hit_test.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/window/non_client_view.h" - -namespace ash { - -int FrameBorderNonClientHitTest( - views::NonClientFrameView* view, - FrameCaptionButtonContainerView* caption_button_container, - const gfx::Point& point_in_widget) { - gfx::Rect expanded_bounds = view->bounds(); - int outside_bounds = kResizeOutsideBoundsSize; - - if (WmShell::Get()->IsTouchDown()) - outside_bounds *= kResizeOutsideBoundsScaleForTouch; - expanded_bounds.Inset(-outside_bounds, -outside_bounds); - - if (!expanded_bounds.Contains(point_in_widget)) - return HTNOWHERE; - - // Check the frame first, as we allow a small area overlapping the contents - // to be used for resize handles. - views::Widget* frame = view->GetWidget(); - bool can_ever_resize = frame->widget_delegate()->CanResize(); - // Don't allow overlapping resize handles when the window is maximized or - // fullscreen, as it can't be resized in those states. - int resize_border = kResizeInsideBoundsSize; - if (frame->IsMaximized() || frame->IsFullscreen()) { - resize_border = 0; - can_ever_resize = false; - } - int frame_component = view->GetHTComponentForFrame( - point_in_widget, resize_border, resize_border, kResizeAreaCornerSize, - kResizeAreaCornerSize, can_ever_resize); - if (frame_component != HTNOWHERE) - return frame_component; - - int client_component = - frame->client_view()->NonClientHitTest(point_in_widget); - if (client_component != HTNOWHERE) - return client_component; - - if (caption_button_container->visible()) { - gfx::Point point_in_caption_button_container(point_in_widget); - views::View::ConvertPointFromWidget(caption_button_container, - &point_in_caption_button_container); - int caption_button_component = caption_button_container->NonClientHitTest( - point_in_caption_button_container); - if (caption_button_component != HTNOWHERE) - return caption_button_component; - } - - // Caption is a safe default. - return HTCAPTION; -} - -} // namespace ash
diff --git a/ash/frame/frame_border_hit_test.h b/ash/frame/frame_border_hit_test.h deleted file mode 100644 index 083ba6a9..0000000 --- a/ash/frame/frame_border_hit_test.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_FRAME_BORDER_HIT_TEST_H_ -#define ASH_FRAME_FRAME_BORDER_HIT_TEST_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Point; -} - -namespace views { -class NonClientFrameView; -} - -namespace ash { - -class FrameCaptionButtonContainerView; - -// Returns the HitTestCompat for the specified point. -ASH_EXPORT int FrameBorderNonClientHitTest( - views::NonClientFrameView* view, - FrameCaptionButtonContainerView* caption_button_container, - const gfx::Point& point_in_widget); - -} // namespace ash - -#endif // ASH_FRAME_FRAME_BORDER_HIT_TEST_H_
diff --git a/ash/frame/header_painter.h b/ash/frame/header_painter.h deleted file mode 100644 index 517f2aa..0000000 --- a/ash/frame/header_painter.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_HEADER_PAINTER_H_ -#define ASH_FRAME_HEADER_PAINTER_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Canvas; -} - -namespace ash { - -// Helper class for painting the window header. -class ASH_EXPORT HeaderPainter { - public: - enum Mode { MODE_ACTIVE, MODE_INACTIVE }; - - virtual ~HeaderPainter() {} - - // Returns the header's minimum width. - virtual int GetMinimumHeaderWidth() const = 0; - - // Paints the header. - virtual void PaintHeader(gfx::Canvas* canvas, Mode mode) = 0; - - // Performs layout for the header. - virtual void LayoutHeader() = 0; - - // Get the height of the header. - virtual int GetHeaderHeight() const = 0; - - // Gets / sets how much of the header is painted. This allows the header to - // paint under things (like the tabstrip) which have transparent / - // non-painting sections. This height does not affect LayoutHeader(). - virtual int GetHeaderHeightForPainting() const = 0; - virtual void SetHeaderHeightForPainting(int height_for_painting) = 0; - - // Schedule a re-paint of the entire title. - virtual void SchedulePaintForTitle() = 0; -}; - -} // namespace ash - -#endif // ASH_FRAME_HEADER_PAINTER_H_
diff --git a/ash/frame/header_painter_util.cc b/ash/frame/header_painter_util.cc deleted file mode 100644 index 4d8b4a7..0000000 --- a/ash/frame/header_painter_util.cc +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/header_painter_util.h" - -#include <algorithm> - -#include "ash/common/wm_window.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animator.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace { - -// Radius of the header's top corners when the window is restored. -const int kTopCornerRadiusWhenRestored = 2; - -// Distance between left edge of the window and the leftmost view. -const int kLeftViewXInset = 9; - -// Space between the title text and the caption buttons. -const int kTitleCaptionButtonSpacing = 5; - -// Space between window icon and title text. -const int kTitleIconOffsetX = 5; - -// Space between window edge and title text, when there is no icon. -const int kTitleNoIconOffsetX = 8; - -// In the pre-Ash era the web content area had a frame along the left edge, so -// user-generated theme images for the new tab page assume they are shifted -// right relative to the header. Now that we have removed the left edge frame -// we need to copy the theme image for the window header from a few pixels -// inset to preserve alignment with the NTP image, or else we'll break a bunch -// of existing themes. We do something similar on OS X for the same reason. -const int kThemeFrameImageInsetX = 5; - -} // namespace - -namespace ash { - -// static -int HeaderPainterUtil::GetTopCornerRadiusWhenRestored() { - return kTopCornerRadiusWhenRestored; -} - -// static -int HeaderPainterUtil::GetLeftViewXInset() { - return kLeftViewXInset; -} - -// static -int HeaderPainterUtil::GetThemeBackgroundXInset() { - return kThemeFrameImageInsetX; -} - -// static -gfx::Rect HeaderPainterUtil::GetTitleBounds( - const views::View* left_view, - const views::View* right_view, - const gfx::FontList& title_font_list) { - int x = left_view ? left_view->bounds().right() + kTitleIconOffsetX - : kTitleNoIconOffsetX; - int height = title_font_list.GetHeight(); - // Floor when computing the center of |caption_button_container| and when - // computing the center of the text. - int y = std::max(0, (right_view->height() / 2) - (height / 2)); - int width = std::max(0, right_view->x() - kTitleCaptionButtonSpacing - x); - return gfx::Rect(x, y, width, height); -} - -// static -bool HeaderPainterUtil::CanAnimateActivation(views::Widget* widget) { - // Do not animate the header if the parent (e.g. - // kShellWindowId_DefaultContainer) is already animating. All of the - // implementers of HeaderPainter animate activation by continuously painting - // during the animation. This gives the parent's animation a slower frame - // rate. - // TODO(sky): Expose a better way to determine this rather than assuming the - // parent is a toplevel container. - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - // TODO(sky): GetParent()->GetLayer() is for mash until animations ported. - if (!window || !window->GetParent() || !window->GetParent()->GetLayer()) - return true; - - ui::LayerAnimator* parent_layer_animator = - window->GetParent()->GetLayer()->GetAnimator(); - return !parent_layer_animator->IsAnimatingProperty( - ui::LayerAnimationElement::OPACITY) && - !parent_layer_animator->IsAnimatingProperty( - ui::LayerAnimationElement::VISIBILITY); -} - -} // namespace ash
diff --git a/ash/frame/header_painter_util.h b/ash/frame/header_painter_util.h deleted file mode 100644 index d0b5e3c..0000000 --- a/ash/frame/header_painter_util.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_HEADER_PAINTER_UTIL_H_ -#define ASH_FRAME_HEADER_PAINTER_UTIL_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" - -namespace gfx { -class FontList; -class Rect; -} -namespace views { -class View; -class Widget; -} - -namespace ash { - -// Static-only helper class for functionality used accross multiple -// implementations of HeaderPainter. -class ASH_EXPORT HeaderPainterUtil { - public: - // Returns the radius of the header's corners when the window is restored. - static int GetTopCornerRadiusWhenRestored(); - - // Returns the default distance between the left edge of the window and the - // leftmost view in the header. - static int GetLeftViewXInset(); - - // Returns the amount that the frame background is inset from the left edge of - // the window. - static int GetThemeBackgroundXInset(); - - // Returns the bounds for the header's title given the views to the left and - // right of the title, and the font used. - // |left_view| should be NULL if there is no view to the left of the title. - static gfx::Rect GetTitleBounds(const views::View* left_view, - const views::View* right_view, - const gfx::FontList& title_font_list); - - // Returns true if the header for |widget| can animate to new visuals when the - // widget's activation changes. Returns false if the header should switch to - // new visuals instantaneously. - static bool CanAnimateActivation(views::Widget* widget); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(HeaderPainterUtil); -}; - -} // namespace ash - -#endif // ASH_FRAME_HEADER_PAINTER_UTIL_H_
diff --git a/ash/frame/header_view.cc b/ash/frame/header_view.cc deleted file mode 100644 index 206489c..0000000 --- a/ash/frame/header_view.cc +++ /dev/null
@@ -1,201 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/frame/header_view.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/default_header_painter.h" -#include "ui/gfx/canvas.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -HeaderView::HeaderView(views::Widget* target_widget) - : target_widget_(target_widget), - header_painter_(new DefaultHeaderPainter), - avatar_icon_(nullptr), - caption_button_container_(nullptr), - fullscreen_visible_fraction_(0) { - caption_button_container_ = - new FrameCaptionButtonContainerView(target_widget_); - caption_button_container_->UpdateSizeButtonVisibility(); - AddChildView(caption_button_container_); - - header_painter_->Init(target_widget_, this, caption_button_container_); - UpdateAvatarIcon(); - - WmShell::Get()->AddShellObserver(this); -} - -HeaderView::~HeaderView() { - WmShell::Get()->RemoveShellObserver(this); -} - -void HeaderView::SchedulePaintForTitle() { - header_painter_->SchedulePaintForTitle(); -} - -void HeaderView::ResetWindowControls() { - caption_button_container_->ResetWindowControls(); -} - -int HeaderView::GetPreferredOnScreenHeight() { - if (is_immersive_delegate_ && target_widget_->IsFullscreen()) { - return static_cast<int>(GetPreferredHeight() * - fullscreen_visible_fraction_); - } - return GetPreferredHeight(); -} - -int HeaderView::GetPreferredHeight() { - // Calculating the preferred height requires at least one Layout(). - if (!did_layout_) - Layout(); - return header_painter_->GetHeaderHeightForPainting(); -} - -int HeaderView::GetMinimumWidth() const { - return header_painter_->GetMinimumHeaderWidth(); -} - -void HeaderView::UpdateAvatarIcon() { - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - WmWindow* window = WmWindow::Get(target_widget_->GetNativeWindow()); - bool show = delegate->ShouldShowAvatar(window); - if (!show) { - if (!avatar_icon_) - return; - delete avatar_icon_; - avatar_icon_ = nullptr; - } else { - gfx::ImageSkia image = delegate->GetAvatarImageForWindow(window); - DCHECK_EQ(image.width(), image.height()); - if (!avatar_icon_) { - avatar_icon_ = new views::ImageView(); - AddChildView(avatar_icon_); - } - avatar_icon_->SetImage(image); - } - header_painter_->UpdateLeftHeaderView(avatar_icon_); - Layout(); -} - -void HeaderView::SizeConstraintsChanged() { - caption_button_container_->ResetWindowControls(); - caption_button_container_->UpdateSizeButtonVisibility(); - Layout(); -} - -void HeaderView::SetFrameColors(SkColor active_frame_color, - SkColor inactive_frame_color) { - header_painter_->SetFrameColors(active_frame_color, inactive_frame_color); -} - -SkColor HeaderView::GetActiveFrameColor() const { - return header_painter_->GetActiveFrameColor(); -} - -SkColor HeaderView::GetInactiveFrameColor() const { - return header_painter_->GetInactiveFrameColor(); -} - -/////////////////////////////////////////////////////////////////////////////// -// HeaderView, views::View overrides: - -void HeaderView::Layout() { - did_layout_ = true; - header_painter_->LayoutHeader(); -} - -void HeaderView::OnPaint(gfx::Canvas* canvas) { - bool paint_as_active = - target_widget_->non_client_view()->frame_view()->ShouldPaintAsActive(); - caption_button_container_->SetPaintAsActive(paint_as_active); - - HeaderPainter::Mode header_mode = paint_as_active - ? HeaderPainter::MODE_ACTIVE - : HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeader(canvas, header_mode); -} - -void HeaderView::ChildPreferredSizeChanged(views::View* child) { - // FrameCaptionButtonContainerView animates the visibility changes in - // UpdateSizeButtonVisibility(false). Due to this a new size is not available - // until the completion of the animation. Layout in response to the preferred - // size changes. - if (child != caption_button_container_) - return; - parent()->Layout(); -} - -/////////////////////////////////////////////////////////////////////////////// -// HeaderView, ShellObserver overrides: - -void HeaderView::OnOverviewModeStarting() { - caption_button_container_->SetVisible(false); -} - -void HeaderView::OnOverviewModeEnded() { - caption_button_container_->SetVisible(true); -} - -void HeaderView::OnMaximizeModeStarted() { - caption_button_container_->UpdateSizeButtonVisibility(); - parent()->Layout(); -} - -void HeaderView::OnMaximizeModeEnded() { - caption_button_container_->UpdateSizeButtonVisibility(); - parent()->Layout(); -} - -views::View* HeaderView::avatar_icon() const { - return avatar_icon_; -} - -/////////////////////////////////////////////////////////////////////////////// -// HeaderView, -// ImmersiveFullscreenControllerDelegate overrides: - -void HeaderView::OnImmersiveRevealStarted() { - fullscreen_visible_fraction_ = 0; - SetPaintToLayer(); - parent()->Layout(); -} - -void HeaderView::OnImmersiveRevealEnded() { - fullscreen_visible_fraction_ = 0; - DestroyLayer(); - parent()->Layout(); -} - -void HeaderView::OnImmersiveFullscreenExited() { - fullscreen_visible_fraction_ = 0; - DestroyLayer(); - parent()->Layout(); -} - -void HeaderView::SetVisibleFraction(double visible_fraction) { - if (fullscreen_visible_fraction_ != visible_fraction) { - fullscreen_visible_fraction_ = visible_fraction; - parent()->Layout(); - } -} - -std::vector<gfx::Rect> HeaderView::GetVisibleBoundsInScreen() const { - // TODO(pkotwicz): Implement views::View::ConvertRectToScreen(). - gfx::Rect visible_bounds(GetVisibleBounds()); - gfx::Point visible_origin_in_screen(visible_bounds.origin()); - views::View::ConvertPointToScreen(this, &visible_origin_in_screen); - std::vector<gfx::Rect> bounds_in_screen; - bounds_in_screen.push_back( - gfx::Rect(visible_origin_in_screen, visible_bounds.size())); - return bounds_in_screen; -} - -} // namespace ash
diff --git a/ash/frame/header_view.h b/ash/frame/header_view.h deleted file mode 100644 index 78c9774..0000000 --- a/ash/frame/header_view.h +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_FRAME_HEADER_VIEW_H_ -#define ASH_FRAME_HEADER_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/shared/immersive_fullscreen_controller_delegate.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/views/view.h" - -namespace views { -class ImageView; -class Widget; -} - -namespace ash { - -class DefaultHeaderPainter; -class FrameCaptionButtonContainerView; - -// View which paints the frame header (title, caption buttons...). It slides off -// and on screen in immersive fullscreen. -class ASH_EXPORT HeaderView : public views::View, - public ImmersiveFullscreenControllerDelegate, - public ShellObserver { - public: - // |target_widget| is the widget that the caption buttons act on. - // |target_widget| is not necessarily the same as the widget the header is - // placed in. For example, in immersive fullscreen this view may be painted in - // a widget that slides in and out on top of the main app or browser window. - // However, clicking a caption button should act on the target widget. - explicit HeaderView(views::Widget* target_widget); - ~HeaderView() override; - - void set_is_immersive_delegate(bool value) { is_immersive_delegate_ = value; } - - // Schedules a repaint for the entire title. - void SchedulePaintForTitle(); - - // Tells the window controls to reset themselves to the normal state. - void ResetWindowControls(); - - // Returns the amount of the view's pixels which should be on screen. - int GetPreferredOnScreenHeight(); - - // Returns the view's preferred height. - int GetPreferredHeight(); - - // Returns the view's minimum width. - int GetMinimumWidth() const; - - void UpdateAvatarIcon(); - - void SizeConstraintsChanged(); - - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - SkColor GetActiveFrameColor() const; - SkColor GetInactiveFrameColor() const; - - // views::View: - void Layout() override; - void OnPaint(gfx::Canvas* canvas) override; - void ChildPreferredSizeChanged(views::View* child) override; - - // ShellObserver: - void OnOverviewModeStarting() override; - void OnOverviewModeEnded() override; - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - - FrameCaptionButtonContainerView* caption_button_container() { - return caption_button_container_; - } - - views::View* avatar_icon() const; - - private: - // ImmersiveFullscreenControllerDelegate: - void OnImmersiveRevealStarted() override; - void OnImmersiveRevealEnded() override; - void OnImmersiveFullscreenExited() override; - void SetVisibleFraction(double visible_fraction) override; - std::vector<gfx::Rect> GetVisibleBoundsInScreen() const override; - - // The widget that the caption buttons act on. - views::Widget* target_widget_; - - // Helper for painting the header. - std::unique_ptr<DefaultHeaderPainter> header_painter_; - - views::ImageView* avatar_icon_; - - // View which contains the window caption buttons. - FrameCaptionButtonContainerView* caption_button_container_; - - // The fraction of the header's height which is visible while in fullscreen. - // This value is meaningless when not in fullscreen. - double fullscreen_visible_fraction_; - - // Has this instance been set as the ImmersiveFullscreenControllerDelegate? - bool is_immersive_delegate_ = true; - - bool did_layout_ = false; - - DISALLOW_COPY_AND_ASSIGN(HeaderView); -}; - -} // namespace ash - -#endif // ASH_FRAME_HEADER_VIEW_H_
diff --git a/ash/laser/laser_pointer_controller.cc b/ash/laser/laser_pointer_controller.cc index d98a2520..e979549 100644 --- a/ash/laser/laser_pointer_controller.cc +++ b/ash/laser/laser_pointer_controller.cc
@@ -4,9 +4,9 @@ #include "ash/laser/laser_pointer_controller.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" #include "ash/laser/laser_pointer_view.h" #include "ash/shell.h" -#include "ash/system/palette/palette_utils.h" #include "ui/display/screen.h" #include "ui/views/widget/widget.h"
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc index ab2a4e3..aa8295b 100644 --- a/ash/magnifier/magnification_controller.cc +++ b/ash/magnifier/magnification_controller.cc
@@ -7,15 +7,15 @@ #include <memory> #include <utility> -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/accessibility_delegate.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/display/root_window_transformers.h" #include "ash/host/ash_window_tree_host.h" #include "ash/host/root_window_transformer.h" #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "base/command_line.h" #include "base/synchronization/waitable_event.h" #include "base/timer/timer.h"
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc index 513e1c67..3cbedb8 100644 --- a/ash/magnifier/partial_magnification_controller.cc +++ b/ash/magnifier/partial_magnification_controller.cc
@@ -4,8 +4,8 @@ #include "ash/magnifier/partial_magnification_controller.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" #include "ash/shell.h" -#include "ash/system/palette/palette_utils.h" #include "third_party/skia/include/core/SkDrawLooper.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host.h"
diff --git a/ash/metrics/gesture_action_type.h b/ash/metrics/gesture_action_type.h deleted file mode 100644 index 120298dc1..0000000 --- a/ash/metrics/gesture_action_type.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_METRICS_GESTURE_ACTION_TYPE_H_ -#define ASH_METRICS_GESTURE_ACTION_TYPE_H_ - -namespace ash { - -enum GestureActionType { - GESTURE_UNKNOWN, - GESTURE_OMNIBOX_PINCH, - GESTURE_OMNIBOX_SCROLL, - GESTURE_TABSTRIP_PINCH, - GESTURE_TABSTRIP_SCROLL, - GESTURE_BEZEL_SCROLL, - GESTURE_DESKTOP_SCROLL, - GESTURE_DESKTOP_PINCH, - GESTURE_WEBPAGE_PINCH, - GESTURE_WEBPAGE_SCROLL, - GESTURE_WEBPAGE_TAP, - GESTURE_TABSTRIP_TAP, - GESTURE_BEZEL_DOWN, - GESTURE_TABSWITCH_TAP, - GESTURE_TABNOSWITCH_TAP, - GESTURE_TABCLOSE_TAP, - GESTURE_NEWTAB_TAP, - GESTURE_ROOTVIEWTOP_TAP, - GESTURE_FRAMEMAXIMIZE_TAP, - GESTURE_FRAMEVIEW_TAP, - GESTURE_MAXIMIZE_DOUBLETAP, - // NOTE: Add new action types only immediately above this line. Also, - // make sure the enum list in tools/histogram/histograms.xml is - // updated with any change in here. - GESTURE_ACTION_COUNT -}; - -} // namespace ash - -#endif // ASH_METRICS_GESTURE_ACTION_TYPE_H_
diff --git a/ash/metrics/pointer_metrics_recorder.cc b/ash/metrics/pointer_metrics_recorder.cc deleted file mode 100644 index da85806..0000000 --- a/ash/metrics/pointer_metrics_recorder.cc +++ /dev/null
@@ -1,106 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/metrics/pointer_metrics_recorder.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/shared/app_types.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "base/metrics/histogram_macros.h" -#include "ui/events/event_constants.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -namespace { - -// Form factor of the down event. This enum is used to back an UMA histogram -// and new values should be inserted immediately above FORM_FACTOR_COUNT. -enum class DownEventFormFactor { - CLAMSHELL = 0, - TOUCH_VIEW, - FORM_FACTOR_COUNT, -}; - -// Input type of the down event. This enum is used to back an UMA -// histogram and new values should be inserted immediately above SOURCE_COUNT. -enum class DownEventSource { - UNKNOWN = 0, - MOUSE, - STYLUS, - TOUCH, - SOURCE_COUNT, -}; - -int GetDestination(views::Widget* target) { - if (!target) - return static_cast<int>(AppType::OTHERS); - - WmWindow* window = WmWindow::Get(target->GetNativeWindow()); - DCHECK(window); - return window->GetAppType(); -} - -void RecordUMA(ui::EventPointerType type, views::Widget* target) { - DownEventFormFactor form_factor = DownEventFormFactor::CLAMSHELL; - if (ash::WmShell::Get() - ->maximize_mode_controller() - ->IsMaximizeModeWindowManagerEnabled()) { - form_factor = DownEventFormFactor::TOUCH_VIEW; - } - UMA_HISTOGRAM_ENUMERATION( - "Event.DownEventCount.PerFormFactor", - static_cast<base::HistogramBase::Sample>(form_factor), - static_cast<base::HistogramBase::Sample>( - DownEventFormFactor::FORM_FACTOR_COUNT)); - - DownEventSource input_type = DownEventSource::UNKNOWN; - switch (type) { - case ui::EventPointerType::POINTER_TYPE_UNKNOWN: - input_type = DownEventSource::UNKNOWN; - break; - case ui::EventPointerType::POINTER_TYPE_MOUSE: - input_type = DownEventSource::MOUSE; - break; - case ui::EventPointerType::POINTER_TYPE_PEN: - input_type = DownEventSource::STYLUS; - break; - case ui::EventPointerType::POINTER_TYPE_TOUCH: - input_type = DownEventSource::TOUCH; - break; - case ui::EventPointerType::POINTER_TYPE_ERASER: - input_type = DownEventSource::STYLUS; - break; - } - - UMA_HISTOGRAM_ENUMERATION( - "Event.DownEventCount.PerInput", - static_cast<base::HistogramBase::Sample>(input_type), - static_cast<base::HistogramBase::Sample>(DownEventSource::SOURCE_COUNT)); - - UMA_HISTOGRAM_ENUMERATION("Event.DownEventCount.PerDestination", - GetDestination(target), kAppCount); -} - -} // namespace - -PointerMetricsRecorder::PointerMetricsRecorder() { - ash::WmShell::Get()->AddPointerWatcher( - this, views::PointerWatcherEventTypes::BASIC); -} - -PointerMetricsRecorder::~PointerMetricsRecorder() { - ash::WmShell::Get()->RemovePointerWatcher(this); -} - -void PointerMetricsRecorder::OnPointerEventObserved( - const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - if (event.type() == ui::ET_POINTER_DOWN) - RecordUMA(event.pointer_details().pointer_type, target); -} - -} // namespace ash
diff --git a/ash/metrics/pointer_metrics_recorder.h b/ash/metrics/pointer_metrics_recorder.h deleted file mode 100644 index e3d49f6..0000000 --- a/ash/metrics/pointer_metrics_recorder.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_ASH_METRICS_POINTER_METRICS_RECORDER_H_ -#define UI_ASH_METRICS_POINTER_METRICS_RECORDER_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/views/pointer_watcher.h" - -namespace gfx { -class Point; -} - -namespace ui { -class PointerEvent; -} - -namespace ash { - -// A metrics recorder that records pointer related metrics. -class ASH_EXPORT PointerMetricsRecorder : public views::PointerWatcher { - public: - PointerMetricsRecorder(); - ~PointerMetricsRecorder() override; - - // views::PointerWatcher: - void OnPointerEventObserved(const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - - private: - DISALLOW_COPY_AND_ASSIGN(PointerMetricsRecorder); -}; - -} // namespace ash - -#endif // UI_ASH_METRICS_POINTER_METRICS_RECORDER_H_
diff --git a/ash/metrics/pointer_metrics_recorder_unittest.cc b/ash/metrics/pointer_metrics_recorder_unittest.cc deleted file mode 100644 index be1ae6d..0000000 --- a/ash/metrics/pointer_metrics_recorder_unittest.cc +++ /dev/null
@@ -1,185 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/metrics/pointer_metrics_recorder.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/shared/app_types.h" -#include "ash/test/ash_test_base.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "base/test/histogram_tester.h" -#include "ui/events/event.h" -#include "ui/views/pointer_watcher.h" -#include "ui/views/widget/widget.h" - -using views::PointerWatcher; - -namespace ash { -namespace { - -const char kFormFactorHistogramName[] = "Event.DownEventCount.PerFormFactor"; -const char kInputHistogramName[] = "Event.DownEventCount.PerInput"; -const char kDestinationHistogramName[] = "Event.DownEventCount.PerDestination"; - -// Test fixture for the PointerMetricsRecorder class. -class PointerMetricsRecorderTest : public test::AshTestBase { - public: - PointerMetricsRecorderTest(); - ~PointerMetricsRecorderTest() override; - - // test::AshTestBase: - void SetUp() override; - void TearDown() override; - - protected: - // The test target. - std::unique_ptr<PointerMetricsRecorder> pointer_metrics_recorder_; - - // Used to verify recorded data. - std::unique_ptr<base::HistogramTester> histogram_tester_; - - private: - DISALLOW_COPY_AND_ASSIGN(PointerMetricsRecorderTest); -}; - -PointerMetricsRecorderTest::PointerMetricsRecorderTest() {} - -PointerMetricsRecorderTest::~PointerMetricsRecorderTest() {} - -void PointerMetricsRecorderTest::SetUp() { - test::AshTestBase::SetUp(); - pointer_metrics_recorder_.reset(new PointerMetricsRecorder()); - histogram_tester_.reset(new base::HistogramTester()); -} - -void PointerMetricsRecorderTest::TearDown() { - pointer_metrics_recorder_.reset(); - test::AshTestBase::TearDown(); -} - -} // namespace - -// Verifies that histogram is not recorded when receiving events that are not -// down events. -TEST_F(PointerMetricsRecorderTest, NonDownEventsInAllPointerHistogram) { - std::unique_ptr<views::Widget> target = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - const ui::PointerEvent pointer_event( - ui::ET_POINTER_UP, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), - base::TimeTicks()); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - - histogram_tester_->ExpectTotalCount(kFormFactorHistogramName, 0); - histogram_tester_->ExpectTotalCount(kInputHistogramName, 0); - histogram_tester_->ExpectTotalCount(kDestinationHistogramName, 0); -} - -// Verifies that down events from different inputs are recorded. -TEST_F(PointerMetricsRecorderTest, DownEventPerInput) { - std::unique_ptr<views::Widget> target = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - - const ui::PointerEvent unknown_event( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_UNKNOWN), - base::TimeTicks()); - pointer_metrics_recorder_->OnPointerEventObserved(unknown_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kInputHistogramName, 0, 1); - - const ui::PointerEvent mouse_event( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), - base::TimeTicks()); - pointer_metrics_recorder_->OnPointerEventObserved(mouse_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kInputHistogramName, 1, 1); - - const ui::PointerEvent stylus_event( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_PEN), - base::TimeTicks()); - pointer_metrics_recorder_->OnPointerEventObserved(stylus_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kInputHistogramName, 2, 1); - - const ui::PointerEvent stylus_event2( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_ERASER), - base::TimeTicks()); - pointer_metrics_recorder_->OnPointerEventObserved(stylus_event2, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kInputHistogramName, 2, 2); - - const ui::PointerEvent touch_event( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH), - base::TimeTicks()); - pointer_metrics_recorder_->OnPointerEventObserved(touch_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kInputHistogramName, 3, 1); -} - -// Verifies that down events in different form factors are recorded. -TEST_F(PointerMetricsRecorderTest, DownEventPerFormFactor) { - std::unique_ptr<views::Widget> target = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - const ui::PointerEvent pointer_event( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), - base::TimeTicks()); - - // Enable maximize mode - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kFormFactorHistogramName, 1, 1); - - // Disable maximize mode - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kFormFactorHistogramName, 0, 1); -} - -// Verifies that down events dispatched to different destinations are recorded. -TEST_F(PointerMetricsRecorderTest, DownEventPerDestination) { - std::unique_ptr<views::Widget> target = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - const ui::PointerEvent pointer_event( - ui::ET_POINTER_DOWN, gfx::Point(), gfx::Point(), 0, 0, 0, - ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE), - base::TimeTicks()); - - WmWindow* window = WmWindow::Get(target->GetNativeWindow()); - CHECK(window); - - window->SetAppType(static_cast<int>(AppType::OTHERS)); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 0, 1); - - window->SetAppType(static_cast<int>(AppType::BROWSER)); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 1, 1); - - window->SetAppType(static_cast<int>(AppType::CHROME_APP)); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 2, 1); - - window->SetAppType(static_cast<int>(AppType::ARC_APP)); - pointer_metrics_recorder_->OnPointerEventObserved(pointer_event, gfx::Point(), - target.get()); - histogram_tester_->ExpectBucketCount(kDestinationHistogramName, 3, 1); -} - -} // namespace ash
diff --git a/ash/metrics/task_switch_metrics_recorder.h b/ash/metrics/task_switch_metrics_recorder.h index c637d4a..164d0ce5 100644 --- a/ash/metrics/task_switch_metrics_recorder.h +++ b/ash/metrics/task_switch_metrics_recorder.h
@@ -10,7 +10,7 @@ #include <unordered_map> #include "ash/ash_export.h" -#include "ash/metrics/task_switch_source.h" +#include "ash/common/metrics/task_switch_source.h" #include "base/macros.h" namespace ash {
diff --git a/ash/metrics/task_switch_source.h b/ash/metrics/task_switch_source.h deleted file mode 100644 index d915281..0000000 --- a/ash/metrics/task_switch_source.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_METRICS_TASK_SWITCH_SOURCE_H_ -#define ASH_METRICS_TASK_SWITCH_SOURCE_H_ - -namespace ash { - -// Enumeration of the different user interfaces that could be the source of -// a task switch. Note this is not necessarily comprehensive of all sources. -enum class TaskSwitchSource { - // Task switches caused by any two sources in this enum. NOTE: This value - // should NOT be used outside of TaskSwitchMetricsRecorder. - ANY, - // Task switches caused by the user activating a task window by clicking or - // tapping on it. - DESKTOP, - // Task switches caused by selecting a window from overview mode which is - // different from the previously-active window. - OVERVIEW_MODE, - // All task switches caused by shelf buttons, not including sub-menus. - SHELF, - // Task switches caused by the WindowCycleController (ie Alt+Tab). - WINDOW_CYCLE_CONTROLLER -}; - -} // namespace ash - -#endif // ASH_METRICS_TASK_SWITCH_SOURCE_H_
diff --git a/ash/metrics/user_metrics_action.h b/ash/metrics/user_metrics_action.h deleted file mode 100644 index e76b613..0000000 --- a/ash/metrics/user_metrics_action.h +++ /dev/null
@@ -1,150 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_METRICS_USER_METRICS_ACTION_H_ -#define ASH_METRICS_USER_METRICS_ACTION_H_ - -namespace ash { - -// Ash-owned user metrics. -enum UserMetricsAction { - UMA_ACCEL_EXIT_FIRST_Q, - UMA_ACCEL_EXIT_SECOND_Q, - UMA_ACCEL_KEYBOARD_BRIGHTNESS_DOWN_F6, - UMA_ACCEL_KEYBOARD_BRIGHTNESS_UP_F7, - UMA_ACCEL_LOCK_SCREEN_LOCK_BUTTON, - UMA_ACCEL_LOCK_SCREEN_POWER_BUTTON, - UMA_ACCEL_MAXIMIZE_RESTORE_F4, - UMA_ACCEL_PREVWINDOW_F5, - UMA_ACCEL_RESTART_POWER_BUTTON, - UMA_ACCEL_SHUT_DOWN_POWER_BUTTON, - UMA_CLOSE_THROUGH_CONTEXT_MENU, - UMA_DESKTOP_SWITCH_TASK, - UMA_DRAG_MAXIMIZE_LEFT, - UMA_DRAG_MAXIMIZE_RIGHT, - UMA_LAUNCHER_BUTTON_PRESSED_WITH_MOUSE, - UMA_LAUNCHER_BUTTON_PRESSED_WITH_TOUCH, - UMA_LAUNCHER_CLICK_ON_APP, - UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON, - UMA_LAUNCHER_LAUNCH_TASK, - UMA_LAUNCHER_MINIMIZE_TASK, - UMA_LAUNCHER_SWITCH_TASK, - UMA_MAXIMIZE_MODE_DISABLED, - UMA_MAXIMIZE_MODE_ENABLED, - UMA_MAXIMIZE_MODE_INITIALLY_DISABLED, - UMA_MOUSE_DOWN, - UMA_PANEL_MINIMIZE_CAPTION_CLICK, - UMA_PANEL_MINIMIZE_CAPTION_GESTURE, - UMA_SHELF_ALIGNMENT_SET_BOTTOM, - UMA_SHELF_ALIGNMENT_SET_LEFT, - UMA_SHELF_ALIGNMENT_SET_RIGHT, - UMA_STATUS_AREA_AUDIO_CURRENT_INPUT_DEVICE, - UMA_STATUS_AREA_AUDIO_CURRENT_OUTPUT_DEVICE, - UMA_STATUS_AREA_AUDIO_SWITCH_INPUT_DEVICE, - UMA_STATUS_AREA_AUDIO_SWITCH_OUTPUT_DEVICE, - UMA_STATUS_AREA_BRIGHTNESS_CHANGED, - UMA_STATUS_AREA_BLUETOOTH_DISABLED, - UMA_STATUS_AREA_BLUETOOTH_ENABLED, - UMA_STATUS_AREA_CAPS_LOCK_DETAILED, - UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK, - UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK, - UMA_STATUS_AREA_CAPS_LOCK_POPUP, - UMA_STATUS_AREA_CAST_STOP_CAST, - UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK, - UMA_STATUS_AREA_CONNECT_TO_UNCONFIGURED_NETWORK, - UMA_STATUS_AREA_CONNECT_TO_VPN, - UMA_STATUS_AREA_CHANGED_VOLUME_MENU, - UMA_STATUS_AREA_CHANGED_VOLUME_POPUP, - UMA_STATUS_AREA_DETAILED_ACCESSABILITY, - UMA_STATUS_AREA_DETAILED_AUDIO_VIEW, - UMA_STATUS_AREA_DETAILED_BLUETOOTH_VIEW, - UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW, - UMA_STATUS_AREA_DETAILED_CAST_VIEW, - UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST, - UMA_STATUS_AREA_DETAILED_DRIVE_VIEW, - UMA_STATUS_AREA_DETAILED_NETWORK_VIEW, - UMA_STATUS_AREA_DETAILED_SMS_VIEW, - UMA_STATUS_AREA_DETAILED_VPN_VIEW, - UMA_STATUS_AREA_DISABLE_AUTO_CLICK, - UMA_STATUS_AREA_DISABLE_HIGH_CONTRAST, - UMA_STATUS_AREA_DISABLE_LARGE_CURSOR, - UMA_STATUS_AREA_DISABLE_MAGNIFIER, - UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK, - UMA_STATUS_AREA_DISABLE_WIFI, - UMA_STATUS_AREA_DISABLE_VIRTUAL_KEYBOARD, - UMA_STATUS_AREA_DISPLAY_DEFAULT_SELECTED, - UMA_STATUS_AREA_DISPLAY_DEFAULT_SHOW_SETTINGS, - UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED, - UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED, - UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS, - UMA_STATUS_AREA_DRIVE_CANCEL_OPERATION, - UMA_STATUS_AREA_DRIVE_SETTINGS, - UMA_STATUS_AREA_ENABLE_AUTO_CLICK, - UMA_STATUS_AREA_ENABLE_HIGH_CONTRAST, - UMA_STATUS_AREA_ENABLE_LARGE_CURSOR, - UMA_STATUS_AREA_ENABLE_MAGNIFIER, - UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK, - UMA_STATUS_AREA_ENABLE_WIFI, - UMA_STATUS_AREA_ENABLE_VIRTUAL_KEYBOARD, - UMA_STATUS_AREA_IME_SHOW_DETAILED, - UMA_STATUS_AREA_IME_SWITCH_MODE, - UMA_STATUS_AREA_MENU_OPENED, - UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED, - UMA_STATUS_AREA_NETWORK_SETTINGS_OPENED, - UMA_STATUS_AREA_OS_UPDATE_DEFAULT_SELECTED, - UMA_STATUS_AREA_SCREEN_CAPTURE_DEFAULT_STOP, - UMA_STATUS_AREA_SCREEN_CAPTURE_NOTIFICATION_STOP, - UMA_STATUS_AREA_SHOW_NETWORK_CONNECTION_DETAILS, - UMA_STATUS_AREA_SHOW_VPN_CONNECTION_DETAILS, - UMA_STATUS_AREA_SIGN_OUT, - UMA_STATUS_AREA_SMS_DETAILED_DISMISS_MSG, - UMA_STATUS_AREA_SMS_NOTIFICATION_DISMISS_MSG, - UMA_STATUS_AREA_TRACING_DEFAULT_SELECTED, - UMA_STATUS_AREA_VPN_ADD_BUILT_IN_CLICKED, - UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED, - UMA_STATUS_AREA_VPN_DISCONNECT_CLICKED, - UMA_STATUS_AREA_VPN_SETTINGS_OPENED, - UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK, - UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE, - UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK, - UMA_TOUCHPAD_GESTURE_OVERVIEW, - UMA_TOUCHSCREEN_TAP_DOWN, - UMA_TRAY_HELP, - UMA_TRAY_LOCK_SCREEN, - UMA_TRAY_OVERVIEW, - UMA_TRAY_SETTINGS, - UMA_TRAY_SHUT_DOWN, - UMA_WINDOW_APP_CLOSE_BUTTON_CLICK, - UMA_WINDOW_CLOSE_BUTTON_CLICK, - UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_EXIT_FULLSCREEN, - UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MAXIMIZE, - UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_MINIMIZE, - UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE, - UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_LEFT, - UMA_WINDOW_MAXIMIZE_BUTTON_MAXIMIZE_RIGHT, - - // Window selection started by beginning an alt+tab cycle. This does not count - // each step through an alt+tab cycle. - UMA_WINDOW_CYCLE, - - // Thumbnail sized overview of windows triggered by pressing the overview key. - UMA_WINDOW_OVERVIEW, - - // User selected a window in overview mode different from the - // previously-active window. - UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED, - - // Selecting a window in overview mode by pressing the enter key. - UMA_WINDOW_OVERVIEW_ENTER_KEY, - - // Closing a window in overview mode by clicking the 'X' button. - UMA_WINDOW_OVERVIEW_CLOSE_BUTTON, - - // Closing a window in overview mode by pressing Ctrl+w shortcut. - UMA_WINDOW_OVERVIEW_CLOSE_KEY, -}; - -} // namespace ash - -#endif // ASH_METRICS_USER_METRICS_ACTION_H_
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc index 639eb1e..414ce2f 100644 --- a/ash/metrics/user_metrics_recorder.cc +++ b/ash/metrics/user_metrics_recorder.cc
@@ -4,20 +4,20 @@ #include "ash/metrics/user_metrics_recorder.h" +#include "ash/common/metrics/pointer_metrics_recorder.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/metrics/desktop_task_switch_metric_recorder.h" -#include "ash/metrics/pointer_metrics_recorder.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_item_types.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h"
diff --git a/ash/metrics/user_metrics_recorder.h b/ash/metrics/user_metrics_recorder.h index 524c5c1..7437dff 100644 --- a/ash/metrics/user_metrics_recorder.h +++ b/ash/metrics/user_metrics_recorder.h
@@ -8,8 +8,8 @@ #include <memory> #include "ash/ash_export.h" +#include "ash/common/metrics/user_metrics_action.h" #include "ash/metrics/task_switch_metrics_recorder.h" -#include "ash/metrics/user_metrics_action.h" #include "base/macros.h" #include "base/timer/timer.h"
diff --git a/ash/metrics/user_metrics_recorder_unittest.cc b/ash/metrics/user_metrics_recorder_unittest.cc index ed228427..8351032 100644 --- a/ash/metrics/user_metrics_recorder_unittest.cc +++ b/ash/metrics/user_metrics_recorder_unittest.cc
@@ -7,12 +7,12 @@ #include <memory> #include "ash/common/login_status.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" -#include "ash/shelf/shelf_model.h" #include "ash/test/ash_test_base.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/test/test_system_tray_delegate.h" #include "ash/test/user_metrics_recorder_test_api.h" #include "base/test/histogram_tester.h" #include "ui/aura/window.h"
diff --git a/ash/mus/accelerators/accelerator_controller_delegate_mus.h b/ash/mus/accelerators/accelerator_controller_delegate_mus.h index fce5bfd..79a30fee 100644 --- a/ash/mus/accelerators/accelerator_controller_delegate_mus.h +++ b/ash/mus/accelerators/accelerator_controller_delegate_mus.h
@@ -5,7 +5,7 @@ #ifndef ASH_MUS_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_MUS_H_ #define ASH_MUS_ACCELERATORS_ACCELERATOR_CONTROLLER_DELEGATE_MUS_H_ -#include "ash/accelerators/accelerator_controller_delegate.h" +#include "ash/common/accelerators/accelerator_controller_delegate.h" #include "base/macros.h" namespace ash {
diff --git a/ash/mus/accelerators/accelerator_controller_registrar.cc b/ash/mus/accelerators/accelerator_controller_registrar.cc index 4bf2c403..ef1f124 100644 --- a/ash/mus/accelerators/accelerator_controller_registrar.cc +++ b/ash/mus/accelerators/accelerator_controller_registrar.cc
@@ -6,8 +6,8 @@ #include <limits> -#include "ash/accelerators/accelerator_controller.h" -#include "ash/accelerators/accelerator_router.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_router.h" #include "ash/common/wm_shell.h" #include "ash/mus/accelerators/accelerator_ids.h" #include "ash/mus/window_manager.h"
diff --git a/ash/mus/bridge/wm_shell_mus.cc b/ash/mus/bridge/wm_shell_mus.cc index 2470cfc4c..8772871 100644 --- a/ash/mus/bridge/wm_shell_mus.cc +++ b/ash/mus/bridge/wm_shell_mus.cc
@@ -6,12 +6,18 @@ #include <utility> -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/key_event_watcher.h" #include "ash/common/session/session_state_delegate.h" #include "ash/common/shell_delegate.h" #include "ash/common/shell_observer.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_event_handler.h" +#include "ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_cycle_event_filter.h" +#include "ash/common/wm/window_resizer.h" #include "ash/common/wm_window.h" #include "ash/mus/accelerators/accelerator_controller_delegate_mus.h" #include "ash/mus/accelerators/accelerator_controller_registrar.h" @@ -26,12 +32,6 @@ #include "ash/shared/immersive_fullscreen_controller.h" #include "ash/shell.h" #include "ash/shell_init_params.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_event_handler.h" -#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_cycle_event_filter.h" -#include "ash/wm/window_resizer.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h" #include "components/user_manager/user_info_impl.h"
diff --git a/ash/mus/bridge/workspace_event_handler_mus.h b/ash/mus/bridge/workspace_event_handler_mus.h index 00a300e..6f10ad7 100644 --- a/ash/mus/bridge/workspace_event_handler_mus.h +++ b/ash/mus/bridge/workspace_event_handler_mus.h
@@ -5,7 +5,7 @@ #ifndef ASH_MUS_BRIDGE_WORKSPACE_EVENT_HANDLER_MUS_H_ #define ASH_MUS_BRIDGE_WORKSPACE_EVENT_HANDLER_MUS_H_ -#include "ash/wm/workspace/workspace_event_handler.h" +#include "ash/common/wm/workspace/workspace_event_handler.h" #include "base/macros.h" namespace aura {
diff --git a/ash/mus/context_menu_mus.cc b/ash/mus/context_menu_mus.cc index e53ae563..c3fe04f 100644 --- a/ash/mus/context_menu_mus.cc +++ b/ash/mus/context_menu_mus.cc
@@ -4,11 +4,11 @@ #include "ash/mus/context_menu_mus.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wallpaper/wallpaper_controller.h" #include "ash/common/wallpaper/wallpaper_delegate.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf.h" #include "ash/strings/grit/ash_strings.h" namespace ash {
diff --git a/ash/mus/context_menu_mus.h b/ash/mus/context_menu_mus.h index c3d27fb..01f69f5 100644 --- a/ash/mus/context_menu_mus.h +++ b/ash/mus/context_menu_mus.h
@@ -5,7 +5,7 @@ #ifndef ASH_MUS_CONTEXT_MENU_MUS_H_ #define ASH_MUS_CONTEXT_MENU_MUS_H_ -#include "ash/shelf/shelf_alignment_menu.h" +#include "ash/common/shelf/shelf_alignment_menu.h" #include "base/macros.h" #include "ui/base/models/simple_menu_model.h"
diff --git a/ash/mus/drag_window_resizer.h b/ash/mus/drag_window_resizer.h index cd46660..4d57087 100644 --- a/ash/mus/drag_window_resizer.h +++ b/ash/mus/drag_window_resizer.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/wm/window_resizer.h" +#include "ash/common/wm/window_resizer.h" #include "base/macros.h" namespace ash {
diff --git a/ash/mus/frame/custom_frame_view_mus.h b/ash/mus/frame/custom_frame_view_mus.h index 3129455..413e45e 100644 --- a/ash/mus/frame/custom_frame_view_mus.h +++ b/ash/mus/frame/custom_frame_view_mus.h
@@ -5,7 +5,7 @@ #ifndef ASH_MUS_FRAME_CUSTOM_FRAME_VIEW_MUS_H_ #define ASH_MUS_FRAME_CUSTOM_FRAME_VIEW_MUS_H_ -#include "ash/frame/custom_frame_view_ash.h" +#include "ash/common/frame/custom_frame_view_ash.h" #include "ui/compositor/paint_cache.h" namespace ash {
diff --git a/ash/mus/frame/detached_title_area_renderer.cc b/ash/mus/frame/detached_title_area_renderer.cc index 181b3f6d..c6f42235 100644 --- a/ash/mus/frame/detached_title_area_renderer.cc +++ b/ash/mus/frame/detached_title_area_renderer.cc
@@ -4,11 +4,11 @@ #include "ash/mus/frame/detached_title_area_renderer.h" +#include "ash/common/frame/header_view.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" -#include "ash/frame/header_view.h" #include "ash/mus/property_util.h" #include "ash/mus/window_manager.h" -#include "ash/wm/window_state.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/transient_window_client.h" #include "ui/aura/mus/property_converter.h"
diff --git a/ash/mus/move_event_handler.h b/ash/mus/move_event_handler.h index 8854c45..754882b 100644 --- a/ash/mus/move_event_handler.h +++ b/ash/mus/move_event_handler.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/wm/wm_toplevel_window_event_handler.h" +#include "ash/common/wm/wm_toplevel_window_event_handler.h" #include "base/macros.h" #include "ui/aura/window_observer.h" #include "ui/events/event_handler.h"
diff --git a/ash/mus/network_connect_delegate_mus.cc b/ash/mus/network_connect_delegate_mus.cc index c28ac5da..5affaed 100644 --- a/ash/mus/network_connect_delegate_mus.cc +++ b/ash/mus/network_connect_delegate_mus.cc
@@ -4,8 +4,8 @@ #include "ash/mus/network_connect_delegate_mus.h" +#include "ash/common/system/tray/system_tray_controller.h" #include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_controller.h" #include "base/logging.h" namespace ash {
diff --git a/ash/mus/non_client_frame_controller.cc b/ash/mus/non_client_frame_controller.cc index 06442090..12b1639f 100644 --- a/ash/mus/non_client_frame_controller.cc +++ b/ash/mus/non_client_frame_controller.cc
@@ -12,8 +12,9 @@ #include "ash/common/ash_constants.h" #include "ash/common/ash_layout_constants.h" +#include "ash/common/frame/custom_frame_view_ash.h" +#include "ash/common/wm/panels/panel_frame_view.h" #include "ash/common/wm_window.h" -#include "ash/frame/custom_frame_view_ash.h" #include "ash/mus/frame/custom_frame_view_mus.h" #include "ash/mus/frame/detached_title_area_renderer.h" #include "ash/mus/move_event_handler.h" @@ -21,7 +22,6 @@ #include "ash/mus/window_manager.h" #include "ash/mus/window_properties.h" #include "ash/shared/immersive_fullscreen_controller_delegate.h" -#include "ash/wm/panels/panel_frame_view.h" #include "ash/wm/window_properties.h" #include "base/macros.h" #include "base/memory/ptr_util.h"
diff --git a/ash/mus/screen_mus.cc b/ash/mus/screen_mus.cc index 4785d7d..e58cff9 100644 --- a/ash/mus/screen_mus.cc +++ b/ash/mus/screen_mus.cc
@@ -4,8 +4,8 @@ #include "ash/mus/screen_mus.h" +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" -#include "ash/wm/root_window_finder.h" #include "services/ui/public/interfaces/display/display_controller.mojom.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h"
diff --git a/ash/mus/shelf_delegate_mus.cc b/ash/mus/shelf_delegate_mus.cc index 4b8ba01..3f0e6d8 100644 --- a/ash/mus/shelf_delegate_mus.cc +++ b/ash/mus/shelf_delegate_mus.cc
@@ -4,8 +4,8 @@ #include "ash/mus/shelf_delegate_mus.h" +#include "ash/common/shelf/shelf_controller.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_controller.h" #include "base/strings/string_util.h" namespace ash {
diff --git a/ash/mus/shelf_delegate_mus.h b/ash/mus/shelf_delegate_mus.h index 9ca5799..8f45b8da 100644 --- a/ash/mus/shelf_delegate_mus.h +++ b/ash/mus/shelf_delegate_mus.h
@@ -7,8 +7,8 @@ #include <string> +#include "ash/common/shelf/shelf_delegate.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_delegate.h" namespace ash {
diff --git a/ash/mus/system_tray_delegate_mus.cc b/ash/mus/system_tray_delegate_mus.cc index 5093f3c..c5d0ee17 100644 --- a/ash/mus/system_tray_delegate_mus.cc +++ b/ash/mus/system_tray_delegate_mus.cc
@@ -4,7 +4,7 @@ #include "ash/mus/system_tray_delegate_mus.h" -#include "ash/system/networking_config_delegate.h" +#include "ash/common/system/networking_config_delegate.h" namespace ash { namespace {
diff --git a/ash/mus/system_tray_delegate_mus.h b/ash/mus/system_tray_delegate_mus.h index 07b4004..87b189f 100644 --- a/ash/mus/system_tray_delegate_mus.h +++ b/ash/mus/system_tray_delegate_mus.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/system/tray/default_system_tray_delegate.h" +#include "ash/common/system/tray/default_system_tray_delegate.h" #include "base/macros.h" namespace ash {
diff --git a/ash/mus/test/ash_test_impl_mus.cc b/ash/mus/test/ash_test_impl_mus.cc index 2aa95e1..71a44f4 100644 --- a/ash/mus/test/ash_test_impl_mus.cc +++ b/ash/mus/test/ash_test_impl_mus.cc
@@ -4,8 +4,8 @@ #include "ash/mus/test/ash_test_impl_mus.h" +#include "ash/common/test/ash_test.h" #include "ash/common/wm_window.h" -#include "ash/test/ash_test.h" #include "base/memory/ptr_util.h" #include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/interfaces/window_manager.mojom.h"
diff --git a/ash/mus/test/ash_test_impl_mus.h b/ash/mus/test/ash_test_impl_mus.h index 5e900aa..e0ba272f 100644 --- a/ash/mus/test/ash_test_impl_mus.h +++ b/ash/mus/test/ash_test_impl_mus.h
@@ -5,8 +5,8 @@ #ifndef ASH_MUS_TEST_ASH_TEST_IMPL_MUS_H_ #define ASH_MUS_TEST_ASH_TEST_IMPL_MUS_H_ +#include "ash/common/test/ash_test_impl.h" #include "ash/mus/test/wm_test_base.h" -#include "ash/test/ash_test_impl.h" #include "base/macros.h" namespace ash {
diff --git a/ash/mus/test/wm_test_helper.cc b/ash/mus/test/wm_test_helper.cc index d079535..d3839cfe 100644 --- a/ash/mus/test/wm_test_helper.cc +++ b/ash/mus/test/wm_test_helper.cc
@@ -4,13 +4,13 @@ #include "ash/mus/test/wm_test_helper.h" +#include "ash/common/test/wm_shell_test_api.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/mus/screen_mus.h" #include "ash/mus/window_manager.h" #include "ash/mus/window_manager_application.h" #include "ash/test/test_shell_delegate.h" -#include "ash/test/wm_shell_test_api.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_number_conversions.h"
diff --git a/ash/mus/top_level_window_factory.cc b/ash/mus/top_level_window_factory.cc index cdcc9e2..602d0c3 100644 --- a/ash/mus/top_level_window_factory.cc +++ b/ash/mus/top_level_window_factory.cc
@@ -4,6 +4,8 @@ #include "ash/mus/top_level_window_factory.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/mus/disconnected_app_handler.h" @@ -14,8 +16,6 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/root_window_settings.h" -#include "ash/wm/container_finder.h" -#include "ash/wm/window_state.h" #include "mojo/public/cpp/bindings/type_converter.h" #include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/interfaces/window_manager.mojom.h"
diff --git a/ash/mus/top_level_window_factory_unittest.cc b/ash/mus/top_level_window_factory_unittest.cc index c4b03e1a..2fb98002 100644 --- a/ash/mus/top_level_window_factory_unittest.cc +++ b/ash/mus/top_level_window_factory_unittest.cc
@@ -10,12 +10,12 @@ #include <string> #include <vector> +#include "ash/common/test/ash_test.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/mus/test/wm_test_base.h" #include "ash/mus/window_manager.h" #include "ash/mus/window_manager_application.h" -#include "ash/test/ash_test.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ui/aura/window.h"
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc index 61338662..8818e3c 100644 --- a/ash/mus/window_manager.cc +++ b/ash/mus/window_manager.cc
@@ -9,6 +9,8 @@ #include <utility> #include "ash/common/session/session_controller.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/mus/accelerators/accelerator_handler.h" #include "ash/mus/accelerators/accelerator_ids.h" @@ -28,8 +30,6 @@ #include "ash/shell.h" #include "ash/shell_init_params.h" #include "ash/wm/ash_focus_rules.h" -#include "ash/wm/container_finder.h" -#include "ash/wm/window_state.h" #include "base/memory/ptr_util.h" #include "base/threading/sequenced_worker_pool.h" #include "services/service_manager/public/cpp/connector.h"
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc index b8a9b91b..c3dbcf5 100644 --- a/ash/mus/window_manager_application.cc +++ b/ash/mus/window_manager_application.cc
@@ -7,10 +7,10 @@ #include <utility> #include "ash/common/mojo_interface_factory.h" +#include "ash/common/system/chromeos/power/power_status.h" #include "ash/common/wm_shell.h" #include "ash/mus/network_connect_delegate_mus.h" #include "ash/mus/window_manager.h" -#include "ash/system/power/power_status.h" #include "base/bind.h" #include "base/memory/ptr_util.h" #include "base/threading/sequenced_worker_pool.h"
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index a4ffb45..f621e805 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc
@@ -15,9 +15,29 @@ #include "ash/common/focus_cycler.h" #include "ash/common/login_status.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/shell_delegate.h" +#include "ash/common/system/status_area_layout_manager.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wallpaper/wallpaper_delegate.h" #include "ash/common/wallpaper/wallpaper_widget_controller.h" +#include "ash/common/wm/always_on_top_controller.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/fullscreen_window_finder.h" +#include "ash/common/wm/lock_layout_manager.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/root_window_layout_manager.h" +#include "ash/common/wm/switchable_windows.h" +#include "ash/common/wm/system_modal_container_layout_manager.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm/workspace/workspace_layout_manager.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/high_contrast/high_contrast_controller.h" @@ -25,39 +45,19 @@ #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_settings.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_widget.h" #include "ash/shelf/shelf_window_targeter.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/status_area_layout_manager.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/touch/touch_hud_debug.h" #include "ash/touch/touch_hud_projection.h" #include "ash/touch/touch_observer_hud.h" -#include "ash/wm/always_on_top_controller.h" #include "ash/wm/boot_splash_screen_chromeos.h" -#include "ash/wm/container_finder.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/lock_layout_manager.h" #include "ash/wm/panels/attached_panel_window_targeter.h" -#include "ash/wm/panels/panel_layout_manager.h" #include "ash/wm/panels/panel_window_event_handler.h" -#include "ash/wm/root_window_layout_manager.h" #include "ash/wm/stacking_controller.h" -#include "ash/wm/switchable_windows.h" -#include "ash/wm/system_modal_container_layout_manager.h" #include "ash/wm/system_wallpaper_controller.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_screen_util.h" -#include "ash/wm/workspace/workspace_layout_manager.h" -#include "ash/wm/workspace_controller.h" #include "base/command_line.h" #include "base/macros.h" #include "base/memory/ptr_util.h"
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 43357016..660b2cf8 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h
@@ -11,8 +11,8 @@ #include "ash/ash_export.h" #include "ash/common/shell_observer.h" +#include "ash/common/wm/workspace/workspace_types.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/wm/workspace/workspace_types.h" #include "base/macros.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h"
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc index 3e4eb29e..cf5c9b9 100644 --- a/ash/root_window_controller_unittest.cc +++ b/ash/root_window_controller_unittest.cc
@@ -8,15 +8,15 @@ #include "ash/common/session/session_controller.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm/system_modal_container_layout_manager.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/system_modal_container_layout_manager.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/command_line.h"
diff --git a/ash/screen_util.cc b/ash/screen_util.cc index d7c7c83..ea11d87 100644 --- a/ash/screen_util.cc +++ b/ash/screen_util.cc
@@ -4,8 +4,8 @@ #include "ash/screen_util.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "base/logging.h" #include "ui/aura/client/screen_position_client.h"
diff --git a/ash/screen_util_unittest.cc b/ash/screen_util_unittest.cc index 9646cbaa..149c18b 100644 --- a/ash/screen_util_unittest.cc +++ b/ash/screen_util_unittest.cc
@@ -4,12 +4,12 @@ #include "ash/screen_util.h" +#include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_screen_util.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc deleted file mode 100644 index 6d2fb33..0000000 --- a/ash/shelf/app_list_button.cc +++ /dev/null
@@ -1,216 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/app_list_button.h" - -#include "ash/common/wm_shell.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/ink_drop_button_listener.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "base/memory/ptr_util.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_mask.h" -#include "ui/views/painter.h" - -namespace ash { - -AppListButton::AppListButton(InkDropButtonListener* listener, - ShelfView* shelf_view, - WmShelf* wm_shelf) - : views::ImageButton(nullptr), - is_showing_app_list_(false), - background_color_(kShelfDefaultBaseColor), - listener_(listener), - shelf_view_(shelf_view), - wm_shelf_(wm_shelf) { - DCHECK(listener_); - DCHECK(shelf_view_); - DCHECK(wm_shelf_); - - SetInkDropMode(InkDropMode::ON_NO_GESTURE_HANDLER); - set_ink_drop_base_color(kShelfInkDropBaseColor); - set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); - SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE)); - SetSize( - gfx::Size(GetShelfConstant(SHELF_SIZE), GetShelfConstant(SHELF_SIZE))); - SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); - set_notify_action(CustomButton::NOTIFY_ON_PRESS); -} - -AppListButton::~AppListButton() {} - -void AppListButton::OnAppListShown() { - AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr); - is_showing_app_list_ = true; - wm_shelf_->UpdateAutoHideState(); -} - -void AppListButton::OnAppListDismissed() { - AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr); - is_showing_app_list_ = false; - wm_shelf_->UpdateAutoHideState(); -} - -void AppListButton::UpdateShelfItemBackground(SkColor color) { - background_color_ = color; - SchedulePaint(); -} - -bool AppListButton::OnMousePressed(const ui::MouseEvent& event) { - ImageButton::OnMousePressed(event); - shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); - return true; -} - -void AppListButton::OnMouseReleased(const ui::MouseEvent& event) { - ImageButton::OnMouseReleased(event); - shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); -} - -void AppListButton::OnMouseCaptureLost() { - shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, true); - ImageButton::OnMouseCaptureLost(); -} - -bool AppListButton::OnMouseDragged(const ui::MouseEvent& event) { - ImageButton::OnMouseDragged(event); - shelf_view_->PointerDraggedOnButton(this, ShelfView::MOUSE, event); - return true; -} - -void AppListButton::OnGestureEvent(ui::GestureEvent* event) { - switch (event->type()) { - case ui::ET_GESTURE_SCROLL_BEGIN: - AnimateInkDrop(views::InkDropState::HIDDEN, event); - shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); - event->SetHandled(); - return; - case ui::ET_GESTURE_SCROLL_UPDATE: - shelf_view_->PointerDraggedOnButton(this, ShelfView::TOUCH, *event); - event->SetHandled(); - return; - case ui::ET_GESTURE_SCROLL_END: - case ui::ET_SCROLL_FLING_START: - shelf_view_->PointerReleasedOnButton(this, ShelfView::TOUCH, false); - event->SetHandled(); - return; - case ui::ET_GESTURE_TAP_DOWN: - if (!WmShell::Get()->IsApplistVisible()) - AnimateInkDrop(views::InkDropState::ACTION_PENDING, event); - ImageButton::OnGestureEvent(event); - break; - default: - ImageButton::OnGestureEvent(event); - return; - } -} - -void AppListButton::OnPaint(gfx::Canvas* canvas) { - // Call the base class first to paint any background/borders. - View::OnPaint(canvas); - - gfx::PointF circle_center(GetCenterPoint()); - - // Paint the circular background. - cc::PaintFlags bg_flags; - bg_flags.setColor(background_color_); - bg_flags.setAntiAlias(true); - bg_flags.setStyle(cc::PaintFlags::kFill_Style); - canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags); - - // Paint a white ring as the foreground. The ceil/dsf math assures that the - // ring draws sharply and is centered at all scale factors. - const float kRingOuterRadiusDp = 7.f; - const float kRingThicknessDp = 1.5f; - gfx::ScopedCanvas scoped_canvas(canvas); - const float dsf = canvas->UndoDeviceScaleFactor(); - circle_center.Scale(dsf); - - cc::PaintFlags fg_flags; - fg_flags.setAntiAlias(true); - fg_flags.setStyle(cc::PaintFlags::kStroke_Style); - fg_flags.setColor(kShelfIconColor); - const float thickness = std::ceil(kRingThicknessDp * dsf); - const float radius = std::ceil(kRingOuterRadiusDp * dsf) - thickness / 2; - fg_flags.setStrokeWidth(thickness); - // Make sure the center of the circle lands on pixel centers. - canvas->DrawCircle(circle_center, radius, fg_flags); - - views::Painter::PaintFocusPainter(this, canvas, focus_painter()); -} - -void AppListButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_BUTTON; - node_data->SetName(shelf_view_->GetTitleForView(this)); -} - -std::unique_ptr<views::InkDropRipple> AppListButton::CreateInkDropRipple() - const { - gfx::Point center = GetCenterPoint(); - gfx::Rect bounds(center.x() - kAppListButtonRadius, - center.y() - kAppListButtonRadius, 2 * kAppListButtonRadius, - 2 * kAppListButtonRadius); - return base::MakeUnique<views::FloodFillInkDropRipple>( - size(), GetLocalBounds().InsetsFrom(bounds), - GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(), - ink_drop_visible_opacity()); -} - -void AppListButton::NotifyClick(const ui::Event& event) { - ImageButton::NotifyClick(event); - if (listener_) - listener_->ButtonPressed(this, event, GetInkDrop()); -} - -bool AppListButton::ShouldEnterPushedState(const ui::Event& event) { - if (!shelf_view_->ShouldEventActivateButton(this, event)) - return false; - if (WmShell::Get()->IsApplistVisible()) - return false; - return views::ImageButton::ShouldEnterPushedState(event); -} - -std::unique_ptr<views::InkDrop> AppListButton::CreateInkDrop() { - std::unique_ptr<views::InkDropImpl> ink_drop = - CustomButton::CreateDefaultInkDropImpl(); - ink_drop->SetShowHighlightOnHover(false); - return std::move(ink_drop); -} - -std::unique_ptr<views::InkDropMask> AppListButton::CreateInkDropMask() const { - return base::MakeUnique<views::CircleInkDropMask>(size(), GetCenterPoint(), - kAppListButtonRadius); -} - -gfx::Point AppListButton::GetCenterPoint() const { - // For a bottom-aligned shelf, the button bounds could have a larger height - // than width (in the case of touch-dragging the shelf updwards) or a larger - // width than height (in the case of a shelf hide/show animation), so adjust - // the y-position of the circle's center to ensure correct layout. Similarly - // adjust the x-position for a left- or right-aligned shelf. - const int x_mid = width() / 2.f; - const int y_mid = height() / 2.f; - ShelfAlignment alignment = wm_shelf_->GetAlignment(); - if (alignment == SHELF_ALIGNMENT_BOTTOM || - alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { - return gfx::Point(x_mid, x_mid); - } else if (alignment == SHELF_ALIGNMENT_RIGHT) { - return gfx::Point(y_mid, y_mid); - } else { - DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT); - return gfx::Point(width() - y_mid, y_mid); - } -} - -} // namespace ash
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h deleted file mode 100644 index 494017b2..0000000 --- a/ash/shelf/app_list_button.h +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_APP_LIST_BUTTON_H_ -#define ASH_SHELF_APP_LIST_BUTTON_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/views/controls/button/image_button.h" - -namespace ash { -class InkDropButtonListener; -class ShelfView; -class WmShelf; - -// Button used for the AppList icon on the shelf. -class ASH_EXPORT AppListButton : public views::ImageButton { - public: - AppListButton(InkDropButtonListener* listener, - ShelfView* shelf_view, - WmShelf* wm_shelf); - ~AppListButton() override; - - void OnAppListShown(); - void OnAppListDismissed(); - - bool is_showing_app_list() const { return is_showing_app_list_; } - - // Updates background and schedules a paint. - void UpdateShelfItemBackground(SkColor color); - - protected: - // views::ImageButton overrides: - bool OnMousePressed(const ui::MouseEvent& event) override; - void OnMouseReleased(const ui::MouseEvent& event) override; - void OnMouseCaptureLost() override; - bool OnMouseDragged(const ui::MouseEvent& event) override; - void OnPaint(gfx::Canvas* canvas) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - void NotifyClick(const ui::Event& event) override; - bool ShouldEnterPushedState(const ui::Event& event) override; - std::unique_ptr<views::InkDrop> CreateInkDrop() override; - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; - - // ui::EventHandler overrides: - void OnGestureEvent(ui::GestureEvent* event) override; - - private: - // Get the center point of the app list button used to draw its background and - // ink drops. - gfx::Point GetCenterPoint() const; - - // True if the app list is currently showing for this display. - // This is useful because other IsApplistVisible functions aren't per-display. - bool is_showing_app_list_; - - // Color used to paint the background. - SkColor background_color_; - - InkDropButtonListener* listener_; - ShelfView* shelf_view_; - WmShelf* wm_shelf_; - - DISALLOW_COPY_AND_ASSIGN(AppListButton); -}; - -} // namespace ash - -#endif // ASH_SHELF_APP_LIST_BUTTON_H_
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc deleted file mode 100644 index b2ba8a2..0000000 --- a/ash/shelf/app_list_shelf_item_delegate.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/app_list_shelf_item_delegate.h" - -#include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_model.h" -#include "ash/strings/grit/ash_strings.h" -#include "base/memory/ptr_util.h" -#include "ui/app_list/app_list_switches.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -// static -void AppListShelfItemDelegate::CreateAppListItemAndDelegate(ShelfModel* model) { - // Add the app list item to the shelf model. - ShelfItem item; - item.type = TYPE_APP_LIST; - item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE); - int index = model->Add(item); - DCHECK_GE(index, 0); - - // Create an AppListShelfItemDelegate for that item. - ShelfID id = model->items()[index].id; - DCHECK_GE(id, 0); - model->SetShelfItemDelegate(id, base::MakeUnique<AppListShelfItemDelegate>()); -} - -AppListShelfItemDelegate::AppListShelfItemDelegate() {} - -AppListShelfItemDelegate::~AppListShelfItemDelegate() {} - -ShelfAction AppListShelfItemDelegate::ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) { - WmShell::Get()->ToggleAppList(); - return SHELF_ACTION_APP_LIST_SHOWN; -} - -ShelfAppMenuItemList AppListShelfItemDelegate::GetAppMenuItems( - int event_flags) { - // Return an empty item list to avoid showing an application menu. - return ShelfAppMenuItemList(); -} - -void AppListShelfItemDelegate::ExecuteCommand(uint32_t command_id, - int event_flags) { - // This delegate does not support showing an application menu. - NOTIMPLEMENTED(); -} - -void AppListShelfItemDelegate::Close() {} - -} // namespace ash
diff --git a/ash/shelf/app_list_shelf_item_delegate.h b/ash/shelf/app_list_shelf_item_delegate.h deleted file mode 100644 index 0f52bf6..0000000 --- a/ash/shelf/app_list_shelf_item_delegate.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_ -#define ASH_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_ - -#include "ash/shelf/shelf_item_delegate.h" -#include "base/macros.h" - -namespace ash { -class ShelfModel; - -// ShelfItemDelegate for TYPE_APP_LIST. -class AppListShelfItemDelegate : public ShelfItemDelegate { - public: - // Initializes the app list item in the shelf data model and creates an - // AppListShelfItemDelegate which will be owned by |model|. - static void CreateAppListItemAndDelegate(ShelfModel* model); - - AppListShelfItemDelegate(); - ~AppListShelfItemDelegate() override; - - // ShelfItemDelegate: - ShelfAction ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) override; - ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; - void ExecuteCommand(uint32_t command_id, int event_flags) override; - void Close() override; - - private: - DISALLOW_COPY_AND_ASSIGN(AppListShelfItemDelegate); -}; - -} // namespace ash - -#endif // ASH_SHELF_APP_LIST_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/shelf/ink_drop_button_listener.h b/ash/shelf/ink_drop_button_listener.h deleted file mode 100644 index 48b10ae..0000000 --- a/ash/shelf/ink_drop_button_listener.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_INK_DROP_BUTTON_LISTENER_H_ -#define ASH_SHELF_INK_DROP_BUTTON_LISTENER_H_ - -#include "ash/ash_export.h" - -namespace ui { -class Event; -} - -namespace views { -class Button; -class InkDrop; -} - -namespace ash { - -// An interface used by buttons on shelf to notify ShelfView when they are -// pressed. |ink_drop| is used to do appropriate ink drop animation based on the -// action performed. -// TODO(mohsen): A better approach would be to return a value indicating the -// type of action performed such that the button can animate the ink drop. -// Currently, it is not possible because showing menu is synchronous and blocks -// the call. Fix this after menu is converted to synchronous. Long-term, the -// return value can be merged into ButtonListener. -class ASH_EXPORT InkDropButtonListener { - public: - virtual void ButtonPressed(views::Button* sender, - const ui::Event& event, - views::InkDrop* ink_drop) = 0; - - protected: - virtual ~InkDropButtonListener() {} -}; - -} // namespace ash - -#endif // ASH_SHELF_INK_DROP_BUTTON_LISTENER_H_
diff --git a/ash/shelf/overflow_bubble.cc b/ash/shelf/overflow_bubble.cc deleted file mode 100644 index 2f09f860..0000000 --- a/ash/shelf/overflow_bubble.cc +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/overflow_bubble.h" - -#include "ash/common/wm_shell.h" -#include "ash/shelf/overflow_bubble_view.h" -#include "ash/shelf/overflow_button.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/tray/tray_background_view.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -OverflowBubble::OverflowBubble(WmShelf* wm_shelf) - : wm_shelf_(wm_shelf), - bubble_(nullptr), - overflow_button_(nullptr), - shelf_view_(nullptr) { - DCHECK(wm_shelf_); - WmShell::Get()->AddPointerWatcher(this, - views::PointerWatcherEventTypes::BASIC); -} - -OverflowBubble::~OverflowBubble() { - Hide(); - WmShell::Get()->RemovePointerWatcher(this); -} - -void OverflowBubble::Show(OverflowButton* overflow_button, - ShelfView* shelf_view) { - DCHECK(overflow_button); - DCHECK(shelf_view); - - Hide(); - - bubble_ = new OverflowBubbleView(wm_shelf_); - bubble_->InitOverflowBubble(overflow_button, shelf_view); - shelf_view_ = shelf_view; - overflow_button_ = overflow_button; - - TrayBackgroundView::InitializeBubbleAnimations(bubble_->GetWidget()); - bubble_->GetWidget()->AddObserver(this); - bubble_->GetWidget()->Show(); - - overflow_button->OnOverflowBubbleShown(); -} - -void OverflowBubble::Hide() { - if (!IsShowing()) - return; - - OverflowButton* overflow_button = overflow_button_; - - bubble_->GetWidget()->RemoveObserver(this); - bubble_->GetWidget()->Close(); - bubble_ = nullptr; - overflow_button_ = nullptr; - shelf_view_ = nullptr; - - overflow_button->OnOverflowBubbleHidden(); -} - -void OverflowBubble::ProcessPressedEvent( - const gfx::Point& event_location_in_screen) { - if (IsShowing() && !shelf_view_->IsShowingMenu() && - !bubble_->GetBoundsInScreen().Contains(event_location_in_screen) && - !overflow_button_->GetBoundsInScreen().Contains( - event_location_in_screen)) { - Hide(); - } -} - -void OverflowBubble::OnPointerEventObserved( - const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - if (event.type() == ui::ET_POINTER_DOWN) - ProcessPressedEvent(location_in_screen); -} - -void OverflowBubble::OnWidgetDestroying(views::Widget* widget) { - DCHECK(widget == bubble_->GetWidget()); - // Update the overflow button in the parent ShelfView. - overflow_button_->SchedulePaint(); - bubble_ = nullptr; - overflow_button_ = nullptr; - shelf_view_ = nullptr; -} - -} // namespace ash
diff --git a/ash/shelf/overflow_bubble.h b/ash/shelf/overflow_bubble.h deleted file mode 100644 index d6afdf83..0000000 --- a/ash/shelf/overflow_bubble.h +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_OVERFLOW_BUBBLE_H_ -#define ASH_SHELF_OVERFLOW_BUBBLE_H_ - -#include "base/macros.h" -#include "ui/views/pointer_watcher.h" -#include "ui/views/widget/widget_observer.h" - -namespace ui { -class PointerEvent; -} - -namespace ash { -class OverflowBubbleView; -class OverflowButton; -class ShelfView; -class WmShelf; - -// OverflowBubble shows shelf items that won't fit on the main shelf in a -// separate bubble. -class OverflowBubble : public views::PointerWatcher, - public views::WidgetObserver { - public: - // |wm_shelf| is the shelf that spawns the bubble. - explicit OverflowBubble(WmShelf* wm_shelf); - ~OverflowBubble() override; - - // Shows an bubble pointing to |overflow_button| with |shelf_view| as its - // content. This |shelf_view| is different than the main shelf's view and - // only contains the overflow items. - void Show(OverflowButton* overflow_button, ShelfView* shelf_view); - - void Hide(); - - bool IsShowing() const { return !!bubble_; } - ShelfView* shelf_view() { return shelf_view_; } - OverflowBubbleView* bubble_view() { return bubble_; } - - private: - void ProcessPressedEvent(const gfx::Point& event_location_in_screen); - - // views::PointerWatcher: - void OnPointerEventObserved(const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - - // Overridden from views::WidgetObserver: - void OnWidgetDestroying(views::Widget* widget) override; - - WmShelf* wm_shelf_; - OverflowBubbleView* bubble_; // Owned by views hierarchy. - OverflowButton* overflow_button_; // Owned by ShelfView. - - // ShelfView containing the overflow items. Owned by |bubble_|. - ShelfView* shelf_view_; - - DISALLOW_COPY_AND_ASSIGN(OverflowBubble); -}; - -} // namespace ash - -#endif // ASH_SHELF_OVERFLOW_BUBBLE_H_
diff --git a/ash/shelf/overflow_bubble_view.cc b/ash/shelf/overflow_bubble_view.cc deleted file mode 100644 index 80d8f09..0000000 --- a/ash/shelf/overflow_bubble_view.cc +++ /dev/null
@@ -1,228 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/overflow_bubble_view.h" - -#include <algorithm> - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/events/event.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/views/bubble/bubble_frame_view.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -// Max bubble size to screen size ratio. -const float kMaxBubbleSizeToScreenRatio = 0.5f; - -// Inner padding in pixels for shelf view inside bubble. -const int kPadding = 2; - -// Padding space in pixels between ShelfView's left/top edge to its contents. -const int kShelfViewLeadingInset = 8; - -} // namespace - -OverflowBubbleView::OverflowBubbleView(WmShelf* wm_shelf) - : wm_shelf_(wm_shelf), shelf_view_(nullptr) { - DCHECK(wm_shelf_); -} - -OverflowBubbleView::~OverflowBubbleView() {} - -void OverflowBubbleView::InitOverflowBubble(views::View* anchor, - views::View* shelf_view) { - shelf_view_ = shelf_view; - - SetAnchorView(anchor); - set_arrow(GetBubbleArrow()); - set_mirror_arrow_in_rtl(false); - set_background(nullptr); - set_color(kShelfDefaultBaseColor); - set_margins(gfx::Insets(kPadding, kPadding, kPadding, kPadding)); - // Overflow bubble should not get focus. If it get focus when it is shown, - // active state item is changed to running state. - set_can_activate(false); - - // Makes bubble view has a layer and clip its children layers. - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetMasksToBounds(true); - - // Calls into OnBeforeBubbleWidgetInit to set the window parent container. - views::BubbleDialogDelegateView::CreateBubble(this); - AddChildView(shelf_view_); -} - -const gfx::Size OverflowBubbleView::GetContentsSize() const { - return shelf_view_->GetPreferredSize(); -} - -// Gets arrow location based on shelf alignment. -views::BubbleBorder::Arrow OverflowBubbleView::GetBubbleArrow() const { - switch (wm_shelf_->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - return views::BubbleBorder::BOTTOM_LEFT; - case SHELF_ALIGNMENT_LEFT: - return views::BubbleBorder::LEFT_TOP; - case SHELF_ALIGNMENT_RIGHT: - return views::BubbleBorder::RIGHT_TOP; - } - NOTREACHED(); - return views::BubbleBorder::NONE; -} - -void OverflowBubbleView::ScrollByXOffset(int x_offset) { - const gfx::Rect visible_bounds(GetContentsBounds()); - const gfx::Size contents_size(GetContentsSize()); - - DCHECK_GE(contents_size.width(), visible_bounds.width()); - int x = std::min(contents_size.width() - visible_bounds.width(), - std::max(0, scroll_offset_.x() + x_offset)); - scroll_offset_.set_x(x); -} - -void OverflowBubbleView::ScrollByYOffset(int y_offset) { - const gfx::Rect visible_bounds(GetContentsBounds()); - const gfx::Size contents_size(GetContentsSize()); - - DCHECK_GE(contents_size.width(), visible_bounds.width()); - int y = std::min(contents_size.height() - visible_bounds.height(), - std::max(0, scroll_offset_.y() + y_offset)); - scroll_offset_.set_y(y); -} - -gfx::Size OverflowBubbleView::GetPreferredSize() const { - gfx::Size preferred_size = GetContentsSize(); - - const gfx::Rect monitor_rect = - display::Screen::GetScreen() - ->GetDisplayNearestPoint(GetAnchorRect().CenterPoint()) - .work_area(); - if (!monitor_rect.IsEmpty()) { - if (wm_shelf_->IsHorizontalAlignment()) { - preferred_size.set_width( - std::min(preferred_size.width(), - static_cast<int>(monitor_rect.width() * - kMaxBubbleSizeToScreenRatio))); - } else { - preferred_size.set_height( - std::min(preferred_size.height(), - static_cast<int>(monitor_rect.height() * - kMaxBubbleSizeToScreenRatio))); - } - } - - return preferred_size; -} - -void OverflowBubbleView::Layout() { - shelf_view_->SetBoundsRect(gfx::Rect( - gfx::PointAtOffsetFromOrigin(-scroll_offset_), GetContentsSize())); -} - -void OverflowBubbleView::ChildPreferredSizeChanged(views::View* child) { - // When contents size is changed, ContentsBounds should be updated before - // calculating scroll offset. - SizeToContents(); - - // Ensures |shelf_view_| is still visible. - if (wm_shelf_->IsHorizontalAlignment()) - ScrollByXOffset(0); - else - ScrollByYOffset(0); - Layout(); -} - -bool OverflowBubbleView::OnMouseWheel(const ui::MouseWheelEvent& event) { - // The MouseWheelEvent was changed to support both X and Y offsets - // recently, but the behavior of this function was retained to continue - // using Y offsets only. Might be good to simply scroll in both - // directions as in OverflowBubbleView::OnScrollEvent. - if (wm_shelf_->IsHorizontalAlignment()) - ScrollByXOffset(-event.y_offset()); - else - ScrollByYOffset(-event.y_offset()); - Layout(); - - return true; -} - -void OverflowBubbleView::OnScrollEvent(ui::ScrollEvent* event) { - ScrollByXOffset(-event->x_offset()); - ScrollByYOffset(-event->y_offset()); - Layout(); - event->SetHandled(); -} - -int OverflowBubbleView::GetDialogButtons() const { - return ui::DIALOG_BUTTON_NONE; -} - -void OverflowBubbleView::OnBeforeBubbleWidgetInit( - views::Widget::InitParams* params, - views::Widget* bubble_widget) const { - // Place the bubble in the same root window as the anchor. - WmWindow::Get(anchor_widget()->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - bubble_widget, kShellWindowId_ShelfBubbleContainer, params); -} - -gfx::Rect OverflowBubbleView::GetBubbleBounds() { - views::BubbleBorder* border = GetBubbleFrameView()->bubble_border(); - gfx::Insets bubble_insets = border->GetInsets(); - - const int border_size = views::BubbleBorder::is_arrow_on_horizontal(arrow()) - ? bubble_insets.left() - : bubble_insets.top(); - const int arrow_offset = border_size + kPadding + kShelfViewLeadingInset + - GetShelfConstant(SHELF_SIZE) / 2; - - const gfx::Size content_size = GetPreferredSize(); - border->set_arrow_offset(arrow_offset); - - const gfx::Rect anchor_rect = GetAnchorRect(); - gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds( - anchor_rect, content_size, false); - - gfx::Rect monitor_rect = - display::Screen::GetScreen() - ->GetDisplayNearestPoint(anchor_rect.CenterPoint()) - .work_area(); - - int offset = 0; - if (views::BubbleBorder::is_arrow_on_horizontal(arrow())) { - if (bubble_rect.x() < monitor_rect.x()) - offset = monitor_rect.x() - bubble_rect.x(); - else if (bubble_rect.right() > monitor_rect.right()) - offset = monitor_rect.right() - bubble_rect.right(); - - bubble_rect.Offset(offset, 0); - border->set_arrow_offset(anchor_rect.CenterPoint().x() - bubble_rect.x()); - } else { - if (bubble_rect.y() < monitor_rect.y()) - offset = monitor_rect.y() - bubble_rect.y(); - else if (bubble_rect.bottom() > monitor_rect.bottom()) - offset = monitor_rect.bottom() - bubble_rect.bottom(); - - bubble_rect.Offset(0, offset); - border->set_arrow_offset(anchor_rect.CenterPoint().y() - bubble_rect.y()); - } - - GetBubbleFrameView()->SchedulePaint(); - return bubble_rect; -} - -} // namespace ash
diff --git a/ash/shelf/overflow_bubble_view.h b/ash/shelf/overflow_bubble_view.h deleted file mode 100644 index 1e2ae83..0000000 --- a/ash/shelf/overflow_bubble_view.h +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_OVERFLOW_BUBBLE_VIEW_H_ -#define ASH_SHELF_OVERFLOW_BUBBLE_VIEW_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/views/bubble/bubble_dialog_delegate.h" - -namespace views { -class View; -} - -namespace ash { -class WmShelf; - -namespace test { -class OverflowBubbleViewTestAPI; -} - -// OverflowBubbleView hosts a ShelfView to display overflown items. -// Exports to access this class from OverflowBubbleViewTestAPI. -class ASH_EXPORT OverflowBubbleView : public views::BubbleDialogDelegateView { - public: - explicit OverflowBubbleView(WmShelf* wm_shelf); - ~OverflowBubbleView() override; - - // |anchor| is the overflow button on the main shelf. |shelf_view| is the - // ShelfView containing the overflow items. - void InitOverflowBubble(views::View* anchor, views::View* shelf_view); - - // views::BubbleDialogDelegateView overrides: - int GetDialogButtons() const override; - void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, - views::Widget* bubble_widget) const override; - gfx::Rect GetBubbleBounds() override; - - private: - friend class test::OverflowBubbleViewTestAPI; - - const gfx::Size GetContentsSize() const; - - // Gets arrow location based on shelf alignment. - views::BubbleBorder::Arrow GetBubbleArrow() const; - - void ScrollByXOffset(int x_offset); - void ScrollByYOffset(int y_offset); - - // views::View overrides: - gfx::Size GetPreferredSize() const override; - void Layout() override; - void ChildPreferredSizeChanged(views::View* child) override; - bool OnMouseWheel(const ui::MouseWheelEvent& event) override; - - // ui::EventHandler overrides: - void OnScrollEvent(ui::ScrollEvent* event) override; - - WmShelf* wm_shelf_; - views::View* shelf_view_; // Owned by views hierarchy. - gfx::Vector2d scroll_offset_; - - DISALLOW_COPY_AND_ASSIGN(OverflowBubbleView); -}; - -} // namespace ash - -#endif // ASH_SHELF_OVERFLOW_BUBBLE_VIEW_H_
diff --git a/ash/shelf/overflow_button.cc b/ash/shelf/overflow_button.cc deleted file mode 100644 index e7944aa..0000000 --- a/ash/shelf/overflow_button.cc +++ /dev/null
@@ -1,150 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/overflow_button.h" - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" -#include "base/memory/ptr_util.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/skbitmap_operations.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_mask.h" - -namespace ash { - -OverflowButton::OverflowButton(ShelfView* shelf_view, WmShelf* wm_shelf) - : CustomButton(nullptr), - shelf_view_(shelf_view), - wm_shelf_(wm_shelf), - background_color_(kShelfDefaultBaseColor) { - DCHECK(shelf_view_); - - SetInkDropMode(InkDropMode::ON); - set_ink_drop_base_color(kShelfInkDropBaseColor); - set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); - set_hide_ink_drop_when_showing_context_menu(false); - bottom_image_ = gfx::CreateVectorIcon(kShelfOverflowIcon, kShelfIconColor); - - SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); - SetAccessibleName(l10n_util::GetStringUTF16(IDS_ASH_SHELF_OVERFLOW_NAME)); -} - -OverflowButton::~OverflowButton() {} - -void OverflowButton::OnShelfAlignmentChanged() { - SchedulePaint(); -} - -void OverflowButton::OnOverflowBubbleShown() { - AnimateInkDrop(views::InkDropState::ACTIVATED, nullptr); -} - -void OverflowButton::OnOverflowBubbleHidden() { - AnimateInkDrop(views::InkDropState::DEACTIVATED, nullptr); -} - -void OverflowButton::UpdateShelfItemBackground(SkColor color) { - background_color_ = color; - SchedulePaint(); -} - -void OverflowButton::OnPaint(gfx::Canvas* canvas) { - gfx::Rect bounds = CalculateButtonBounds(); - PaintBackground(canvas, bounds); - PaintForeground(canvas, bounds); -} - -std::unique_ptr<views::InkDrop> OverflowButton::CreateInkDrop() { - std::unique_ptr<views::InkDropImpl> ink_drop = - CreateDefaultFloodFillInkDropImpl(); - ink_drop->SetShowHighlightOnHover(false); - ink_drop->SetAutoHighlightMode(views::InkDropImpl::AutoHighlightMode::NONE); - return std::move(ink_drop); -} - -std::unique_ptr<views::InkDropRipple> OverflowButton::CreateInkDropRipple() - const { - gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds()); - return base::MakeUnique<views::FloodFillInkDropRipple>( - size(), insets, GetInkDropCenterBasedOnLastEvent(), GetInkDropBaseColor(), - ink_drop_visible_opacity()); -} - -bool OverflowButton::ShouldEnterPushedState(const ui::Event& event) { - if (shelf_view_->IsShowingOverflowBubble()) - return false; - - return CustomButton::ShouldEnterPushedState(event); -} - -void OverflowButton::NotifyClick(const ui::Event& event) { - CustomButton::NotifyClick(event); - shelf_view_->ButtonPressed(this, event, GetInkDrop()); -} - -std::unique_ptr<views::InkDropMask> OverflowButton::CreateInkDropMask() const { - gfx::Insets insets = GetLocalBounds().InsetsFrom(CalculateButtonBounds()); - return base::MakeUnique<views::RoundRectInkDropMask>( - size(), insets, kOverflowButtonCornerRadius); -} - -void OverflowButton::PaintBackground(gfx::Canvas* canvas, - const gfx::Rect& bounds) { - cc::PaintFlags flags; - flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); - flags.setColor(background_color_); - canvas->DrawRoundRect(bounds, kOverflowButtonCornerRadius, flags); -} - -void OverflowButton::PaintForeground(gfx::Canvas* canvas, - const gfx::Rect& bounds) { - const gfx::ImageSkia* image = nullptr; - - switch (wm_shelf_->GetAlignment()) { - case SHELF_ALIGNMENT_LEFT: - if (left_image_.isNull()) { - left_image_ = gfx::ImageSkiaOperations::CreateRotatedImage( - bottom_image_, SkBitmapOperations::ROTATION_90_CW); - } - image = &left_image_; - break; - case SHELF_ALIGNMENT_RIGHT: - if (right_image_.isNull()) { - right_image_ = gfx::ImageSkiaOperations::CreateRotatedImage( - bottom_image_, SkBitmapOperations::ROTATION_270_CW); - } - image = &right_image_; - break; - default: - image = &bottom_image_; - break; - } - - canvas->DrawImageInt(*image, - bounds.x() + ((bounds.width() - image->width()) / 2), - bounds.y() + ((bounds.height() - image->height()) / 2)); -} - -gfx::Rect OverflowButton::CalculateButtonBounds() const { - ShelfAlignment alignment = wm_shelf_->GetAlignment(); - gfx::Rect content_bounds = GetContentsBounds(); - // Align the button to the top of a bottom-aligned shelf, to the right edge - // a left-aligned shelf, and to the left edge of a right-aligned shelf. - const int inset = (GetShelfConstant(SHELF_SIZE) - kOverflowButtonSize) / 2; - const int x = alignment == SHELF_ALIGNMENT_LEFT - ? content_bounds.right() - inset - kOverflowButtonSize - : content_bounds.x() + inset; - return gfx::Rect(x, content_bounds.y() + inset, kOverflowButtonSize, - kOverflowButtonSize); -} - -} // namespace ash
diff --git a/ash/shelf/overflow_button.h b/ash/shelf/overflow_button.h deleted file mode 100644 index aaca229..0000000 --- a/ash/shelf/overflow_button.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_OVERFLOW_BUTTON_H_ -#define ASH_SHELF_OVERFLOW_BUTTON_H_ - -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/controls/button/custom_button.h" - -namespace ash { -class ShelfView; -class WmShelf; - -// Shelf overflow chevron button. -class OverflowButton : public views::CustomButton { - public: - // |shelf_view| is the view containing this button. - OverflowButton(ShelfView* shelf_view, WmShelf* wm_shelf); - ~OverflowButton() override; - - void OnShelfAlignmentChanged(); - void OnOverflowBubbleShown(); - void OnOverflowBubbleHidden(); - - // Updates background and schedules a paint. - void UpdateShelfItemBackground(SkColor color); - - private: - // views::CustomButton: - void OnPaint(gfx::Canvas* canvas) override; - std::unique_ptr<views::InkDrop> CreateInkDrop() override; - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - bool ShouldEnterPushedState(const ui::Event& event) override; - void NotifyClick(const ui::Event& event) override; - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; - - // Helper functions to paint the background and foreground of the button - // at |bounds|. - void PaintBackground(gfx::Canvas* canvas, const gfx::Rect& bounds); - void PaintForeground(gfx::Canvas* canvas, const gfx::Rect& bounds); - - // Calculates the bounds of the overflow button based on the shelf alignment. - gfx::Rect CalculateButtonBounds() const; - - // Used for bottom shelf alignment. - gfx::ImageSkia bottom_image_; - - // Cached rotations of |bottom_image_| used for left and right shelf - // alignments. - gfx::ImageSkia left_image_; - gfx::ImageSkia right_image_; - - ShelfView* shelf_view_; - WmShelf* wm_shelf_; - - // Color used to paint the background. - SkColor background_color_; - - DISALLOW_COPY_AND_ASSIGN(OverflowButton); -}; - -} // namespace ash - -#endif // ASH_SHELF_OVERFLOW_BUTTON_H_
diff --git a/ash/shelf/shelf_alignment_menu.cc b/ash/shelf/shelf_alignment_menu.cc deleted file mode 100644 index 5429b4e..0000000 --- a/ash/shelf/shelf_alignment_menu.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_alignment_menu.h" - -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" - -namespace ash { - -ShelfAlignmentMenu::ShelfAlignmentMenu(WmShelf* wm_shelf) - : ui::SimpleMenuModel(nullptr), wm_shelf_(wm_shelf) { - DCHECK(wm_shelf_); - const int align_group_id = 1; - set_delegate(this); - AddRadioItemWithStringId( - MENU_ALIGN_LEFT, IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_LEFT, align_group_id); - AddRadioItemWithStringId(MENU_ALIGN_BOTTOM, - IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_BOTTOM, - align_group_id); - AddRadioItemWithStringId( - MENU_ALIGN_RIGHT, IDS_ASH_SHELF_CONTEXT_MENU_ALIGN_RIGHT, align_group_id); -} - -ShelfAlignmentMenu::~ShelfAlignmentMenu() {} - -bool ShelfAlignmentMenu::IsCommandIdChecked(int command_id) const { - switch (wm_shelf_->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - return command_id == MENU_ALIGN_BOTTOM; - case SHELF_ALIGNMENT_LEFT: - return command_id == MENU_ALIGN_LEFT; - case SHELF_ALIGNMENT_RIGHT: - return command_id == MENU_ALIGN_RIGHT; - } - return false; -} - -bool ShelfAlignmentMenu::IsCommandIdEnabled(int command_id) const { - return true; -} - -void ShelfAlignmentMenu::ExecuteCommand(int command_id, int event_flags) { - WmShell* shell = WmShell::Get(); - switch (static_cast<MenuItem>(command_id)) { - case MENU_ALIGN_LEFT: - shell->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_LEFT); - wm_shelf_->SetAlignment(SHELF_ALIGNMENT_LEFT); - break; - case MENU_ALIGN_BOTTOM: - shell->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_BOTTOM); - wm_shelf_->SetAlignment(SHELF_ALIGNMENT_BOTTOM); - break; - case MENU_ALIGN_RIGHT: - shell->RecordUserMetricsAction(UMA_SHELF_ALIGNMENT_SET_RIGHT); - wm_shelf_->SetAlignment(SHELF_ALIGNMENT_RIGHT); - break; - } -} - -} // namespace ash
diff --git a/ash/shelf/shelf_alignment_menu.h b/ash/shelf/shelf_alignment_menu.h deleted file mode 100644 index ddbdcda..0000000 --- a/ash/shelf/shelf_alignment_menu.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_ALIGNMENT_MENU_H_ -#define ASH_SHELF_SHELF_ALIGNMENT_MENU_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/base/models/simple_menu_model.h" - -namespace ash { - -class WmShelf; - -// Submenu for choosing the alignment of the shelf. -class ASH_EXPORT ShelfAlignmentMenu : public ui::SimpleMenuModel, - public ui::SimpleMenuModel::Delegate { - public: - explicit ShelfAlignmentMenu(WmShelf* wm_shelf); - ~ShelfAlignmentMenu() override; - - // ui::SimpleMenuModel::Delegate overrides: - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - void ExecuteCommand(int command_id, int event_flags) override; - - private: - enum MenuItem { - // Offset so as not to interfere with other menus. - MENU_ALIGN_LEFT = 500, - MENU_ALIGN_RIGHT, - MENU_ALIGN_BOTTOM, - }; - - WmShelf* wm_shelf_; - - DISALLOW_COPY_AND_ASSIGN(ShelfAlignmentMenu); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_ALIGNMENT_MENU_H_
diff --git a/ash/shelf/shelf_application_menu_model.cc b/ash/shelf/shelf_application_menu_model.cc deleted file mode 100644 index 672c6a8..0000000 --- a/ash/shelf/shelf_application_menu_model.cc +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_application_menu_model.h" - -#include <stddef.h> - -#include <limits> -#include <utility> - -#include "ash/public/cpp/shelf_application_menu_item.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "base/metrics/histogram_macros.h" - -namespace { - -const int kInvalidCommandId = std::numeric_limits<int>::max(); - -} // namespace - -namespace ash { - -ShelfApplicationMenuModel::ShelfApplicationMenuModel( - const base::string16& title, - ShelfAppMenuItemList items, - ShelfItemDelegate* delegate) - : ui::SimpleMenuModel(this), items_(std::move(items)), delegate_(delegate) { - AddSeparator(ui::SPACING_SEPARATOR); - AddItem(kInvalidCommandId, title); - AddSeparator(ui::SPACING_SEPARATOR); - - for (size_t i = 0; i < items_.size(); i++) { - ShelfApplicationMenuItem* item = items_[i].get(); - AddItem(i, item->title()); - if (!item->icon().IsEmpty()) - SetIcon(GetIndexOfCommandId(i), item->icon()); - } - - // SimpleMenuModel does not allow two consecutive spacing separator items. - // This only occurs in tests; users should not see menus with no |items_|. - if (!items_.empty()) - AddSeparator(ui::SPACING_SEPARATOR); -} - -ShelfApplicationMenuModel::~ShelfApplicationMenuModel() {} - -bool ShelfApplicationMenuModel::IsCommandIdChecked(int command_id) const { - return false; -} - -bool ShelfApplicationMenuModel::IsCommandIdEnabled(int command_id) const { - return command_id >= 0 && static_cast<size_t>(command_id) < items_.size(); -} - -void ShelfApplicationMenuModel::ExecuteCommand(int command_id, - int event_flags) { - DCHECK(delegate_); - DCHECK(IsCommandIdEnabled(command_id)); - // Have the delegate execute its own custom command id for the given item. - delegate_->ExecuteCommand(items_[command_id]->command_id(), event_flags); - RecordMenuItemSelectedMetrics(command_id, items_.size()); -} - -void ShelfApplicationMenuModel::RecordMenuItemSelectedMetrics( - int command_id, - int num_menu_items_enabled) { - UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Menu.SelectedMenuItemIndex", command_id); - UMA_HISTOGRAM_COUNTS_100("Ash.Shelf.Menu.NumItemsEnabledUponSelection", - num_menu_items_enabled); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_application_menu_model.h b/ash/shelf/shelf_application_menu_model.h deleted file mode 100644 index 2093ddd7..0000000 --- a/ash/shelf/shelf_application_menu_model.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_APPLICATION_MENU_MODEL_H_ -#define ASH_SHELF_SHELF_APPLICATION_MENU_MODEL_H_ - -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_application_menu_item.h" -#include "base/macros.h" -#include "ui/base/models/simple_menu_model.h" - -namespace ash { - -class ShelfApplicationMenuModelTestAPI; -class ShelfItemDelegate; - -// A menu model listing open applications associated with a shelf item. Layout: -// +---------------------------+ -// | | -// | App Title | -// | | -// | [Icon] Item Title | -// | [Icon] Item Title | -// | | -// +---------------------------+ -class ASH_EXPORT ShelfApplicationMenuModel - : public ui::SimpleMenuModel, - public ui::SimpleMenuModel::Delegate { - public: - // Makes a menu with a |title|, separators, and |items| for |delegate|. - // |delegate| may be null in unit tests that do not execute commands. - ShelfApplicationMenuModel(const base::string16& title, - ShelfAppMenuItemList items, - ShelfItemDelegate* delegate); - ~ShelfApplicationMenuModel() override; - - // ui::SimpleMenuModel::Delegate: - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - void ExecuteCommand(int command_id, int event_flags) override; - - private: - friend class ShelfApplicationMenuModelTestAPI; - - // Records UMA metrics when a menu item is selected. - void RecordMenuItemSelectedMetrics(int command_id, - int num_menu_items_enabled); - - // The list of menu items as returned from the shelf item's controller. - ShelfAppMenuItemList items_; - - // The shelf item delegate that created the menu and executes its commands. - ShelfItemDelegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModel); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_APPLICATION_MENU_MODEL_H_
diff --git a/ash/shelf/shelf_application_menu_model_unittest.cc b/ash/shelf/shelf_application_menu_model_unittest.cc deleted file mode 100644 index b2b7c0e..0000000 --- a/ash/shelf/shelf_application_menu_model_unittest.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_application_menu_model.h" - -#include <utility> - -#include "ash/public/cpp/shelf_application_menu_item.h" -#include "ash/test/test_shelf_item_delegate.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/histogram_tester.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace ash { - -namespace { - -const char kNumItemsEnabledHistogramName[] = - "Ash.Shelf.Menu.NumItemsEnabledUponSelection"; - -const char kSelectedMenuItemIndexHistogramName[] = - "Ash.Shelf.Menu.SelectedMenuItemIndex"; - -} // namespace - -// Test API to provide internal access to a ShelfApplicationMenuModel. -class ShelfApplicationMenuModelTestAPI { - public: - // Creates a test api to access the internals of the |menu|. - explicit ShelfApplicationMenuModelTestAPI(ShelfApplicationMenuModel* menu) - : menu_(menu) {} - ~ShelfApplicationMenuModelTestAPI() {} - - // Give public access to this metrics recording functions. - void RecordMenuItemSelectedMetrics(int command_id, - int num_menu_items_enabled) { - menu_->RecordMenuItemSelectedMetrics(command_id, num_menu_items_enabled); - } - - private: - // The ShelfApplicationMenuModel to provide internal access to. Not owned. - ShelfApplicationMenuModel* menu_; - - DISALLOW_COPY_AND_ASSIGN(ShelfApplicationMenuModelTestAPI); -}; - -// Verifies the menu contents given an empty item list. -TEST(ShelfApplicationMenuModelTest, VerifyContentsWithNoMenuItems) { - base::string16 title = base::ASCIIToUTF16("title"); - ShelfApplicationMenuModel menu(title, ShelfAppMenuItemList(), nullptr); - // Expect the title with separators. - ASSERT_EQ(static_cast<int>(3), menu.GetItemCount()); - EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0)); - EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(1)); - EXPECT_EQ(title, menu.GetLabelAt(1)); - EXPECT_FALSE(menu.IsEnabledAt(1)); - EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(2)); -} - -// Verifies the menu contents given a non-empty item list. -TEST(ShelfApplicationMenuModelTest, VerifyContentsWithMenuItems) { - ShelfAppMenuItemList items; - base::string16 title1 = base::ASCIIToUTF16("title1"); - base::string16 title2 = base::ASCIIToUTF16("title2"); - base::string16 title3 = base::ASCIIToUTF16("title3"); - items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title1)); - items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(1, title2)); - items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(2, title3)); - - base::string16 title = base::ASCIIToUTF16("title"); - ShelfApplicationMenuModel menu(title, std::move(items), nullptr); - ShelfApplicationMenuModelTestAPI menu_test_api(&menu); - - // Expect the title with separators, the enabled items, and another separator. - ASSERT_EQ(static_cast<int>(7), menu.GetItemCount()); - EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(0)); - EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(1)); - EXPECT_EQ(title, menu.GetLabelAt(1)); - EXPECT_FALSE(menu.IsEnabledAt(1)); - EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(2)); - EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(3)); - EXPECT_EQ(title1, menu.GetLabelAt(3)); - EXPECT_TRUE(menu.IsEnabledAt(3)); - EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(4)); - EXPECT_EQ(title2, menu.GetLabelAt(4)); - EXPECT_TRUE(menu.IsEnabledAt(4)); - EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(5)); - EXPECT_EQ(title3, menu.GetLabelAt(5)); - EXPECT_TRUE(menu.IsEnabledAt(5)); - EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, menu.GetTypeAt(6)); -} - -// Verifies RecordMenuItemSelectedMetrics uses the correct histogram buckets. -TEST(ShelfApplicationMenuModelTest, VerifyHistogramBuckets) { - const int kCommandId = 3; - const int kNumMenuItemsEnabled = 7; - - base::HistogramTester histogram_tester; - - ShelfAppMenuItemList items; - ShelfApplicationMenuModel menu(base::ASCIIToUTF16("title"), std::move(items), - nullptr); - ShelfApplicationMenuModelTestAPI menu_test_api(&menu); - menu_test_api.RecordMenuItemSelectedMetrics(kCommandId, kNumMenuItemsEnabled); - - histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); - histogram_tester.ExpectBucketCount(kNumItemsEnabledHistogramName, - kNumMenuItemsEnabled, 1); - - histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); - histogram_tester.ExpectBucketCount(kSelectedMenuItemIndexHistogramName, - kCommandId, 1); -} - -// Verify histogram data is recorded when ExecuteCommand is called. -TEST(ShelfApplicationMenuModelTest, VerifyHistogramOnExecute) { - base::HistogramTester histogram_tester; - - ShelfAppMenuItemList items; - base::string16 title = base::ASCIIToUTF16("title"); - items.push_back(base::MakeUnique<ShelfApplicationMenuItem>(0, title)); - test::TestShelfItemDelegate test_delegate(nullptr); - ShelfApplicationMenuModel menu(title, std::move(items), &test_delegate); - menu.ExecuteCommand(0, 0); - - histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1); - histogram_tester.ExpectTotalCount(kSelectedMenuItemIndexHistogramName, 1); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_background_animator.cc b/ash/shelf/shelf_background_animator.cc deleted file mode 100644 index 00b3347c..0000000 --- a/ash/shelf/shelf_background_animator.cc +++ /dev/null
@@ -1,245 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_background_animator.h" - -#include <algorithm> - -#include "ash/animation/animation_change_type.h" -#include "ash/common/wallpaper/wallpaper_controller.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/color_utils.h" - -namespace ash { - -ShelfBackgroundAnimator::AnimationValues::AnimationValues() {} - -ShelfBackgroundAnimator::AnimationValues::~AnimationValues() {} - -void ShelfBackgroundAnimator::AnimationValues::UpdateCurrentValues(double t) { - current_color_ = - gfx::Tween::ColorValueBetween(t, initial_color_, target_color_); -} - -void ShelfBackgroundAnimator::AnimationValues::SetTargetValues( - SkColor target_color) { - initial_color_ = current_color_; - target_color_ = target_color; -} - -bool ShelfBackgroundAnimator::AnimationValues::InitialValuesEqualTargetValuesOf( - const AnimationValues& other) const { - return initial_color_ == other.target_color_; -} - -ShelfBackgroundAnimator::ShelfBackgroundAnimator( - ShelfBackgroundType background_type, - WmShelf* wm_shelf, - WallpaperController* wallpaper_controller) - : wm_shelf_(wm_shelf), wallpaper_controller_(wallpaper_controller) { - if (wallpaper_controller_) - wallpaper_controller_->AddObserver(this); - if (wm_shelf_) - wm_shelf_->AddObserver(this); - - // Initialize animators so that adding observers get notified with consistent - // values. - AnimateBackground(background_type, AnimationChangeType::IMMEDIATE); -} - -ShelfBackgroundAnimator::~ShelfBackgroundAnimator() { - if (wallpaper_controller_) - wallpaper_controller_->RemoveObserver(this); - if (wm_shelf_) - wm_shelf_->RemoveObserver(this); -} - -void ShelfBackgroundAnimator::AddObserver( - ShelfBackgroundAnimatorObserver* observer) { - observers_.AddObserver(observer); - NotifyObserver(observer); -} - -void ShelfBackgroundAnimator::RemoveObserver( - ShelfBackgroundAnimatorObserver* observer) { - observers_.RemoveObserver(observer); -} - -void ShelfBackgroundAnimator::NotifyObserver( - ShelfBackgroundAnimatorObserver* observer) { - observer->UpdateShelfBackground(shelf_background_values_.current_color()); - observer->UpdateShelfItemBackground(item_background_values_.current_color()); -} - -void ShelfBackgroundAnimator::PaintBackground( - ShelfBackgroundType background_type, - AnimationChangeType change_type) { - if (target_background_type_ == background_type && - change_type == AnimationChangeType::ANIMATE) { - return; - } - - AnimateBackground(background_type, change_type); -} - -void ShelfBackgroundAnimator::AnimationProgressed( - const gfx::Animation* animation) { - DCHECK_EQ(animation, animator_.get()); - SetAnimationValues(animation->GetCurrentValue()); -} - -void ShelfBackgroundAnimator::AnimationEnded(const gfx::Animation* animation) { - DCHECK_EQ(animation, animator_.get()); - SetAnimationValues(animation->GetCurrentValue()); - animator_.reset(); -} - -void ShelfBackgroundAnimator::AnimationCanceled( - const gfx::Animation* animation) { - DCHECK_EQ(animation, animator_.get()); - SetAnimationValues(animator_->IsShowing() ? 1.0 : 0.0); - // Animations are only cancelled when they are being pre-empted so we don't - // destroy the |animator_| because it may be re-used immediately. -} - -void ShelfBackgroundAnimator::OnWallpaperDataChanged() {} - -void ShelfBackgroundAnimator::OnWallpaperColorsChanged() { - AnimateBackground(target_background_type_, AnimationChangeType::ANIMATE); -} - -void ShelfBackgroundAnimator::OnBackgroundTypeChanged( - ShelfBackgroundType background_type, - AnimationChangeType change_type) { - PaintBackground(background_type, change_type); -} - -void ShelfBackgroundAnimator::NotifyObservers() { - for (auto& observer : observers_) - NotifyObserver(&observer); -} - -void ShelfBackgroundAnimator::AnimateBackground( - ShelfBackgroundType background_type, - AnimationChangeType change_type) { - StopAnimator(); - - if (change_type == AnimationChangeType::IMMEDIATE) { - animator_.reset(); - SetTargetValues(background_type); - SetAnimationValues(1.0); - } else if (CanReuseAnimator(background_type)) { - // |animator_| should not be null here as CanReuseAnimator() returns false - // when it is null. - if (animator_->IsShowing()) - animator_->Hide(); - else - animator_->Show(); - } else { - CreateAnimator(background_type); - SetTargetValues(background_type); - animator_->Show(); - } - - if (target_background_type_ != background_type) { - previous_background_type_ = target_background_type_; - target_background_type_ = background_type; - } -} - -bool ShelfBackgroundAnimator::CanReuseAnimator( - ShelfBackgroundType background_type) const { - if (!animator_) - return false; - - AnimationValues target_shelf_background_values; - AnimationValues target_item_background_values; - GetTargetValues(background_type, &target_shelf_background_values, - &target_item_background_values); - - return previous_background_type_ == background_type && - shelf_background_values_.InitialValuesEqualTargetValuesOf( - target_shelf_background_values) && - item_background_values_.InitialValuesEqualTargetValuesOf( - target_item_background_values); -} - -void ShelfBackgroundAnimator::CreateAnimator( - ShelfBackgroundType background_type) { - int duration_ms = 0; - - switch (background_type) { - case SHELF_BACKGROUND_DEFAULT: - duration_ms = 500; - break; - case SHELF_BACKGROUND_OVERLAP: - duration_ms = 500; - break; - case SHELF_BACKGROUND_MAXIMIZED: - duration_ms = 250; - break; - } - - animator_.reset(new gfx::SlideAnimation(this)); - animator_->SetSlideDuration(duration_ms); -} - -void ShelfBackgroundAnimator::StopAnimator() { - if (animator_) - animator_->Stop(); -} - -void ShelfBackgroundAnimator::SetTargetValues( - ShelfBackgroundType background_type) { - GetTargetValues(background_type, &shelf_background_values_, - &item_background_values_); -} - -void ShelfBackgroundAnimator::GetTargetValues( - ShelfBackgroundType background_type, - AnimationValues* shelf_background_values, - AnimationValues* item_background_values) const { - int target_shelf_background_alpha = 0; - int target_shelf_item_background_alpha = 0; - - switch (background_type) { - case SHELF_BACKGROUND_DEFAULT: - target_shelf_background_alpha = 0; - target_shelf_item_background_alpha = kShelfTranslucentAlpha; - break; - case SHELF_BACKGROUND_OVERLAP: - target_shelf_background_alpha = kShelfTranslucentAlpha; - target_shelf_item_background_alpha = 0; - break; - case SHELF_BACKGROUND_MAXIMIZED: - target_shelf_background_alpha = kMaxAlpha; - target_shelf_item_background_alpha = 0; - break; - } - - SkColor target_color = wallpaper_controller_ - ? wallpaper_controller_->prominent_color() - : kShelfDefaultBaseColor; - - if (target_color == SK_ColorTRANSPARENT) - target_color = kShelfDefaultBaseColor; - - shelf_background_values->SetTargetValues( - SkColorSetA(target_color, target_shelf_background_alpha)); - item_background_values->SetTargetValues( - SkColorSetA(target_color, target_shelf_item_background_alpha)); -} - -void ShelfBackgroundAnimator::SetAnimationValues(double t) { - DCHECK_GE(t, 0.0); - DCHECK_LE(t, 1.0); - shelf_background_values_.UpdateCurrentValues(t); - item_background_values_.UpdateCurrentValues(t); - NotifyObservers(); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_background_animator.h b/ash/shelf/shelf_background_animator.h deleted file mode 100644 index a12fe842..0000000 --- a/ash/shelf/shelf_background_animator.h +++ /dev/null
@@ -1,187 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_BACKGROUND_ANIMATOR_H_ -#define ASH_SHELF_SHELF_BACKGROUND_ANIMATOR_H_ - -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/common/wallpaper/wallpaper_controller_observer.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf_observer.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/animation/animation_delegate.h" - -namespace gfx { -class SlideAnimation; -} // namespace gfx - -namespace ash { - -enum class AnimationChangeType; -class ShelfBackgroundAnimatorObserver; -class ShelfBackgroundAnimatorTestApi; -class WallpaperController; -class WmShelf; - -// Central controller for the Shelf and Dock opacity animations. -// -// The ShelfBackgroundAnimator is capable of observing a WmShelf instance for -// background type changes or clients can call PaintBackground() directly. -// -// The Shelf uses 2 surfaces for the animations: -// -// Material Design: -// 1. Shelf button backgrounds -// 2. Overlay for the SHELF_BACKGROUND_OVERLAP and SHELF_BACKGROUND_MAXIMIZED -// states. -class ASH_EXPORT ShelfBackgroundAnimator : public WmShelfObserver, - public gfx::AnimationDelegate, - public WallpaperControllerObserver { - public: - // The maximum alpha value that can be used. - static const int kMaxAlpha = SK_AlphaOPAQUE; - - // Initializes this with the given |background_type|. This will observe the - // |wm_shelf| for background type changes and the |wallpaper_controller| for - // wallpaper changes if not null. - ShelfBackgroundAnimator(ShelfBackgroundType background_type, - WmShelf* wm_shelf, - WallpaperController* wallpaper_controller); - ~ShelfBackgroundAnimator() override; - - ShelfBackgroundType target_background_type() const { - return target_background_type_; - } - - // Initializes |observer| with current values using the Initialize() function. - void AddObserver(ShelfBackgroundAnimatorObserver* observer); - void RemoveObserver(ShelfBackgroundAnimatorObserver* observer); - - // Updates |observer| with current values. - void NotifyObserver(ShelfBackgroundAnimatorObserver* observer); - - // Conditionally animates the background to the specified |background_type| - // and notifies observers of the new background parameters (e.g. color). - // If |change_type| is BACKGROUND_CHANGE_IMMEDIATE then the - // observers will only receive one notification with the final background - // state, otherwise the observers will be notified multiple times in order to - // animate the changes to the backgrounds. - // - // NOTE: If a second request to paint the same |background_type| using the - // BACKGROUND_CHANGE_ANIMATE change type is received it will be ignored and - // observers will NOT be notified. - void PaintBackground(ShelfBackgroundType background_type, - AnimationChangeType change_type); - - // gfx::AnimationDelegate: - void AnimationProgressed(const gfx::Animation* animation) override; - void AnimationEnded(const gfx::Animation* animation) override; - void AnimationCanceled(const gfx::Animation* animation) override; - - protected: - // WmShelfObserver: - void OnBackgroundTypeChanged(ShelfBackgroundType background_type, - AnimationChangeType change_type) override; - - // WallpaperControllerObserver: - void OnWallpaperDataChanged() override; - void OnWallpaperColorsChanged() override; - - private: - friend class ShelfBackgroundAnimatorTestApi; - - // Track the values related to a single animation (e.g. Shelf background, - // shelf item background) - class AnimationValues { - public: - AnimationValues(); - ~AnimationValues(); - - SkColor current_color() const { return current_color_; } - SkColor target_color() const { return target_color_; } - - // Updates the |current_color_| based on |t| value between 0 and 1. - void UpdateCurrentValues(double t); - - // Set the target color and assign the current color to the initial color. - void SetTargetValues(SkColor target_color); - - // Returns true if the initial values of |this| equal the target values of - // |other|. - bool InitialValuesEqualTargetValuesOf(const AnimationValues& other) const; - - private: - SkColor initial_color_ = SK_ColorTRANSPARENT; - SkColor current_color_ = SK_ColorTRANSPARENT; - SkColor target_color_ = SK_ColorTRANSPARENT; - - DISALLOW_COPY_AND_ASSIGN(AnimationValues); - }; - - // Helper function used by PaintBackground() to animate the background. - void AnimateBackground(ShelfBackgroundType background_type, - AnimationChangeType change_type); - - // Returns true if the current |animator_| should be re-used to animate to the - // given |background_type|. This allows for pre-empted animations to take the - // same amount of time to reverse to the |previous_background_type_|. - bool CanReuseAnimator(ShelfBackgroundType background_type) const; - - // Creates a new |animator_| configured with the correct duration. If the - // |animator_| is currently animating it will be stopped. - void CreateAnimator(ShelfBackgroundType background_type); - - // Stops the animator owned by this. - void StopAnimator(); - - // Updates the |shelf_background_values_| and |shelf_item_background_values_|. - void SetTargetValues(ShelfBackgroundType background_type); - - // Sets the target values for |shelf_background_values| and - // |item_background_values| according to |background_type|. - void GetTargetValues(ShelfBackgroundType background_type, - AnimationValues* shelf_background_values, - AnimationValues* item_background_values) const; - - // Updates the animation values corresponding to the |t| value between 0 and - // 1. - void SetAnimationValues(double t); - - // Called when observers need to be notified. - void NotifyObservers(); - - // The shelf to observe for changes to the shelf background type, can be null. - WmShelf* wm_shelf_; - - // The wallpaper controller to observe for changes and to extract colors from. - WallpaperController* wallpaper_controller_; - - // The background type that this is animating towards or has reached. - ShelfBackgroundType target_background_type_ = SHELF_BACKGROUND_DEFAULT; - - // The last background type this is animating away from. - ShelfBackgroundType previous_background_type_ = SHELF_BACKGROUND_MAXIMIZED; - - // Drives the animtion. - std::unique_ptr<gfx::SlideAnimation> animator_; - - // Tracks the shelf background animation values. - AnimationValues shelf_background_values_; - - // Tracks the item background animation values. - AnimationValues item_background_values_; - - base::ObserverList<ShelfBackgroundAnimatorObserver> observers_; - - DISALLOW_COPY_AND_ASSIGN(ShelfBackgroundAnimator); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_BACKGROUND_ANIMATOR_H_
diff --git a/ash/shelf/shelf_background_animator_observer.h b/ash/shelf/shelf_background_animator_observer.h deleted file mode 100644 index 6c45073..0000000 --- a/ash/shelf/shelf_background_animator_observer.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_BACKGROUND_ANIMATOR_OBSERVER_H_ -#define ASH_SHELF_SHELF_BACKGROUND_ANIMATOR_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "third_party/skia/include/core/SkColor.h" - -namespace ash { - -// Observer for the ShelfBackgroundAnimator class. -class ASH_EXPORT ShelfBackgroundAnimatorObserver { - public: - // Called when the Shelf's background should be updated. - virtual void UpdateShelfBackground(SkColor color) {} - - // Called when the Shelf item (aka button) backgrounds should be updated. - virtual void UpdateShelfItemBackground(SkColor color) {} - - protected: - virtual ~ShelfBackgroundAnimatorObserver() {} -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_BACKGROUND_ANIMATOR_OBSERVER_H_
diff --git a/ash/shelf/shelf_background_animator_unittest.cc b/ash/shelf/shelf_background_animator_unittest.cc deleted file mode 100644 index 5431ca6a..0000000 --- a/ash/shelf/shelf_background_animator_unittest.cc +++ /dev/null
@@ -1,305 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_background_animator.h" - -#include <memory> - -#include "ash/animation/animation_change_type.h" -#include "ash/common/wallpaper/wallpaper_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "ash/shelf/shelf_constants.h" -#include "base/bind.h" -#include "base/macros.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/animation/slide_animation.h" - -namespace ash { -namespace { - -static auto kMaxAlpha = ShelfBackgroundAnimator::kMaxAlpha; - -// A valid color value that is distinct from any final animation state values. -// Used to check if color values are changed during animations. -const SkColor kDummyColor = SK_ColorBLUE; - -// Observer that caches color values for the last observation. -class TestShelfBackgroundObserver : public ShelfBackgroundAnimatorObserver { - public: - TestShelfBackgroundObserver() {} - ~TestShelfBackgroundObserver() override {} - - SkColor background_color() const { return background_color_; } - - // Convenience function to get the alpha value from |background_color_|. - int GetBackgroundAlpha() const; - - SkColor item_background_color() const { return item_background_color_; } - - // Convenience function to get the alpha value from |item_background_color_|. - int GetItemBackgroundAlpha() const; - - // ShelfBackgroundObserver: - void UpdateShelfBackground(SkColor color) override; - void UpdateShelfItemBackground(SkColor color) override; - - private: - int background_color_ = SK_ColorTRANSPARENT; - int item_background_color_ = SK_ColorTRANSPARENT; - - DISALLOW_COPY_AND_ASSIGN(TestShelfBackgroundObserver); -}; - -int TestShelfBackgroundObserver::GetBackgroundAlpha() const { - return SkColorGetA(background_color_); -} - -int TestShelfBackgroundObserver::GetItemBackgroundAlpha() const { - return SkColorGetA(item_background_color_); -} - -void TestShelfBackgroundObserver::UpdateShelfBackground(SkColor color) { - background_color_ = color; -} - -void TestShelfBackgroundObserver::UpdateShelfItemBackground(SkColor color) { - item_background_color_ = color; -} - -} // namespace - -// Provides internal access to a ShelfBackgroundAnimator instance. -class ShelfBackgroundAnimatorTestApi { - public: - explicit ShelfBackgroundAnimatorTestApi(ShelfBackgroundAnimator* animator) - : animator_(animator) {} - - ~ShelfBackgroundAnimatorTestApi() {} - - ShelfBackgroundType previous_background_type() const { - return animator_->previous_background_type_; - } - - gfx::SlideAnimation* animator() const { return animator_->animator_.get(); } - - private: - // The instance to provide internal access to. - ShelfBackgroundAnimator* animator_; - - DISALLOW_COPY_AND_ASSIGN(ShelfBackgroundAnimatorTestApi); -}; - -class ShelfBackgroundAnimatorTest : public testing::Test { - public: - ShelfBackgroundAnimatorTest() {} - ~ShelfBackgroundAnimatorTest() override {} - - // testing::Test: - void SetUp() override; - - protected: - // Convenience wrapper for |animator_|'s PaintBackground(). - void PaintBackground( - ShelfBackgroundType background_type, - AnimationChangeType change_type = AnimationChangeType::IMMEDIATE); - - // Set all of the color values for the |observer_|. - void SetColorValuesOnObserver(SkColor color); - - // Completes all the animations. - void CompleteAnimations(); - - TestShelfBackgroundObserver observer_; - - // Test target. - std::unique_ptr<ShelfBackgroundAnimator> animator_; - - // Provides internal access to |animator_|. - std::unique_ptr<ShelfBackgroundAnimatorTestApi> test_api_; - - // Used to control the animations. - scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; - - private: - std::unique_ptr<base::ThreadTaskRunnerHandle> task_runner_handle_; - - DISALLOW_COPY_AND_ASSIGN(ShelfBackgroundAnimatorTest); -}; - -void ShelfBackgroundAnimatorTest::SetUp() { - task_runner_ = new base::TestMockTimeTaskRunner(); - task_runner_handle_.reset(new base::ThreadTaskRunnerHandle(task_runner_)); - - animator_.reset( - new ShelfBackgroundAnimator(SHELF_BACKGROUND_DEFAULT, nullptr, nullptr)); - animator_->AddObserver(&observer_); - - test_api_.reset(new ShelfBackgroundAnimatorTestApi(animator_.get())); -} - -void ShelfBackgroundAnimatorTest::PaintBackground( - ShelfBackgroundType background_type, - AnimationChangeType change_type) { - animator_->PaintBackground(background_type, change_type); -} - -void ShelfBackgroundAnimatorTest::SetColorValuesOnObserver(SkColor color) { - observer_.UpdateShelfBackground(color); - observer_.UpdateShelfItemBackground(color); -} - -void ShelfBackgroundAnimatorTest::CompleteAnimations() { - task_runner_->FastForwardUntilNoTasksRemain(); -} - -// Verify the |previous_background_type_| and |target_background_type_| values -// when animating to the same target type multiple times. -TEST_F(ShelfBackgroundAnimatorTest, BackgroundTypesWhenAnimatingToSameTarget) { - PaintBackground(SHELF_BACKGROUND_MAXIMIZED); - EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, animator_->target_background_type()); - - PaintBackground(SHELF_BACKGROUND_DEFAULT); - EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, animator_->target_background_type()); - EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, test_api_->previous_background_type()); - - PaintBackground(SHELF_BACKGROUND_DEFAULT); - EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, animator_->target_background_type()); - EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, test_api_->previous_background_type()); -} - -// Verify subsequent calls to PaintBackground() using the -// AnimationChangeType::ANIMATE change type are ignored. -TEST_F(ShelfBackgroundAnimatorTest, - MultipleAnimateCallsToSameTargetAreIgnored) { - PaintBackground(SHELF_BACKGROUND_MAXIMIZED); - SetColorValuesOnObserver(kDummyColor); - animator_->PaintBackground(SHELF_BACKGROUND_DEFAULT, - AnimationChangeType::ANIMATE); - CompleteAnimations(); - - EXPECT_NE(observer_.background_color(), kDummyColor); - EXPECT_NE(observer_.item_background_color(), kDummyColor); - - SetColorValuesOnObserver(kDummyColor); - animator_->PaintBackground(SHELF_BACKGROUND_DEFAULT, - AnimationChangeType::ANIMATE); - CompleteAnimations(); - - EXPECT_EQ(observer_.background_color(), kDummyColor); - EXPECT_EQ(observer_.item_background_color(), kDummyColor); -} - -// Verify observers are updated with the current values when they are added. -TEST_F(ShelfBackgroundAnimatorTest, ObserversUpdatedWhenAdded) { - animator_->RemoveObserver(&observer_); - SetColorValuesOnObserver(kDummyColor); - - animator_->AddObserver(&observer_); - - EXPECT_NE(observer_.background_color(), kDummyColor); - EXPECT_NE(observer_.item_background_color(), kDummyColor); -} - -// Verify the alpha values for the SHELF_BACKGROUND_DEFAULT state. -TEST_F(ShelfBackgroundAnimatorTest, DefaultBackground) { - PaintBackground(SHELF_BACKGROUND_DEFAULT); - - EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, animator_->target_background_type()); - EXPECT_EQ(0, observer_.GetBackgroundAlpha()); - EXPECT_EQ(kShelfTranslucentAlpha, observer_.GetItemBackgroundAlpha()); -} - -// Verify the alpha values for the SHELF_BACKGROUND_OVERLAP state. -TEST_F(ShelfBackgroundAnimatorTest, OverlapBackground) { - PaintBackground(SHELF_BACKGROUND_OVERLAP); - - EXPECT_EQ(SHELF_BACKGROUND_OVERLAP, animator_->target_background_type()); - EXPECT_EQ(kShelfTranslucentAlpha, observer_.GetBackgroundAlpha()); - EXPECT_EQ(0, observer_.GetItemBackgroundAlpha()); -} - -// Verify the alpha values for the SHELF_BACKGROUND_MAXIMIZED state. -TEST_F(ShelfBackgroundAnimatorTest, MaximizedBackground) { - PaintBackground(SHELF_BACKGROUND_MAXIMIZED); - - EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, animator_->target_background_type()); - EXPECT_EQ(kMaxAlpha, observer_.GetBackgroundAlpha()); - EXPECT_EQ(0, observer_.GetItemBackgroundAlpha()); -} - -TEST_F(ShelfBackgroundAnimatorTest, - AnimatorIsDetroyedWhenCompletingSuccessfully) { - PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); - EXPECT_TRUE(test_api_->animator()); - CompleteAnimations(); - EXPECT_FALSE(test_api_->animator()); -} - -TEST_F(ShelfBackgroundAnimatorTest, - AnimatorDestroyedWhenChangingBackgroundImmediately) { - PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); - EXPECT_TRUE(test_api_->animator()); - - PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::IMMEDIATE); - EXPECT_FALSE(test_api_->animator()); -} - -// Verify that existing animator is used when animating to the previous state. -TEST_F(ShelfBackgroundAnimatorTest, - ExistingAnimatorIsReusedWhenAnimatingToPreviousState) { - PaintBackground(SHELF_BACKGROUND_DEFAULT, AnimationChangeType::ANIMATE); - PaintBackground(SHELF_BACKGROUND_MAXIMIZED, AnimationChangeType::ANIMATE); - - const gfx::SlideAnimation* animator = test_api_->animator(); - EXPECT_TRUE(animator); - - PaintBackground(SHELF_BACKGROUND_DEFAULT, AnimationChangeType::ANIMATE); - - EXPECT_EQ(animator, test_api_->animator()); -} - -// Verify that existing animator is not re-used when the target background isn't -// the same as the previous background. -TEST_F(ShelfBackgroundAnimatorTest, - ExistingAnimatorNotReusedWhenTargetBackgroundNotPreviousBackground) { - PaintBackground(SHELF_BACKGROUND_DEFAULT, AnimationChangeType::ANIMATE); - PaintBackground(SHELF_BACKGROUND_MAXIMIZED, AnimationChangeType::ANIMATE); - - const gfx::SlideAnimation* animator = test_api_->animator(); - EXPECT_TRUE(animator); - - EXPECT_NE(SHELF_BACKGROUND_OVERLAP, test_api_->previous_background_type()); - PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); - - EXPECT_NE(animator, test_api_->animator()); -} - -TEST_F(ShelfBackgroundAnimatorTest, - AnimationProgressesToTargetWhenStoppingUnfinishedAnimator) { - PaintBackground(SHELF_BACKGROUND_OVERLAP, AnimationChangeType::ANIMATE); - - EXPECT_NE(kShelfTranslucentAlpha, observer_.GetBackgroundAlpha()); - EXPECT_NE(0, observer_.GetItemBackgroundAlpha()); - - test_api_->animator()->Stop(); - - EXPECT_EQ(kShelfTranslucentAlpha, observer_.GetBackgroundAlpha()); - EXPECT_EQ(0, observer_.GetItemBackgroundAlpha()); -} - -// Verify observers are always notified, even when alpha values don't change. -TEST_F(ShelfBackgroundAnimatorTest, - ObserversAreNotifiedWhenSnappingToSameTargetBackground) { - PaintBackground(SHELF_BACKGROUND_DEFAULT); - SetColorValuesOnObserver(kDummyColor); - PaintBackground(SHELF_BACKGROUND_DEFAULT); - - EXPECT_NE(observer_.background_color(), kDummyColor); - EXPECT_NE(observer_.item_background_color(), kDummyColor); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_bezel_event_handler.cc b/ash/shelf/shelf_bezel_event_handler.cc index fa2b5f97..da40409 100644 --- a/ash/shelf/shelf_bezel_event_handler.cc +++ b/ash/shelf/shelf_bezel_event_handler.cc
@@ -4,7 +4,7 @@ #include "ash/shelf/shelf_bezel_event_handler.h" -#include "ash/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/shell.h" #include "ui/aura/window.h" #include "ui/display/display.h"
diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc deleted file mode 100644 index bcd86583..0000000 --- a/ash/shelf/shelf_button.cc +++ /dev/null
@@ -1,514 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_button.h" - -#include <algorithm> - -#include "ash/common/ash_constants.h" -#include "ash/shelf/ink_drop_button_listener.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "base/memory/ptr_util.h" -#include "base/time/time.h" -#include "skia/ext/image_operations.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/gfx/animation/throb_animation.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/gfx/skbitmap_operations.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/square_ink_drop_ripple.h" -#include "ui/views/controls/image_view.h" - -namespace { - -const int kIconSize = 32; -const int kAttentionThrobDurationMS = 800; -const int kMaxAnimationSeconds = 10; -const int kIndicatorOffsetFromBottom = 3; -const int kIndicatorRadiusDip = 2; -const SkColor kIndicatorColor = SK_ColorWHITE; - -// Shelf item ripple constants. -const int kInkDropSmallSize = 48; -const int kInkDropLargeSize = 60; - -// Padding from the edge of the shelf to the application icon when the shelf -// is horizontally and vertically aligned, respectively. -const int kIconPaddingHorizontal = 7; -const int kIconPaddingVertical = 8; - -// Simple AnimationDelegate that owns a single ThrobAnimation instance to -// keep all Draw Attention animations in sync. -class ShelfButtonAnimation : public gfx::AnimationDelegate { - public: - class Observer { - public: - virtual void AnimationProgressed() = 0; - - protected: - virtual ~Observer() {} - }; - - static ShelfButtonAnimation* GetInstance() { - static ShelfButtonAnimation* s_instance = new ShelfButtonAnimation(); - return s_instance; - } - - void AddObserver(Observer* observer) { observers_.AddObserver(observer); } - - void RemoveObserver(Observer* observer) { - observers_.RemoveObserver(observer); - if (!observers_.might_have_observers()) - animation_.Stop(); - } - - bool HasObserver(Observer* observer) const { - return observers_.HasObserver(observer); - } - - SkAlpha GetAlpha() { - return GetThrobAnimation().CurrentValueBetween(SK_AlphaTRANSPARENT, - SK_AlphaOPAQUE); - } - - double GetAnimation() { return GetThrobAnimation().GetCurrentValue(); } - - private: - ShelfButtonAnimation() : animation_(this) { - animation_.SetThrobDuration(kAttentionThrobDurationMS); - animation_.SetTweenType(gfx::Tween::SMOOTH_IN_OUT); - } - - ~ShelfButtonAnimation() override {} - - gfx::ThrobAnimation& GetThrobAnimation() { - if (!animation_.is_animating()) { - animation_.Reset(); - animation_.StartThrobbing(-1 /*throb indefinitely*/); - } - return animation_; - } - - // gfx::AnimationDelegate - void AnimationProgressed(const gfx::Animation* animation) override { - if (animation != &animation_) - return; - if (!animation_.is_animating()) - return; - for (auto& observer : observers_) - observer.AnimationProgressed(); - } - - gfx::ThrobAnimation animation_; - base::ObserverList<Observer> observers_; - - DISALLOW_COPY_AND_ASSIGN(ShelfButtonAnimation); -}; - -} // namespace - -namespace ash { - -//////////////////////////////////////////////////////////////////////////////// -// ShelfButton::AppStatusIndicatorView - -class ShelfButton::AppStatusIndicatorView - : public views::View, - public ShelfButtonAnimation::Observer { - public: - AppStatusIndicatorView() - : show_attention_(false), animation_end_time_(base::TimeTicks()) { - // Make sure the events reach the parent view for handling. - set_can_process_events_within_subtree(false); - } - - ~AppStatusIndicatorView() override { - ShelfButtonAnimation::GetInstance()->RemoveObserver(this); - } - - // views::View: - void OnPaint(gfx::Canvas* canvas) override { - gfx::ScopedCanvas scoped(canvas); - if (show_attention_) { - SkAlpha alpha = ShelfButtonAnimation::GetInstance()->HasObserver(this) - ? ShelfButtonAnimation::GetInstance()->GetAlpha() - : SK_AlphaOPAQUE; - canvas->SaveLayerAlpha(alpha); - } - - DCHECK_EQ(width(), height()); - DCHECK_EQ(kIndicatorRadiusDip, width() / 2); - const float dsf = canvas->UndoDeviceScaleFactor(); - const int kStrokeWidthPx = 1; - gfx::PointF center = gfx::RectF(GetLocalBounds()).CenterPoint(); - center.Scale(dsf); - - // Fill the center. - cc::PaintFlags flags; - flags.setColor(kIndicatorColor); - flags.setFlags(cc::PaintFlags::kAntiAlias_Flag); - canvas->DrawCircle(center, dsf * kIndicatorRadiusDip - kStrokeWidthPx, - flags); - - // Stroke the border. - flags.setColor(SkColorSetA(SK_ColorBLACK, 0x4D)); - flags.setStyle(SkPaint::kStroke_Style); - canvas->DrawCircle( - center, dsf * kIndicatorRadiusDip - kStrokeWidthPx / 2.0f, flags); - } - - // ShelfButtonAnimation::Observer - void AnimationProgressed() override { - UpdateAnimating(); - SchedulePaint(); - } - - void ShowAttention(bool show) { - if (show_attention_ == show) - return; - - show_attention_ = show; - if (show_attention_) { - animation_end_time_ = base::TimeTicks::Now() + - base::TimeDelta::FromSeconds(kMaxAnimationSeconds); - ShelfButtonAnimation::GetInstance()->AddObserver(this); - } else { - ShelfButtonAnimation::GetInstance()->RemoveObserver(this); - } - } - - private: - void UpdateAnimating() { - if (base::TimeTicks::Now() > animation_end_time_) - ShelfButtonAnimation::GetInstance()->RemoveObserver(this); - } - - bool show_attention_; - base::TimeTicks animation_end_time_; // For attention throbbing underline. - - DISALLOW_COPY_AND_ASSIGN(AppStatusIndicatorView); -}; - -//////////////////////////////////////////////////////////////////////////////// -// ShelfButton - -// static -const char ShelfButton::kViewClassName[] = "ash/ShelfButton"; - -ShelfButton::ShelfButton(InkDropButtonListener* listener, ShelfView* shelf_view) - : CustomButton(nullptr), - listener_(listener), - shelf_view_(shelf_view), - icon_view_(new views::ImageView()), - indicator_(new AppStatusIndicatorView()), - state_(STATE_NORMAL), - destroyed_flag_(nullptr) { - SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); - SetInkDropMode(InkDropMode::ON); - set_ink_drop_base_color(kShelfInkDropBaseColor); - set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); - - const gfx::ShadowValue kShadows[] = { - gfx::ShadowValue(gfx::Vector2d(0, 2), 0, SkColorSetARGB(0x1A, 0, 0, 0)), - gfx::ShadowValue(gfx::Vector2d(0, 3), 1, SkColorSetARGB(0x1A, 0, 0, 0)), - gfx::ShadowValue(gfx::Vector2d(0, 0), 1, SkColorSetARGB(0x54, 0, 0, 0)), - }; - icon_shadows_.assign(kShadows, kShadows + arraysize(kShadows)); - - // TODO: refactor the layers so each button doesn't require 2. - icon_view_->SetPaintToLayer(); - icon_view_->layer()->SetFillsBoundsOpaquely(false); - icon_view_->SetHorizontalAlignment(views::ImageView::CENTER); - icon_view_->SetVerticalAlignment(views::ImageView::LEADING); - // Do not make this interactive, so that events are sent to ShelfView. - icon_view_->set_can_process_events_within_subtree(false); - - AddChildView(indicator_); - AddChildView(icon_view_); -} - -ShelfButton::~ShelfButton() { - if (destroyed_flag_) - *destroyed_flag_ = true; -} - -void ShelfButton::SetShadowedImage(const gfx::ImageSkia& image) { - icon_view_->SetImage(gfx::ImageSkiaOperations::CreateImageWithDropShadow( - image, icon_shadows_)); -} - -void ShelfButton::SetImage(const gfx::ImageSkia& image) { - if (image.isNull()) { - // TODO: need an empty image. - icon_view_->SetImage(image); - return; - } - - // Resize the image maintaining our aspect ratio. - float aspect_ratio = - static_cast<float>(image.width()) / static_cast<float>(image.height()); - int height = kIconSize; - int width = static_cast<int>(aspect_ratio * height); - if (width > kIconSize) { - width = kIconSize; - height = static_cast<int>(width / aspect_ratio); - } - - if (width == image.width() && height == image.height()) { - SetShadowedImage(image); - return; - } - - SetShadowedImage(gfx::ImageSkiaOperations::CreateResizedImage( - image, skia::ImageOperations::RESIZE_BEST, gfx::Size(width, height))); -} - -const gfx::ImageSkia& ShelfButton::GetImage() const { - return icon_view_->GetImage(); -} - -void ShelfButton::AddState(State state) { - if (!(state_ & state)) { - state_ |= state; - Layout(); - if (state & STATE_ATTENTION) - indicator_->ShowAttention(true); - } -} - -void ShelfButton::ClearState(State state) { - if (state_ & state) { - state_ &= ~state; - Layout(); - if (state & STATE_ATTENTION) - indicator_->ShowAttention(false); - } -} - -gfx::Rect ShelfButton::GetIconBounds() const { - return icon_view_->bounds(); -} - -void ShelfButton::OnDragStarted(const ui::LocatedEvent* event) { - AnimateInkDrop(views::InkDropState::HIDDEN, event); -} - -void ShelfButton::ShowContextMenu(const gfx::Point& p, - ui::MenuSourceType source_type) { - if (!context_menu_controller()) - return; - - bool destroyed = false; - destroyed_flag_ = &destroyed; - - CustomButton::ShowContextMenu(p, source_type); - - if (!destroyed) { - destroyed_flag_ = nullptr; - // The menu will not propagate mouse events while its shown. To address, - // the hover state gets cleared once the menu was shown (and this was not - // destroyed). - ClearState(STATE_HOVERED); - } -} - -const char* ShelfButton::GetClassName() const { - return kViewClassName; -} - -bool ShelfButton::OnMousePressed(const ui::MouseEvent& event) { - CustomButton::OnMousePressed(event); - shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); - return true; -} - -void ShelfButton::OnMouseReleased(const ui::MouseEvent& event) { - CustomButton::OnMouseReleased(event); - shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); -} - -void ShelfButton::OnMouseCaptureLost() { - ClearState(STATE_HOVERED); - shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, true); - CustomButton::OnMouseCaptureLost(); -} - -bool ShelfButton::OnMouseDragged(const ui::MouseEvent& event) { - CustomButton::OnMouseDragged(event); - shelf_view_->PointerDraggedOnButton(this, ShelfView::MOUSE, event); - return true; -} - -void ShelfButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_BUTTON; - node_data->SetName(shelf_view_->GetTitleForView(this)); -} - -void ShelfButton::Layout() { - const gfx::Rect button_bounds(GetContentsBounds()); - WmShelf* wm_shelf = shelf_view_->wm_shelf(); - const bool is_horizontal_shelf = wm_shelf->IsHorizontalAlignment(); - const int icon_pad = - is_horizontal_shelf ? kIconPaddingHorizontal : kIconPaddingVertical; - int x_offset = is_horizontal_shelf ? 0 : icon_pad; - int y_offset = is_horizontal_shelf ? icon_pad : 0; - - int icon_width = std::min(kIconSize, button_bounds.width() - x_offset); - int icon_height = std::min(kIconSize, button_bounds.height() - y_offset); - - // If on the left or top 'invert' the inset so the constant gap is on - // the interior (towards the center of display) edge of the shelf. - if (SHELF_ALIGNMENT_LEFT == wm_shelf->GetAlignment()) - x_offset = button_bounds.width() - (kIconSize + icon_pad); - - // Center icon with respect to the secondary axis. - if (is_horizontal_shelf) - x_offset = std::max(0, button_bounds.width() - icon_width) / 2; - else - y_offset = std::max(0, button_bounds.height() - icon_height) / 2; - - // Expand bounds to include shadows. - gfx::Insets insets_shadows = gfx::ShadowValue::GetMargin(icon_shadows_); - // Adjust offsets to center icon, not icon + shadow. - x_offset += (insets_shadows.left() - insets_shadows.right()) / 2; - y_offset += (insets_shadows.top() - insets_shadows.bottom()) / 2; - gfx::Rect icon_view_bounds = - gfx::Rect(button_bounds.x() + x_offset, button_bounds.y() + y_offset, - icon_width, icon_height); - // The indicator should be aligned with the icon, not the icon + shadow. - gfx::Point indicator_midpoint = icon_view_bounds.CenterPoint(); - icon_view_bounds.Inset(insets_shadows); - icon_view_bounds.AdjustToFit(gfx::Rect(size())); - icon_view_->SetBoundsRect(icon_view_bounds); - - // Icon size has been incorrect when running - // PanelLayoutManagerTest.PanelAlignmentSecondDisplay on valgrind bot, see - // http://crbug.com/234854. - DCHECK_LE(icon_width, kIconSize); - DCHECK_LE(icon_height, kIconSize); - - switch (wm_shelf->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - indicator_midpoint.set_y(button_bounds.bottom() - kIndicatorRadiusDip - - kIndicatorOffsetFromBottom); - break; - case SHELF_ALIGNMENT_LEFT: - indicator_midpoint.set_x(button_bounds.x() + kIndicatorRadiusDip + - kIndicatorOffsetFromBottom); - break; - case SHELF_ALIGNMENT_RIGHT: - indicator_midpoint.set_x(button_bounds.right() - kIndicatorRadiusDip - - kIndicatorOffsetFromBottom); - break; - } - - gfx::Rect indicator_bounds(indicator_midpoint, gfx::Size()); - indicator_bounds.Inset(gfx::Insets(-kIndicatorRadiusDip)); - indicator_->SetBoundsRect(indicator_bounds); - - UpdateState(); -} - -void ShelfButton::ChildPreferredSizeChanged(views::View* child) { - Layout(); -} - -void ShelfButton::OnFocus() { - AddState(STATE_FOCUSED); - CustomButton::OnFocus(); -} - -void ShelfButton::OnBlur() { - ClearState(STATE_FOCUSED); - CustomButton::OnBlur(); -} - -void ShelfButton::OnPaint(gfx::Canvas* canvas) { - CustomButton::OnPaint(canvas); - if (HasFocus()) { - canvas->DrawSolidFocusRect(gfx::RectF(GetLocalBounds()), kFocusBorderColor, - kFocusBorderThickness); - } -} - -void ShelfButton::OnGestureEvent(ui::GestureEvent* event) { - switch (event->type()) { - case ui::ET_GESTURE_TAP_DOWN: - AddState(STATE_HOVERED); - return CustomButton::OnGestureEvent(event); - case ui::ET_GESTURE_END: - ClearState(STATE_HOVERED); - return CustomButton::OnGestureEvent(event); - case ui::ET_GESTURE_SCROLL_BEGIN: - shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); - event->SetHandled(); - return; - case ui::ET_GESTURE_SCROLL_UPDATE: - shelf_view_->PointerDraggedOnButton(this, ShelfView::TOUCH, *event); - event->SetHandled(); - return; - case ui::ET_GESTURE_SCROLL_END: - case ui::ET_SCROLL_FLING_START: - shelf_view_->PointerReleasedOnButton(this, ShelfView::TOUCH, false); - event->SetHandled(); - return; - default: - return CustomButton::OnGestureEvent(event); - } -} - -std::unique_ptr<views::InkDropRipple> ShelfButton::CreateInkDropRipple() const { - return base::MakeUnique<views::SquareInkDropRipple>( - gfx::Size(kInkDropLargeSize, kInkDropLargeSize), - kInkDropLargeCornerRadius, - gfx::Size(kInkDropSmallSize, kInkDropSmallSize), - kInkDropSmallCornerRadius, GetLocalBounds().CenterPoint(), - GetInkDropBaseColor(), ink_drop_visible_opacity()); -} - -bool ShelfButton::ShouldEnterPushedState(const ui::Event& event) { - if (!shelf_view_->ShouldEventActivateButton(this, event)) - return false; - - return CustomButton::ShouldEnterPushedState(event); -} - -std::unique_ptr<views::InkDrop> ShelfButton::CreateInkDrop() { - std::unique_ptr<views::InkDropImpl> ink_drop = - CustomButton::CreateDefaultInkDropImpl(); - ink_drop->SetShowHighlightOnHover(false); - return std::move(ink_drop); -} - -void ShelfButton::NotifyClick(const ui::Event& event) { - CustomButton::NotifyClick(event); - if (listener_) - listener_->ButtonPressed(this, event, GetInkDrop()); -} - -void ShelfButton::UpdateState() { - indicator_->SetVisible(!(state_ & STATE_HIDDEN) && - (state_ & STATE_ACTIVE || state_ & STATE_ATTENTION || - state_ & STATE_RUNNING)); - - const bool is_horizontal_shelf = - shelf_view_->wm_shelf()->IsHorizontalAlignment(); - icon_view_->SetHorizontalAlignment(is_horizontal_shelf - ? views::ImageView::CENTER - : views::ImageView::LEADING); - icon_view_->SetVerticalAlignment(is_horizontal_shelf - ? views::ImageView::LEADING - : views::ImageView::CENTER); - SchedulePaint(); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_button.h b/ash/shelf/shelf_button.h deleted file mode 100644 index 540d20ac..0000000 --- a/ash/shelf/shelf_button.h +++ /dev/null
@@ -1,129 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_BUTTON_H_ -#define ASH_SHELF_SHELF_BUTTON_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/gfx/shadow_value.h" -#include "ui/views/controls/button/custom_button.h" - -namespace views { -class ImageView; -} - -namespace ash { -class InkDropButtonListener; -class ShelfView; - -// Button used for items on the launcher, except for the AppList. -class ASH_EXPORT ShelfButton : public views::CustomButton { - public: - static const char kViewClassName[]; - - // Used to indicate the current state of the button. - enum State { - // Nothing special. Usually represents an app shortcut item with no running - // instance. - STATE_NORMAL = 0, - // Button has mouse hovering on it. - STATE_HOVERED = 1 << 0, - // Underlying ShelfItem has a running instance. - STATE_RUNNING = 1 << 1, - // Underlying ShelfItem is active (i.e. has focus). - STATE_ACTIVE = 1 << 2, - // Underlying ShelfItem needs user's attention. - STATE_ATTENTION = 1 << 3, - STATE_FOCUSED = 1 << 4, - // Hide the status (temporarily for some animations). - STATE_HIDDEN = 1 << 5, - }; - - ShelfButton(InkDropButtonListener* listener, ShelfView* shelf_view); - ~ShelfButton() override; - - // Sets the image to display for this entry. - void SetImage(const gfx::ImageSkia& image); - - // Retrieve the image to show proxy operations. - const gfx::ImageSkia& GetImage() const; - - // |state| is or'd into the current state. - void AddState(State state); - void ClearState(State state); - int state() const { return state_; } - - // Returns the bounds of the icon. - gfx::Rect GetIconBounds() const; - - // Called when user started dragging the shelf button. - void OnDragStarted(const ui::LocatedEvent* event); - - // Overrides to views::CustomButton: - void ShowContextMenu(const gfx::Point& p, - ui::MenuSourceType source_type) override; - - // View override - needed by unit test. - void OnMouseCaptureLost() override; - - protected: - // View overrides: - const char* GetClassName() const override; - bool OnMousePressed(const ui::MouseEvent& event) override; - void OnMouseReleased(const ui::MouseEvent& event) override; - bool OnMouseDragged(const ui::MouseEvent& event) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void Layout() override; - void ChildPreferredSizeChanged(views::View* child) override; - void OnFocus() override; - void OnBlur() override; - void OnPaint(gfx::Canvas* canvas) override; - - // ui::EventHandler overrides: - void OnGestureEvent(ui::GestureEvent* event) override; - - // views::CustomButton overrides: - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - bool ShouldEnterPushedState(const ui::Event& event) override; - std::unique_ptr<views::InkDrop> CreateInkDrop() override; - void NotifyClick(const ui::Event& event) override; - - // Sets the icon image with a shadow. - void SetShadowedImage(const gfx::ImageSkia& bitmap); - - private: - class AppStatusIndicatorView; - - // Updates the parts of the button to reflect the current |state_| and - // alignment. This may add or remove views, layout and paint. - void UpdateState(); - - InkDropButtonListener* listener_; - - // The shelf view hosting this button. - ShelfView* shelf_view_; - - // The icon part of a button can be animated independently of the rest. - views::ImageView* icon_view_; - - // Draws an indicator underneath the image to represent the state of the - // application. - AppStatusIndicatorView* indicator_; - - // The current application state, a bitfield of State enum values. - int state_; - - gfx::ShadowValues icon_shadows_; - - // If non-null the destuctor sets this to true. This is set while the menu is - // showing and used to detect if the menu was deleted while running. - bool* destroyed_flag_; - - DISALLOW_COPY_AND_ASSIGN(ShelfButton); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_BUTTON_H_
diff --git a/ash/shelf/shelf_button_pressed_metric_tracker.cc b/ash/shelf/shelf_button_pressed_metric_tracker.cc deleted file mode 100644 index 0724cf6..0000000 --- a/ash/shelf/shelf_button_pressed_metric_tracker.cc +++ /dev/null
@@ -1,100 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_button_pressed_metric_tracker.h" - -#include "ash/common/wm_shell.h" -#include "base/metrics/histogram_macros.h" -#include "base/time/default_tick_clock.h" -#include "ui/views/controls/button/button.h" - -namespace ash { - -const char ShelfButtonPressedMetricTracker:: - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName[] = - "Ash.Shelf.TimeBetweenWindowMinimizedAndActivatedActions"; - -ShelfButtonPressedMetricTracker::ShelfButtonPressedMetricTracker() - : tick_clock_(new base::DefaultTickClock()), - time_of_last_minimize_(base::TimeTicks()), - last_minimized_source_button_(nullptr) {} - -ShelfButtonPressedMetricTracker::~ShelfButtonPressedMetricTracker() {} - -void ShelfButtonPressedMetricTracker::ButtonPressed( - const ui::Event& event, - const views::Button* sender, - ShelfAction performed_action) { - RecordButtonPressedSource(event); - RecordButtonPressedAction(performed_action); - - switch (performed_action) { - case SHELF_ACTION_WINDOW_MINIMIZED: - SetMinimizedData(sender); - break; - case SHELF_ACTION_WINDOW_ACTIVATED: - if (IsSubsequentActivationEvent(sender)) - RecordTimeBetweenMinimizedAndActivated(); - break; - default: - break; - } - - if (performed_action != SHELF_ACTION_WINDOW_MINIMIZED) - ResetMinimizedData(); -} - -void ShelfButtonPressedMetricTracker::RecordButtonPressedSource( - const ui::Event& event) { - if (event.IsMouseEvent()) { - WmShell::Get()->RecordUserMetricsAction( - UMA_LAUNCHER_BUTTON_PRESSED_WITH_MOUSE); - } else if (event.IsGestureEvent()) { - WmShell::Get()->RecordUserMetricsAction( - UMA_LAUNCHER_BUTTON_PRESSED_WITH_TOUCH); - } -} - -void ShelfButtonPressedMetricTracker::RecordButtonPressedAction( - ShelfAction performed_action) { - switch (performed_action) { - case SHELF_ACTION_NONE: - case SHELF_ACTION_APP_LIST_SHOWN: - break; - case SHELF_ACTION_NEW_WINDOW_CREATED: - WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_LAUNCH_TASK); - break; - case SHELF_ACTION_WINDOW_ACTIVATED: - WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_SWITCH_TASK); - break; - case SHELF_ACTION_WINDOW_MINIMIZED: - WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_MINIMIZE_TASK); - break; - } -} - -void ShelfButtonPressedMetricTracker::RecordTimeBetweenMinimizedAndActivated() { - UMA_HISTOGRAM_TIMES( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, - tick_clock_->NowTicks() - time_of_last_minimize_); -} - -bool ShelfButtonPressedMetricTracker::IsSubsequentActivationEvent( - const views::Button* sender) const { - return time_of_last_minimize_ != base::TimeTicks() && - last_minimized_source_button_ == sender; -} - -void ShelfButtonPressedMetricTracker::SetMinimizedData( - const views::Button* sender) { - last_minimized_source_button_ = sender; - time_of_last_minimize_ = tick_clock_->NowTicks(); -} - -void ShelfButtonPressedMetricTracker::ResetMinimizedData() { - last_minimized_source_button_ = nullptr; - time_of_last_minimize_ = base::TimeTicks(); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_button_pressed_metric_tracker.h b/ash/shelf/shelf_button_pressed_metric_tracker.h deleted file mode 100644 index 4c9044b..0000000 --- a/ash/shelf/shelf_button_pressed_metric_tracker.h +++ /dev/null
@@ -1,91 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_H_ -#define ASH_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "base/macros.h" -#include "base/time/tick_clock.h" -#include "base/time/time.h" -#include "ui/events/event.h" - -namespace views { -class Button; -} // namespace views - -namespace ash { - -namespace test { -class ShelfButtonPressedMetricTrackerTestAPI; -} // namespace test - -// Tracks UMA metrics based on shelf button press actions. More specifically -// data is added to the following user actions and histograms: -// -// User Actions: -// - Launcher_ButtonPressed_Mouse -// - Launcher_ButtonPressed_Touch -// - Launcher_LaunchTask -// - Launcher_MinimizeTask -// - Launcher_SwitchTask -// Histograms: -// - Ash.Shelf.TimeBetweenWindowMinimizedAndActivatedActions -// -class ASH_EXPORT ShelfButtonPressedMetricTracker { - public: - static const char - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName[]; - - ShelfButtonPressedMetricTracker(); - ~ShelfButtonPressedMetricTracker(); - - // Records metrics based on the |event|, |sender|, and |performed_action|. - void ButtonPressed(const ui::Event& event, - const views::Button* sender, - ShelfAction performed_action); - - private: - friend class test::ShelfButtonPressedMetricTrackerTestAPI; - - // Records UMA metrics for the input source when a button is pressed. - void RecordButtonPressedSource(const ui::Event& event); - - // Records UMA metrics for the action performed when a button is pressed. - void RecordButtonPressedAction(ShelfAction performed_action); - - // Records UMA metrics for the elapsed time since the last window minimize - // action. - void RecordTimeBetweenMinimizedAndActivated(); - - // Returns true if a window activation action triggered by |sender| would - // be subsequent to the last minimize window action. - bool IsSubsequentActivationEvent(const views::Button* sender) const; - - // Caches state data for a window minimized action. The |sender| is the button - // that caused the action. - void SetMinimizedData(const views::Button* sender); - - // Resets the state data associated with the last window minimize action. - void ResetMinimizedData(); - - // Time source for performed action times. - std::unique_ptr<base::TickClock> tick_clock_; - - // Stores the time of the last window minimize action. - base::TimeTicks time_of_last_minimize_; - - // Stores the source button of the last window minimize action. - // NOTE: This may become stale and should not be operated on. Not owned. - const views::Button* last_minimized_source_button_; - - DISALLOW_COPY_AND_ASSIGN(ShelfButtonPressedMetricTracker); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_H_
diff --git a/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc b/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc deleted file mode 100644 index 1cc2879..0000000 --- a/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc +++ /dev/null
@@ -1,314 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_button_pressed_metric_tracker.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/shelf_button_pressed_metric_tracker_test_api.h" -#include "ash/test/shelf_view_test_api.h" -#include "base/macros.h" -#include "base/test/histogram_tester.h" -#include "base/test/simple_test_tick_clock.h" -#include "base/test/user_action_tester.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/events/event.h" -#include "ui/views/controls/button/button.h" - -namespace ash { -namespace test { -namespace { - -// A simple light weight test double dummy for a views::Button. -class DummyButton : public views::Button { - public: - DummyButton(); - - private: - DISALLOW_COPY_AND_ASSIGN(DummyButton); -}; - -DummyButton::DummyButton() : views::Button(nullptr) {} - -// A simple light weight test double dummy for a ui::Event. -class DummyEvent : public ui::Event { - public: - DummyEvent(); - ~DummyEvent() override; - int unique_id() const { return unique_id_; } - - private: - static int next_unique_id_; - int unique_id_; - - DISALLOW_COPY_AND_ASSIGN(DummyEvent); -}; - -int DummyEvent::next_unique_id_ = 0; - -DummyEvent::DummyEvent() - : Event(ui::ET_GESTURE_TAP, base::TimeTicks(), 0), - unique_id_(next_unique_id_++) {} - -DummyEvent::~DummyEvent() {} - -// Test fixture for the ShelfButtonPressedMetricTracker class. Relies on -// AshTestBase to initilize the UserMetricsRecorder and it's dependencies. -class ShelfButtonPressedMetricTrackerTest : public AshTestBase { - public: - static const char* - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName; - - ShelfButtonPressedMetricTrackerTest(); - ~ShelfButtonPressedMetricTrackerTest() override; - - // AshTestBase: - void SetUp() override; - void TearDown() override; - - // Calls ButtonPressed on the test target with the given |event| - // and dummy values for the |sender| and |performed_action| parameters. - void ButtonPressed(const ui::Event& event); - - // Calls ButtonPressed on the test target with the given |performed_action| - // and dummy values for the |event| and |sender| parameters. - void ButtonPressed(ShelfAction performed_action); - - // Calls ButtonPressed on the test target with the given |sender| and - // |performed_action| and a dummy value for the |event| parameter. - void ButtonPressed(const views::Button* sender, ShelfAction performed_action); - - protected: - // The test target. Not owned. - ShelfButtonPressedMetricTracker* metric_tracker_; - - // The TickClock injected in to the test target. - base::SimpleTestTickClock* tick_clock_; - - private: - DISALLOW_COPY_AND_ASSIGN(ShelfButtonPressedMetricTrackerTest); -}; - -const char* ShelfButtonPressedMetricTrackerTest:: - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName = - ShelfButtonPressedMetricTracker:: - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName; - -ShelfButtonPressedMetricTrackerTest::ShelfButtonPressedMetricTrackerTest() {} - -ShelfButtonPressedMetricTrackerTest::~ShelfButtonPressedMetricTrackerTest() {} - -void ShelfButtonPressedMetricTrackerTest::SetUp() { - AshTestBase::SetUp(); - - WmShelf* wm_shelf = GetPrimaryShelf(); - ShelfViewTestAPI shelf_view_test_api(wm_shelf->GetShelfViewForTesting()); - - metric_tracker_ = shelf_view_test_api.shelf_button_pressed_metric_tracker(); - - ShelfButtonPressedMetricTrackerTestAPI test_api(metric_tracker_); - - std::unique_ptr<base::TickClock> test_tick_clock( - new base::SimpleTestTickClock()); - tick_clock_ = static_cast<base::SimpleTestTickClock*>(test_tick_clock.get()); - test_api.SetTickClock(std::move(test_tick_clock)); - - // Ensure the TickClock->NowTicks() doesn't return base::TimeTicks because - // ShelfButtonPressedMetricTracker interprets that value as unset. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(100)); -} - -void ShelfButtonPressedMetricTrackerTest::TearDown() { - tick_clock_ = nullptr; - - AshTestBase::TearDown(); -} - -void ShelfButtonPressedMetricTrackerTest::ButtonPressed( - const ui::Event& event) { - const DummyButton kDummyButton; - metric_tracker_->ButtonPressed(event, &kDummyButton, SHELF_ACTION_NONE); -} - -void ShelfButtonPressedMetricTrackerTest::ButtonPressed( - ShelfAction performed_action) { - const DummyEvent kDummyEvent; - const DummyButton kDummyButton; - metric_tracker_->ButtonPressed(kDummyEvent, &kDummyButton, performed_action); -} - -void ShelfButtonPressedMetricTrackerTest::ButtonPressed( - const views::Button* sender, - ShelfAction performed_action) { - const DummyEvent kDummyEvent; - metric_tracker_->ButtonPressed(kDummyEvent, sender, performed_action); -} - -} // namespace - -// Verifies that a Launcher_ButtonPressed_Mouse UMA user action is recorded when -// a button is pressed by a mouse event. -TEST_F(ShelfButtonPressedMetricTrackerTest, - Launcher_ButtonPressed_MouseIsRecordedWhenIconActivatedByMouse) { - // TODO: investigate failure in mash. http://crbug.com/695565. - if (WmShell::Get()->IsRunningInMash()) - return; - - const ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, gfx::Point(), - gfx::Point(), base::TimeTicks(), 0, 0); - - base::UserActionTester user_action_tester; - ButtonPressed(mouse_event); - EXPECT_EQ(1, - user_action_tester.GetActionCount("Launcher_ButtonPressed_Mouse")); -} - -// Verifies that a Launcher_ButtonPressed_Touch UMA user action is recorded when -// a button is pressed by a touch event. -TEST_F(ShelfButtonPressedMetricTrackerTest, - Launcher_ButtonPressed_MouseIsRecordedWhenIconActivatedByTouch) { - // TODO: investigate failure in mash. http://crbug.com/695565. - if (WmShell::Get()->IsRunningInMash()) - return; - - const ui::TouchEvent touch_event(ui::ET_GESTURE_TAP, gfx::Point(), 0, - base::TimeTicks()); - - base::UserActionTester user_action_tester; - ButtonPressed(touch_event); - EXPECT_EQ(1, - user_action_tester.GetActionCount("Launcher_ButtonPressed_Touch")); -} - -// Verifies that a Launcher_LaunchTask UMA user action is recorded when -// pressing a button causes a new window to be created. -TEST_F(ShelfButtonPressedMetricTrackerTest, - Launcher_LaunchTaskIsRecordedWhenNewWindowIsCreated) { - // TODO: investigate failure in mash. http://crbug.com/695565. - if (WmShell::Get()->IsRunningInMash()) - return; - - base::UserActionTester user_action_tester; - ButtonPressed(SHELF_ACTION_NEW_WINDOW_CREATED); - EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_LaunchTask")); -} - -// Verifies that a Launcher_MinimizeTask UMA user action is recorded when -// pressing a button causes an existing window to be minimized. -TEST_F(ShelfButtonPressedMetricTrackerTest, - Launcher_MinimizeTaskIsRecordedWhenWindowIsMinimized) { - // TODO: investigate failure in mash. http://crbug.com/695565. - if (WmShell::Get()->IsRunningInMash()) - return; - - base::UserActionTester user_action_tester; - ButtonPressed(SHELF_ACTION_WINDOW_MINIMIZED); - EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_MinimizeTask")); -} - -// Verifies that a Launcher_SwitchTask UMA user action is recorded when -// pressing a button causes an existing window to be activated. -TEST_F(ShelfButtonPressedMetricTrackerTest, - Launcher_SwitchTaskIsRecordedWhenExistingWindowIsActivated) { - // TODO: investigate failure in mash. http://crbug.com/695565. - if (WmShell::Get()->IsRunningInMash()) - return; - - base::UserActionTester user_action_tester; - ButtonPressed(SHELF_ACTION_WINDOW_ACTIVATED); - EXPECT_EQ(1, user_action_tester.GetActionCount("Launcher_SwitchTask")); -} - -// Verify that a window activation action will record a data point if it was -// subsequent to a minimize action. -TEST_F(ShelfButtonPressedMetricTrackerTest, - VerifyDataRecordedAfterMinimizedAndSubsequentActivatedAction) { - const DummyButton kDummyButton; - - base::HistogramTester histogram_tester; - - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); - histogram_tester.ExpectTotalCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0); - - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); - histogram_tester.ExpectTotalCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1); -} - -// Verify that a multiple window activation actions will record a single data -// point if they are subsequent to a minimize action. -TEST_F(ShelfButtonPressedMetricTrackerTest, - VerifyDataRecordedAfterMinimizedAndMultipleSubsequentActivatedActions) { - const DummyButton kDummyButton; - - base::HistogramTester histogram_tester; - - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); - - histogram_tester.ExpectTotalCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1); -} - -// Verify that a window activation action will not record a data point if it was -// not subsequent to a minimize action. -TEST_F(ShelfButtonPressedMetricTrackerTest, - VerifyDataRecordedAfterMinimizedAndNonSubsequentActivatedAction) { - const DummyButton kDummyButton; - - base::HistogramTester histogram_tester; - - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); - ButtonPressed(&kDummyButton, SHELF_ACTION_APP_LIST_SHOWN); - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); - - histogram_tester.ExpectTotalCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0); -} - -// Verify no data is recorded if a second source button is pressed in between -// subsequent minimized and activated actions on the same source. -TEST_F(ShelfButtonPressedMetricTrackerTest, - VerifyDataRecordedAfterMinimizedButtonA) { - const DummyButton kDummyButton; - const DummyButton kSecondDummyButton; - - base::HistogramTester histogram_tester; - - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); - ButtonPressed(&kSecondDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); - - histogram_tester.ExpectTotalCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 0); -} - -// Verify the data value recorded when a window activation action is subsequent -// to a minimize action. -TEST_F(ShelfButtonPressedMetricTrackerTest, - VerifyTheValueRecordedBySubsequentMinimizedAndActivateActions) { - const int kTimeDeltaInMilliseconds = 17; - const DummyButton kDummyButton; - - base::HistogramTester histogram_tester; - - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_MINIMIZED); - tick_clock_->Advance( - base::TimeDelta::FromMilliseconds(kTimeDeltaInMilliseconds)); - ButtonPressed(&kDummyButton, SHELF_ACTION_WINDOW_ACTIVATED); - - histogram_tester.ExpectTotalCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, 1); - histogram_tester.ExpectBucketCount( - kTimeBetweenWindowMinimizedAndActivatedActionsHistogramName, - kTimeDeltaInMilliseconds, 1); -} - -} // namespace test -} // namespace ash
diff --git a/ash/shelf/shelf_constants.cc b/ash/shelf/shelf_constants.cc deleted file mode 100644 index 1d43a73c..0000000 --- a/ash/shelf/shelf_constants.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_constants.h" - -#include "base/logging.h" -#include "third_party/skia/include/core/SkColor.h" - -namespace ash { - -const int kTimeToSwitchBackgroundMs = 1000; -const int kWorkspaceAreaVisibleInset = 2; -const int kWorkspaceAreaAutoHideInset = 5; -const int kShelfAutoHideSize = 3; -const SkColor kShelfDefaultBaseColor = SK_ColorBLACK; -const int kShelfButtonSize = 48; -const int kShelfButtonSpacing = 16; -const SkColor kShelfButtonActivatedHighlightColor = - SkColorSetA(SK_ColorWHITE, 100); -const SkColor kShelfInkDropBaseColor = SK_ColorWHITE; -const float kShelfInkDropVisibleOpacity = 0.2f; -const SkColor kShelfIconColor = SK_ColorWHITE; -const int kShelfTranslucentAlpha = 153; -const int kOverflowButtonSize = 32; -const int kOverflowButtonCornerRadius = 2; -const int kAppListButtonRadius = kOverflowButtonSize / 2; - -int GetShelfConstant(ShelfConstant shelf_constant) { - const int kShelfSize[] = {47, 48, 48}; - const int kShelfInsetsForAutoHide[] = {3, 0, 0}; - - // TODO(estade): clean this up --- remove unneeded constants and reduce - // remaining arrays to a single constant. - const int mode = 1; - switch (shelf_constant) { - case SHELF_SIZE: - return kShelfSize[mode]; - case SHELF_INSETS_FOR_AUTO_HIDE: - return kShelfInsetsForAutoHide[mode]; - } - NOTREACHED(); - return 0; -} - -} // namespace ash
diff --git a/ash/shelf/shelf_constants.h b/ash/shelf/shelf_constants.h deleted file mode 100644 index 9be93c81..0000000 --- a/ash/shelf/shelf_constants.h +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_CONSTANTS_H_ -#define ASH_SHELF_SHELF_CONSTANTS_H_ - -#include "ash/ash_export.h" -#include "third_party/skia/include/core/SkColor.h" - -namespace ash { - -enum ShelfConstant { - // Size of the shelf when visible (height when the shelf is horizontal and - // width when the shelf is vertical). - SHELF_SIZE, - - // Insets allocated for shelf when it is auto hidden. - SHELF_INSETS_FOR_AUTO_HIDE -}; - -// We reserve a small area on the edge of the workspace area to ensure that -// the resize handle at the edge of the window can be hit. -extern const int kWorkspaceAreaVisibleInset; - -// When autohidden we extend the touch hit target onto the screen so that the -// user can drag the shelf out. -extern const int kWorkspaceAreaAutoHideInset; - -// Size of the shelf when auto-hidden. -ASH_EXPORT extern const int kShelfAutoHideSize; - -// Animation duration for switching black shelf and dock background on and off. -ASH_EXPORT extern const int kTimeToSwitchBackgroundMs; - -// The default base color of the shelf to which different alpha values are -// applied based on the desired shelf opacity level. -ASH_EXPORT extern const SkColor kShelfDefaultBaseColor; - -// Size allocated for each app button on the shelf. -ASH_EXPORT extern const int kShelfButtonSize; - -// Size of the space between buttons on the shelf. -ASH_EXPORT extern const int kShelfButtonSpacing; - -// Highlight color used for shelf button activated states. -// TODO(bruthig|mohsen): Use of this color is temporary. Draw the active state -// using the material design ripple animation. -ASH_EXPORT extern const SkColor kShelfButtonActivatedHighlightColor; - -// Ink drop color for shelf items. -extern const SkColor kShelfInkDropBaseColor; - -// Opacity of the ink drop ripple for shelf items when the ripple is visible. -extern const float kShelfInkDropVisibleOpacity; - -// The foreground color of the icons used in the shelf (launcher, -// notifications, etc). -ASH_EXPORT extern const SkColor kShelfIconColor; - -// The alpha value for the shelf background when a window is overlapping. -ASH_EXPORT extern const int kShelfTranslucentAlpha; - -// The width and height of the material design overflow button. -// TODO(tdanderson): Refactor constants which are common between the shelf -// and the tray. See crbug.com/623987. -extern const int kOverflowButtonSize; - -// The radius of the rounded corners of the overflow button. -extern const int kOverflowButtonCornerRadius; - -// The radius of the circular material design app list button. -extern const int kAppListButtonRadius; - -// The direction of the focus cycling. -enum CycleDirection { CYCLE_FORWARD, CYCLE_BACKWARD }; - -ASH_EXPORT int GetShelfConstant(ShelfConstant shelf_constant); - -} // namespace ash - -#endif // ASH_SHELF_SHELF_CONSTANTS_H_
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc deleted file mode 100644 index 4a0130d..0000000 --- a/ash/shelf/shelf_controller.cc +++ /dev/null
@@ -1,244 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_controller.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shell.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/resources/grit/ui_resources.h" - -namespace ash { - -namespace { - -// A ShelfItemDelegate used for pinned items in mash. -// TODO(mash): Support open windows, cooperate with ShelfWindowWatcher. -class ShelfItemDelegateMus : public ShelfItemDelegate { - public: - ShelfItemDelegateMus() {} - ~ShelfItemDelegateMus() override {} - - void SetDelegate(mojom::ShelfItemDelegateAssociatedPtrInfo delegate) { - delegate_.Bind(std::move(delegate)); - } - - bool pinned() const { return pinned_; } - void set_pinned(bool pinned) { pinned_ = pinned; } - - void AddWindow(uint32_t id, const base::string16& title) { - DCHECK(!window_id_to_title_.count(id)); - window_id_to_title_.insert(std::make_pair(id, title)); - } - void RemoveWindow(uint32_t id) { window_id_to_title_.erase(id); } - void SetWindowTitle(uint32_t id, const base::string16& title) { - DCHECK(window_id_to_title_.count(id)); - window_id_to_title_[id] = title; - } - const std::map<uint32_t, base::string16>& window_id_to_title() const { - return window_id_to_title_; - } - - const base::string16& title() { return title_; } - void set_title(const base::string16& title) { title_ = title; } - - private: - // ShelfItemDelegate: - ShelfAction ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) override { - if (window_id_to_title_.empty()) { - delegate_->LaunchItem(); - return SHELF_ACTION_NEW_WINDOW_CREATED; - } - if (window_id_to_title_.size() == 1) { - // TODO(mash): Activate the window and return - // SHELF_ACTION_WINDOW_ACTIVATED. - NOTIMPLEMENTED(); - } - return SHELF_ACTION_NONE; - } - - ShelfAppMenuItemList GetAppMenuItems(int event_flags) override { - // Return an empty item list to avoid showing an application menu. - return ShelfAppMenuItemList(); - } - - void ExecuteCommand(uint32_t command_id, int event_flags) override { - // This delegate does not support showing an application menu. - NOTIMPLEMENTED(); - } - - void Close() override { NOTIMPLEMENTED(); } - - mojom::ShelfItemDelegateAssociatedPtr delegate_; - bool pinned_ = false; - std::map<uint32_t, base::string16> window_id_to_title_; - base::string16 title_; - - DISALLOW_COPY_AND_ASSIGN(ShelfItemDelegateMus); -}; - -// Returns the ShelfItemDelegateMus instance for the given |shelf_id|. -ShelfItemDelegateMus* GetShelfItemDelegate(ShelfID shelf_id) { - return static_cast<ShelfItemDelegateMus*>( - WmShell::Get()->shelf_model()->GetShelfItemDelegate(shelf_id)); -} - -// Returns an icon image from an SkBitmap, or the default shelf icon image if -// the bitmap is empty. Assumes the bitmap is a 1x icon. -// TODO(jamescook): Support other scale factors. -gfx::ImageSkia GetShelfIconFromBitmap(const SkBitmap& bitmap) { - gfx::ImageSkia icon_image; - if (!bitmap.isNull()) { - icon_image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); - } else { - // Use default icon. - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - icon_image = *rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON); - } - return icon_image; -} - -// Returns the WmShelf instance for the display with the given |display_id|. -WmShelf* GetShelfForDisplay(int64_t display_id) { - // The controller may be null for invalid ids or for displays being removed. - RootWindowController* root_window_controller = - Shell::GetRootWindowControllerWithDisplayId(display_id); - return root_window_controller ? root_window_controller->GetShelf() : nullptr; -} - -} // namespace - -ShelfController::ShelfController() {} - -ShelfController::~ShelfController() {} - -void ShelfController::BindRequest(mojom::ShelfControllerRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void ShelfController::NotifyShelfCreated(WmShelf* shelf) { - // Notify observers, Chrome will set alignment and auto-hide from prefs. - int64_t display_id = shelf->GetWindow()->GetDisplayNearestWindow().id(); - observers_.ForAllPtrs([display_id](mojom::ShelfObserver* observer) { - observer->OnShelfCreated(display_id); - }); -} - -void ShelfController::NotifyShelfAlignmentChanged(WmShelf* shelf) { - ShelfAlignment alignment = shelf->alignment(); - int64_t display_id = shelf->GetWindow()->GetDisplayNearestWindow().id(); - observers_.ForAllPtrs( - [alignment, display_id](mojom::ShelfObserver* observer) { - observer->OnAlignmentChanged(alignment, display_id); - }); -} - -void ShelfController::NotifyShelfAutoHideBehaviorChanged(WmShelf* shelf) { - ShelfAutoHideBehavior behavior = shelf->auto_hide_behavior(); - int64_t display_id = shelf->GetWindow()->GetDisplayNearestWindow().id(); - observers_.ForAllPtrs([behavior, display_id](mojom::ShelfObserver* observer) { - observer->OnAutoHideBehaviorChanged(behavior, display_id); - }); -} - -void ShelfController::AddObserver( - mojom::ShelfObserverAssociatedPtrInfo observer) { - mojom::ShelfObserverAssociatedPtr observer_ptr; - observer_ptr.Bind(std::move(observer)); - observers_.AddPtr(std::move(observer_ptr)); -} - -void ShelfController::SetAlignment(ShelfAlignment alignment, - int64_t display_id) { - if (!ash::WmShelf::CanChangeShelfAlignment()) - return; - - WmShelf* shelf = GetShelfForDisplay(display_id); - // TODO(jamescook): The initialization check should not be necessary, but - // otherwise this wrongly tries to set the alignment on a secondary display - // during login before the ShelfLockingManager and ShelfView are created. - if (shelf && shelf->IsShelfInitialized()) - shelf->SetAlignment(alignment); -} - -void ShelfController::SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide, - int64_t display_id) { - WmShelf* shelf = GetShelfForDisplay(display_id); - // TODO(jamescook): The initialization check should not be necessary, but - // otherwise this wrongly tries to set auto-hide state on a secondary display - // during login before the ShelfView is created. - if (shelf && shelf->IsShelfInitialized()) - shelf->SetAutoHideBehavior(auto_hide); -} - -void ShelfController::PinItem( - mojom::ShelfItemPtr item, - mojom::ShelfItemDelegateAssociatedPtrInfo delegate) { - if (app_id_to_shelf_id_.count(item->app_id)) { - ShelfID shelf_id = app_id_to_shelf_id_[item->app_id]; - ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); - item_delegate->SetDelegate(std::move(delegate)); - item_delegate->set_pinned(true); - return; - } - - ShelfID shelf_id = model_.next_id(); - app_id_to_shelf_id_.insert(std::make_pair(item->app_id, shelf_id)); - shelf_id_to_app_id_.insert(std::make_pair(shelf_id, item->app_id)); - - ShelfItem shelf_item; - shelf_item.type = TYPE_APP_SHORTCUT; - shelf_item.status = STATUS_CLOSED; - shelf_item.image = GetShelfIconFromBitmap(item->image); - shelf_item.title = base::UTF8ToUTF16(item->app_title); - model_.Add(shelf_item); - - std::unique_ptr<ShelfItemDelegateMus> item_delegate = - base::MakeUnique<ShelfItemDelegateMus>(); - item_delegate->SetDelegate(std::move(delegate)); - item_delegate->set_pinned(true); - item_delegate->set_title(shelf_item.title); - model_.SetShelfItemDelegate(shelf_id, std::move(item_delegate)); -} - -void ShelfController::UnpinItem(const std::string& app_id) { - if (!app_id_to_shelf_id_.count(app_id)) - return; - - ShelfID shelf_id = app_id_to_shelf_id_[app_id]; - ShelfItemDelegateMus* item_delegate = GetShelfItemDelegate(shelf_id); - DCHECK(item_delegate->pinned()); - item_delegate->set_pinned(false); - if (item_delegate->window_id_to_title().empty()) { - model_.RemoveItemAt(model_.ItemIndexByID(shelf_id)); - app_id_to_shelf_id_.erase(app_id); - shelf_id_to_app_id_.erase(shelf_id); - } -} - -void ShelfController::SetItemImage(const std::string& app_id, - const SkBitmap& image) { - if (!app_id_to_shelf_id_.count(app_id)) - return; - ShelfID shelf_id = app_id_to_shelf_id_[app_id]; - int index = model_.ItemIndexByID(shelf_id); - DCHECK_GE(index, 0); - ShelfItem item = *model_.ItemByID(shelf_id); - item.image = GetShelfIconFromBitmap(image); - model_.Set(index, item); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_controller.h b/ash/shelf/shelf_controller.h deleted file mode 100644 index de4a19ac..0000000 --- a/ash/shelf/shelf_controller.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_CONTROLLER_H_ -#define ASH_SHELF_SHELF_CONTROLLER_H_ - -#include <map> -#include <string> - -#include "ash/public/cpp/shelf_types.h" -#include "ash/public/interfaces/shelf.mojom.h" -#include "ash/shelf/shelf_item_types.h" -#include "ash/shelf/shelf_model.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "mojo/public/cpp/bindings/interface_ptr_set.h" - -namespace ash { - -class WmShelf; - -// Ash's implementation of the mojom::ShelfController interface. Chrome connects -// to this interface to observe and manage the per-display ash shelf instances. -class ShelfController : public mojom::ShelfController { - public: - ShelfController(); - ~ShelfController() override; - - // Binds the mojom::ShelfController interface request to this object. - void BindRequest(mojom::ShelfControllerRequest request); - - ShelfModel* model() { return &model_; } - - const std::map<std::string, ShelfID>& app_id_to_shelf_id() { - return app_id_to_shelf_id_; - } - - const std::map<ShelfID, std::string>& shelf_id_to_app_id() { - return shelf_id_to_app_id_; - } - - // Functions used to notify mojom::ShelfObserver instances of changes. - void NotifyShelfCreated(WmShelf* shelf); - void NotifyShelfAlignmentChanged(WmShelf* shelf); - void NotifyShelfAutoHideBehaviorChanged(WmShelf* shelf); - - // mojom::Shelf: - void AddObserver(mojom::ShelfObserverAssociatedPtrInfo observer) override; - void SetAlignment(ShelfAlignment alignment, int64_t display_id) override; - void SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide, - int64_t display_id) override; - void PinItem(mojom::ShelfItemPtr item, - mojom::ShelfItemDelegateAssociatedPtrInfo delegate) override; - void UnpinItem(const std::string& app_id) override; - void SetItemImage(const std::string& app_id, const SkBitmap& image) override; - - private: - // The shelf model shared by all shelf instances. - ShelfModel model_; - - // Bindings for the ShelfController interface. - mojo::BindingSet<mojom::ShelfController> bindings_; - - // The set of shelf observers notified about shelf state and settings changes. - mojo::AssociatedInterfacePtrSet<mojom::ShelfObserver> observers_; - - // Mappings between application and shelf ids. - std::map<std::string, ShelfID> app_id_to_shelf_id_; - std::map<ShelfID, std::string> shelf_id_to_app_id_; - - DISALLOW_COPY_AND_ASSIGN(ShelfController); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_CONTROLLER_H_
diff --git a/ash/shelf/shelf_delegate.h b/ash/shelf/shelf_delegate.h deleted file mode 100644 index a19facb..0000000 --- a/ash/shelf/shelf_delegate.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_DELEGATE_H_ -#define ASH_SHELF_SHELF_DELEGATE_H_ - -#include <string> - -#include "ash/ash_export.h" -#include "ash/shelf/shelf_item_types.h" - -namespace ash { - -// Delegate shared by all shelf instances. -class ASH_EXPORT ShelfDelegate { - public: - virtual ~ShelfDelegate() {} - - // Get the shelf ID from an application ID. - virtual ShelfID GetShelfIDForAppID(const std::string& app_id) = 0; - - // Get the shelf ID from an application ID and a launch ID. - // The launch ID can be passed to an app when launched in order to support - // multiple shelf items per app. This id is used together with the app_id to - // uniquely identify each shelf item that has the same app_id. - // For example, a single virtualization app might want to show different - // shelf icons for different remote apps. - virtual ShelfID GetShelfIDForAppIDAndLaunchID( - const std::string& app_id, - const std::string& launch_id) = 0; - - // Checks whether a mapping exists from the ShelfID |id| to an app id. - virtual bool HasShelfIDToAppIDMapping(ShelfID id) const = 0; - - // Get the application ID for a given shelf ID. - // |HasShelfIDToAppIDMapping(ShelfID)| should be called first to ensure the - // ShelfID can be successfully mapped to an app id. - virtual const std::string& GetAppIDForShelfID(ShelfID id) = 0; - - // Pins an app with |app_id| to shelf. A running instance will get pinned. - // In case there is no running instance a new shelf item is created and - // pinned. - virtual void PinAppWithID(const std::string& app_id) = 0; - - // Check if the app with |app_id_| is pinned to the shelf. - virtual bool IsAppPinned(const std::string& app_id) = 0; - - // Unpins app item with |app_id|. - virtual void UnpinAppWithID(const std::string& app_id) = 0; -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_DELEGATE_H_
diff --git a/ash/shelf/shelf_item_delegate.cc b/ash/shelf/shelf_item_delegate.cc deleted file mode 100644 index 9eb63c2..0000000 --- a/ash/shelf/shelf_item_delegate.cc +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_item_delegate.h" - -#include "ui/display/types/display_constants.h" - -namespace ash { - -ShelfItemDelegate::ShelfItemDelegate() {} -ShelfItemDelegate::~ShelfItemDelegate() {} - -ShelfAction ShelfItemDelegate::ItemSelectedBySource(ShelfLaunchSource source) { - return ItemSelected(ui::ET_UNKNOWN, ui::EF_NONE, display::kInvalidDisplayId, - source); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_item_delegate.h b/ash/shelf/shelf_item_delegate.h deleted file mode 100644 index 028d588..0000000 --- a/ash/shelf/shelf_item_delegate.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_ITEM_DELEGATE_H_ -#define ASH_SHELF_SHELF_ITEM_DELEGATE_H_ - -#include <stdint.h> - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_application_menu_item.h" -#include "ash/public/cpp/shelf_types.h" -#include "ui/events/event_constants.h" - -namespace ash { - -// Delegate for the ShelfItem. -class ASH_EXPORT ShelfItemDelegate { - public: - ShelfItemDelegate(); - virtual ~ShelfItemDelegate(); - - // Called when the user selects a shelf item. The event type and flags, the - // relevant display id, and the source of the selection should be provided if - // they are known to the caller; as some subclasses use these arguments. - // Defaults: (ET_UNKNOWN, EF_NONE, kInvalidDisplayId, LAUNCH_FROM_UNKNOWN) - // Returns the action performed by selecting the item. - virtual ShelfAction ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) = 0; - - // A helper to call ItemSelected with a source and default arguments. - ShelfAction ItemSelectedBySource(ShelfLaunchSource source); - - // Returns any application menu items that should appear for this shelf item. - // |event_flags| specifies the flags of the event which triggered this menu. - virtual ShelfAppMenuItemList GetAppMenuItems(int event_flags) = 0; - - // Called on invocation of a shelf item's application menu command. - virtual void ExecuteCommand(uint32_t command_id, int event_flags) = 0; - - // Closes all windows associated with this item. - virtual void Close() = 0; - - DISALLOW_COPY_AND_ASSIGN(ShelfItemDelegate); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/shelf/shelf_item_types.cc b/ash/shelf/shelf_item_types.cc deleted file mode 100644 index 6345fde..0000000 --- a/ash/shelf/shelf_item_types.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_item_types.h" - -namespace ash { - -ShelfItem::ShelfItem() {} -ShelfItem::ShelfItem(const ShelfItem& shelf_item) = default; -ShelfItem::~ShelfItem() {} - -} // namespace ash
diff --git a/ash/shelf/shelf_item_types.h b/ash/shelf/shelf_item_types.h deleted file mode 100644 index ab587d3..0000000 --- a/ash/shelf/shelf_item_types.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_ITEM_TYPES_H_ -#define ASH_SHELF_SHELF_ITEM_TYPES_H_ - -// TODO(msw): Rename these files to shelf_item.*; audit users. - -#include <string> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" -#include "base/strings/string16.h" -#include "ui/gfx/image/image_skia.h" - -namespace ash { - -struct ASH_EXPORT ShelfItem { - ShelfItem(); - ShelfItem(const ShelfItem& shelf_item); - ~ShelfItem(); - - ShelfItemType type = TYPE_UNDEFINED; - - // Image to display in the shelf. - gfx::ImageSkia image; - - // Assigned by the model when the item is added. - ShelfID id = kInvalidShelfID; - - // Running status. - ShelfItemStatus status = STATUS_CLOSED; - - // The application id for this shelf item; only populated for some items. - std::string app_id; - - // The title to display for tooltips, etc. - base::string16 title; - - // Whether the tooltip should be shown on hover; generally true. - bool shows_tooltip = true; - - // Whether the item is pinned by a policy preference (ie. user cannot un-pin). - bool pinned_by_policy = false; -}; - -typedef std::vector<ShelfItem> ShelfItems; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_ITEM_TYPES_H_
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc deleted file mode 100644 index fcd8036c..0000000 --- a/ash/shelf/shelf_layout_manager.cc +++ /dev/null
@@ -1,1143 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_layout_manager.h" - -#include <algorithm> -#include <cmath> -#include <vector> - -#include "ash/animation/animation_change_type.h" -#include "ash/common/session/session_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_layout_manager_observer.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/status_area_widget.h" -#include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_screen_util.h" -#include "base/auto_reset.h" -#include "base/command_line.h" -#include "base/i18n/rtl.h" -#include "ui/base/ui_base_switches.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/compositor/layer_animator.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/events/event.h" -#include "ui/events/event_handler.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_util.h" -#include "ui/views/border.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -// Delay before showing the shelf. This is after the mouse stops moving. -const int kAutoHideDelayMS = 200; - -// Duration of the animation to show or hide the shelf. -const int kAnimationDurationMS = 200; - -// To avoid hiding the shelf when the mouse transitions from a message bubble -// into the shelf, the hit test area is enlarged by this amount of pixels to -// keep the shelf from hiding. -const int kNotificationBubbleGapHeight = 6; - -// The maximum size of the region on the display opposing the shelf managed by -// this ShelfLayoutManager which can trigger showing the shelf. -// For instance: -// - Primary display is left of secondary display. -// - Shelf is left aligned -// - This ShelfLayoutManager manages the shelf for the secondary display. -// |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region -// from the right edge of the primary display which can trigger showing the -// auto hidden shelf. The region is used to make it easier to trigger showing -// the auto hidden shelf when the shelf is on the boundary between displays. -const int kMaxAutoHideShowShelfRegionSize = 10; - -ui::Layer* GetLayer(views::Widget* widget) { - return widget->GetNativeView()->layer(); -} - -// Returns true if the window is in the app list window container. -bool IsAppListWindow(WmWindow* window) { - return window->GetParent() && - window->GetParent()->GetShellWindowId() == - kShellWindowId_AppListContainer; -} - -} // namespace - -// ShelfLayoutManager::UpdateShelfObserver ------------------------------------- - -// UpdateShelfObserver is used to delay updating the background until the -// animation completes. -class ShelfLayoutManager::UpdateShelfObserver - : public ui::ImplicitAnimationObserver { - public: - explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) { - shelf_->update_shelf_observer_ = this; - } - - void Detach() { shelf_ = NULL; } - - void OnImplicitAnimationsCompleted() override { - if (shelf_) - shelf_->MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); - delete this; - } - - private: - ~UpdateShelfObserver() override { - if (shelf_) - shelf_->update_shelf_observer_ = NULL; - } - - // Shelf we're in. NULL if deleted before we're deleted. - ShelfLayoutManager* shelf_; - - DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver); -}; - -ShelfLayoutManager::State::State() - : visibility_state(SHELF_VISIBLE), - auto_hide_state(SHELF_AUTO_HIDE_HIDDEN), - window_state(wm::WORKSPACE_WINDOW_STATE_DEFAULT), - pre_lock_screen_animation_active(false), - session_state(session_manager::SessionState::UNKNOWN) {} - -bool ShelfLayoutManager::State::IsAddingSecondaryUser() const { - return session_state == session_manager::SessionState::LOGIN_SECONDARY; -} - -bool ShelfLayoutManager::State::IsScreenLocked() const { - return session_state == session_manager::SessionState::LOCKED; -} - -bool ShelfLayoutManager::State::Equals(const State& other) const { - return other.visibility_state == visibility_state && - (visibility_state != SHELF_AUTO_HIDE || - other.auto_hide_state == auto_hide_state) && - other.window_state == window_state && - other.pre_lock_screen_animation_active == - pre_lock_screen_animation_active && - other.session_state == session_state; -} - -// ShelfLayoutManager ---------------------------------------------------------- - -ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf_widget, - WmShelf* wm_shelf) - : updating_bounds_(false), - shelf_widget_(shelf_widget), - wm_shelf_(wm_shelf), - window_overlaps_shelf_(false), - mouse_over_shelf_when_auto_hide_timer_started_(false), - gesture_drag_status_(GESTURE_DRAG_NONE), - gesture_drag_amount_(0.f), - gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN), - update_shelf_observer_(NULL), - chromevox_panel_height_(0), - duration_override_in_ms_(0), - shelf_background_type_(SHELF_BACKGROUND_OVERLAP) { - DCHECK(shelf_widget_); - DCHECK(wm_shelf_); - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->AddLockStateObserver(this); - WmShell::Get()->AddActivationObserver(this); - WmShell::Get()->session_controller()->AddSessionStateObserver(this); - state_.session_state = - WmShell::Get()->session_controller()->GetSessionState(); -} - -ShelfLayoutManager::~ShelfLayoutManager() { - if (update_shelf_observer_) - update_shelf_observer_->Detach(); - - for (auto& observer : observers_) - observer.WillDeleteShelfLayoutManager(); - WmShell::Get()->RemoveShellObserver(this); - WmShell::Get()->RemoveLockStateObserver(this); - WmShell::Get()->session_controller()->RemoveSessionStateObserver(this); -} - -void ShelfLayoutManager::PrepareForShutdown() { - in_shutdown_ = true; - // Stop observing changes to avoid updating a partially destructed shelf. - WmShell::Get()->RemoveActivationObserver(this); -} - -bool ShelfLayoutManager::IsVisible() const { - // status_area_widget() may be NULL during the shutdown. - return shelf_widget_->status_area_widget() && - shelf_widget_->status_area_widget()->IsVisible() && - (state_.visibility_state == SHELF_VISIBLE || - (state_.visibility_state == SHELF_AUTO_HIDE && - state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN)); -} - -gfx::Rect ShelfLayoutManager::GetIdealBounds() { - const int shelf_size = GetShelfConstant(SHELF_SIZE); - WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - gfx::Rect rect(wm::GetDisplayBoundsInParent(shelf_window)); - return SelectValueForShelfAlignment( - gfx::Rect(rect.x(), rect.bottom() - shelf_size, rect.width(), shelf_size), - gfx::Rect(rect.x(), rect.y(), shelf_size, rect.height()), - gfx::Rect(rect.right() - shelf_size, rect.y(), shelf_size, - rect.height())); -} - -gfx::Size ShelfLayoutManager::GetPreferredSize() { - TargetBounds target_bounds; - CalculateTargetBounds(state_, &target_bounds); - return target_bounds.shelf_bounds_in_root.size(); -} - -void ShelfLayoutManager::LayoutShelfAndUpdateBounds(bool change_work_area) { - TargetBounds target_bounds; - CalculateTargetBounds(state_, &target_bounds); - UpdateBoundsAndOpacity(target_bounds, false, change_work_area, NULL); - - // Update insets in ShelfWindowTargeter when shelf bounds change. - for (auto& observer : observers_) - observer.WillChangeVisibilityState(visibility_state()); -} - -void ShelfLayoutManager::LayoutShelf() { - LayoutShelfAndUpdateBounds(true); -} - -ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() { - switch (wm_shelf_->auto_hide_behavior()) { - case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS: - return SHELF_AUTO_HIDE; - case SHELF_AUTO_HIDE_BEHAVIOR_NEVER: - return SHELF_VISIBLE; - case SHELF_AUTO_HIDE_ALWAYS_HIDDEN: - return SHELF_HIDDEN; - } - return SHELF_VISIBLE; -} - -void ShelfLayoutManager::UpdateVisibilityState() { - // Bail out early before the shelf is initialized or after it is destroyed. - WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - if (in_shutdown_ || !wm_shelf_->IsShelfInitialized() || !shelf_window) - return; - if (state_.IsScreenLocked() || state_.IsAddingSecondaryUser()) { - SetState(SHELF_VISIBLE); - } else if (WmShell::Get()->IsPinned()) { - SetState(SHELF_HIDDEN); - } else { - // TODO(zelidrag): Verify shelf drag animation still shows on the device - // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN. - wm::WorkspaceWindowState window_state( - shelf_window->GetRootWindowController()->GetWorkspaceWindowState()); - switch (window_state) { - case wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN: { - if (IsShelfHiddenForFullscreen()) { - SetState(SHELF_HIDDEN); - } else { - // The shelf is sometimes not hidden when in immersive fullscreen. - // Force the shelf to be auto hidden in this case. - SetState(SHELF_AUTO_HIDE); - } - break; - } - case wm::WORKSPACE_WINDOW_STATE_MAXIMIZED: - SetState(CalculateShelfVisibility()); - break; - - case wm::WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF: - case wm::WORKSPACE_WINDOW_STATE_DEFAULT: - SetState(CalculateShelfVisibility()); - SetWindowOverlapsShelf( - window_state == wm::WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF); - break; - } - } -} - -void ShelfLayoutManager::UpdateAutoHideState() { - ShelfAutoHideState auto_hide_state = - CalculateAutoHideState(state_.visibility_state); - if (auto_hide_state != state_.auto_hide_state) { - if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) { - // Hides happen immediately. - SetState(state_.visibility_state); - } else { - if (!auto_hide_timer_.IsRunning()) { - mouse_over_shelf_when_auto_hide_timer_started_ = - shelf_widget_->GetWindowBoundsInScreen().Contains( - display::Screen::GetScreen()->GetCursorScreenPoint()); - } - auto_hide_timer_.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(kAutoHideDelayMS), this, - &ShelfLayoutManager::UpdateAutoHideStateNow); - } - } else { - StopAutoHideTimer(); - } -} - -void ShelfLayoutManager::UpdateAutoHideForMouseEvent(ui::MouseEvent* event, - WmWindow* target) { - // This also checks IsShelfWindow() to make sure we don't attempt to hide the - // shelf if the mouse down occurs on the shelf. - in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED || - (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED && - event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) && - !IsShelfWindow(target); - - // Don't update during shutdown because synthetic mouse events (e.g. mouse - // exit) may be generated during status area widget teardown. - if (visibility_state() != SHELF_AUTO_HIDE || in_shutdown_) - return; - - if (event->type() == ui::ET_MOUSE_MOVED || - event->type() == ui::ET_MOUSE_ENTERED || - event->type() == ui::ET_MOUSE_EXITED) { - UpdateAutoHideState(); - } -} - -void ShelfLayoutManager::UpdateAutoHideForGestureEvent(ui::GestureEvent* event, - WmWindow* target) { - if (visibility_state() != SHELF_AUTO_HIDE || in_shutdown_) - return; - - if (IsShelfWindow(target) && ProcessGestureEvent(*event)) - event->StopPropagation(); -} - -void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) { - window_overlaps_shelf_ = value; - MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); -} - -void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) { - observers_.AddObserver(observer); -} - -void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) { - observers_.RemoveObserver(observer); -} - -bool ShelfLayoutManager::ProcessGestureEvent(const ui::GestureEvent& event) { - // The gestures are disabled in the lock/login screen. - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - if (!delegate->NumberOfLoggedInUsers() || delegate->IsScreenLocked()) - return false; - - if (IsShelfHiddenForFullscreen()) - return false; - - if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN) { - StartGestureDrag(event); - return true; - } - - if (gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) - return false; - - if (event.type() == ui::ET_GESTURE_SCROLL_UPDATE) { - UpdateGestureDrag(event); - return true; - } - - if (event.type() == ui::ET_GESTURE_SCROLL_END || - event.type() == ui::ET_SCROLL_FLING_START) { - CompleteGestureDrag(event); - return true; - } - - // Unexpected event. Reset the state and let the event fall through. - CancelGestureDrag(); - return false; -} - -void ShelfLayoutManager::SetAnimationDurationOverride( - int duration_override_in_ms) { - duration_override_in_ms_ = duration_override_in_ms; -} - -//////////////////////////////////////////////////////////////////////////////// -// ShelfLayoutManager, wm::WmSnapToPixelLayoutManager implementation: - -void ShelfLayoutManager::OnWindowResized() { - LayoutShelf(); -} - -void ShelfLayoutManager::SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) { - wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); - // We may contain other widgets (such as frame maximize bubble) but they don't - // effect the layout in anyway. - if (!updating_bounds_ && - ((WmWindow::Get(shelf_widget_->GetNativeWindow()) == child) || - (WmWindow::Get(shelf_widget_->status_area_widget()->GetNativeWindow()) == - child))) { - LayoutShelf(); - } -} - -void ShelfLayoutManager::OnShelfAutoHideBehaviorChanged(WmWindow* root_window) { - UpdateVisibilityState(); -} - -void ShelfLayoutManager::OnPinnedStateChanged(WmWindow* pinned_window) { - // Shelf needs to be hidden on entering to pinned mode, or restored - // on exiting from pinned mode. - UpdateVisibilityState(); -} - -void ShelfLayoutManager::OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) { - UpdateAutoHideStateNow(); -} - -void ShelfLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) { - bool keyboard_is_about_to_hide = false; - if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty()) - keyboard_is_about_to_hide = true; - // If new window behavior flag enabled and in non-sticky mode, do not change - // the work area. - bool change_work_area = - (!base::CommandLine::ForCurrentProcess()->HasSwitch( - ::switches::kUseNewVirtualKeyboardBehavior) || - keyboard::KeyboardController::GetInstance()->keyboard_locked()); - - keyboard_bounds_ = new_bounds; - LayoutShelfAndUpdateBounds(change_work_area); - - // On login screen if keyboard has been just hidden, update bounds just once - // but ignore target_bounds.work_area_insets since shelf overlaps with login - // window. - if (WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked() && - keyboard_is_about_to_hide) { - WmWindow* window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets()); - } -} - -void ShelfLayoutManager::OnKeyboardClosed() {} - -ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const { - if (state_.pre_lock_screen_animation_active) - return SHELF_BACKGROUND_DEFAULT; - - // Handle all non active screen states, including OOBE and pre-login. - if (state_.session_state != session_manager::SessionState::ACTIVE) - return SHELF_BACKGROUND_OVERLAP; - - if (state_.visibility_state != SHELF_AUTO_HIDE && - state_.window_state == wm::WORKSPACE_WINDOW_STATE_MAXIMIZED) { - return SHELF_BACKGROUND_MAXIMIZED; - } - - if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS || - window_overlaps_shelf_ || state_.visibility_state == SHELF_AUTO_HIDE) { - return SHELF_BACKGROUND_OVERLAP; - } - - return SHELF_BACKGROUND_DEFAULT; -} - -void ShelfLayoutManager::SetChromeVoxPanelHeight(int height) { - chromevox_panel_height_ = height; - LayoutShelf(); -} - -//////////////////////////////////////////////////////////////////////////////// -// ShelfLayoutManager, private: - -ShelfLayoutManager::TargetBounds::TargetBounds() - : opacity(0.0f), status_opacity(0.0f) {} - -ShelfLayoutManager::TargetBounds::~TargetBounds() {} - -void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) { - State state; - state.visibility_state = visibility_state; - state.auto_hide_state = CalculateAutoHideState(visibility_state); - - WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - RootWindowController* controller = shelf_window->GetRootWindowController(); - state.window_state = controller ? controller->GetWorkspaceWindowState() - : wm::WORKSPACE_WINDOW_STATE_DEFAULT; - // Preserve the log in screen states. - state.session_state = state_.session_state; - state.pre_lock_screen_animation_active = - state_.pre_lock_screen_animation_active; - - // Force an update because gesture drags affect the shelf bounds and we - // should animate back to the normal bounds at the end of a gesture. - bool force_update = - (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS || - gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS); - - if (!force_update && state_.Equals(state)) - return; // Nothing changed. - - for (auto& observer : observers_) - observer.WillChangeVisibilityState(visibility_state); - - StopAutoHideTimer(); - - State old_state = state_; - state_ = state; - - AnimationChangeType change_type = AnimationChangeType::ANIMATE; - bool delay_background_change = false; - - // Do not animate the background when: - // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf - // in maximized mode. - // - Going from an auto hidden shelf in maximized mode to a visible shelf in - // maximized mode. - if (state.visibility_state == SHELF_VISIBLE && - state.window_state == wm::WORKSPACE_WINDOW_STATE_MAXIMIZED && - old_state.visibility_state != SHELF_VISIBLE) { - change_type = AnimationChangeType::IMMEDIATE; - } else { - // Delay the animation when the shelf was hidden, and has just been made - // visible (e.g. using a gesture-drag). - if (state.visibility_state == SHELF_VISIBLE && - old_state.visibility_state == SHELF_AUTO_HIDE && - old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) { - delay_background_change = true; - } - } - - if (delay_background_change) { - if (update_shelf_observer_) - update_shelf_observer_->Detach(); - // |update_shelf_observer_| deletes itself when the animation is done. - update_shelf_observer_ = new UpdateShelfObserver(this); - } else { - MaybeUpdateShelfBackground(change_type); - } - - TargetBounds target_bounds; - CalculateTargetBounds(state_, &target_bounds); - UpdateBoundsAndOpacity( - target_bounds, true /* animate */, true /* change_work_area */, - delay_background_change ? update_shelf_observer_ : NULL); - - // OnAutoHideStateChanged Should be emitted when: - // - firstly state changed to auto-hide from other state - // - or, auto_hide_state has changed - if ((old_state.visibility_state != state_.visibility_state && - state_.visibility_state == SHELF_AUTO_HIDE) || - old_state.auto_hide_state != state_.auto_hide_state) { - for (auto& observer : observers_) - observer.OnAutoHideStateChanged(state_.auto_hide_state); - } -} - -void ShelfLayoutManager::UpdateBoundsAndOpacity( - const TargetBounds& target_bounds, - bool animate, - bool change_work_area, - ui::ImplicitAnimationObserver* observer) { - base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true); - { - ui::ScopedLayerAnimationSettings shelf_animation_setter( - GetLayer(shelf_widget_)->GetAnimator()); - ui::ScopedLayerAnimationSettings status_animation_setter( - GetLayer(shelf_widget_->status_area_widget())->GetAnimator()); - if (animate) { - int duration = duration_override_in_ms_ ? duration_override_in_ms_ - : kAnimationDurationMS; - shelf_animation_setter.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(duration)); - shelf_animation_setter.SetTweenType(gfx::Tween::EASE_OUT); - shelf_animation_setter.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - status_animation_setter.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(duration)); - status_animation_setter.SetTweenType(gfx::Tween::EASE_OUT); - status_animation_setter.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - } else { - StopAnimating(); - shelf_animation_setter.SetTransitionDuration(base::TimeDelta()); - status_animation_setter.SetTransitionDuration(base::TimeDelta()); - } - if (observer) - status_animation_setter.AddObserver(observer); - - GetLayer(shelf_widget_)->SetOpacity(target_bounds.opacity); - WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - shelf_widget_->SetBounds(shelf_window->GetParent()->ConvertRectToScreen( - target_bounds.shelf_bounds_in_root)); - - GetLayer(shelf_widget_->status_area_widget()) - ->SetOpacity(target_bounds.status_opacity); - - // Having a window which is visible but does not have an opacity is an - // illegal state. We therefore hide the shelf here if required. - if (!target_bounds.status_opacity) - shelf_widget_->status_area_widget()->Hide(); - // Setting visibility during an animation causes the visibility property to - // animate. Override the animation settings to immediately set the - // visibility property. Opacity will still animate. - - // TODO(harrym): Once status area widget is a child view of shelf - // this can be simplified. - gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf; - status_bounds.Offset(target_bounds.shelf_bounds_in_root.OffsetFromOrigin()); - WmWindow* status_window = - WmWindow::Get(shelf_widget_->status_area_widget()->GetNativeWindow()); - shelf_widget_->status_area_widget()->SetBounds( - status_window->GetParent()->ConvertRectToScreen(status_bounds)); - - // For crbug.com/622431, when the shelf alignment is BOTTOM_LOCKED, we - // don't set display work area, as it is not real user-set alignment. - if (!state_.IsScreenLocked() && - wm_shelf_->GetAlignment() != SHELF_ALIGNMENT_BOTTOM_LOCKED && - change_work_area) { - gfx::Insets insets; - // If user session is blocked (login to new user session or add user to - // the existing session - multi-profile) then give 100% of work area only - // if keyboard is not shown. - if (!state_.IsAddingSecondaryUser() || !keyboard_bounds_.IsEmpty()) - insets = target_bounds.work_area_insets; - WmShell::Get()->SetDisplayWorkAreaInsets(shelf_window, insets); - } - } - - // Set an empty border to avoid the shelf view and status area overlapping. - // TODO(msw): Avoid setting bounds of views within the shelf widget here. - gfx::Rect shelf_bounds = gfx::Rect(target_bounds.shelf_bounds_in_root.size()); - shelf_widget_->GetContentsView()->SetBorder(views::CreateEmptyBorder( - shelf_bounds.InsetsFrom(target_bounds.shelf_bounds_in_shelf))); - shelf_widget_->GetContentsView()->Layout(); - - // Setting visibility during an animation causes the visibility property to - // animate. Set the visibility property without an animation. - if (target_bounds.status_opacity) - shelf_widget_->status_area_widget()->Show(); -} - -void ShelfLayoutManager::StopAnimating() { - GetLayer(shelf_widget_)->GetAnimator()->StopAnimating(); - GetLayer(shelf_widget_->status_area_widget())->GetAnimator()->StopAnimating(); -} - -void ShelfLayoutManager::CalculateTargetBounds(const State& state, - TargetBounds* target_bounds) { - int shelf_size = GetShelfConstant(SHELF_SIZE); - if (state.visibility_state == SHELF_AUTO_HIDE && - state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) { - // Auto-hidden shelf always starts with the default size. If a gesture-drag - // is in progress, then the call to UpdateTargetBoundsForGesture() below - // takes care of setting the height properly. - shelf_size = kShelfAutoHideSize; - } else if (state.visibility_state == SHELF_HIDDEN || - (!keyboard_bounds_.IsEmpty() && - !keyboard::IsKeyboardOverscrollEnabled())) { - shelf_size = 0; - } - - WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - gfx::Rect available_bounds = wm::GetDisplayBoundsWithShelf(shelf_window); - available_bounds.Inset(0, chromevox_panel_height_, 0, 0); - int shelf_width = PrimaryAxisValue(available_bounds.width(), shelf_size); - int shelf_height = PrimaryAxisValue(shelf_size, available_bounds.height()); - int bottom_shelf_vertical_offset = available_bounds.bottom(); - if (keyboard_bounds_.IsEmpty()) - bottom_shelf_vertical_offset -= shelf_height; - else - bottom_shelf_vertical_offset -= keyboard_bounds_.height(); - - gfx::Point shelf_origin = SelectValueForShelfAlignment( - gfx::Point(available_bounds.x(), bottom_shelf_vertical_offset), - gfx::Point(available_bounds.x(), available_bounds.y()), - gfx::Point(available_bounds.right() - shelf_width, available_bounds.y())); - target_bounds->shelf_bounds_in_root = - gfx::Rect(shelf_origin.x(), shelf_origin.y(), shelf_width, shelf_height); - - gfx::Size status_size( - shelf_widget_->status_area_widget()->GetWindowBoundsInScreen().size()); - if (wm_shelf_->IsHorizontalAlignment()) - status_size.set_height(GetShelfConstant(SHELF_SIZE)); - else - status_size.set_width(GetShelfConstant(SHELF_SIZE)); - - gfx::Point status_origin = SelectValueForShelfAlignment( - gfx::Point(0, 0), gfx::Point(shelf_width - status_size.width(), - shelf_height - status_size.height()), - gfx::Point(0, shelf_height - status_size.height())); - if (wm_shelf_->IsHorizontalAlignment() && !base::i18n::IsRTL()) - status_origin.set_x(shelf_width - status_size.width()); - target_bounds->status_bounds_in_shelf = gfx::Rect(status_origin, status_size); - - target_bounds->work_area_insets = SelectValueForShelfAlignment( - gfx::Insets(0, 0, GetWorkAreaInsets(state, shelf_height), 0), - gfx::Insets(0, GetWorkAreaInsets(state, shelf_width), 0, 0), - gfx::Insets(0, 0, 0, GetWorkAreaInsets(state, shelf_width))); - - // TODO(varkha): The functionality of managing insets for display areas - // should probably be pushed to a separate component. This would simplify or - // remove entirely the dependency on keyboard and dock. - - if (!keyboard_bounds_.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()) { - // Also push in the work area inset for the keyboard if it is visible. - gfx::Insets keyboard_insets(0, 0, keyboard_bounds_.height(), 0); - target_bounds->work_area_insets += keyboard_insets; - } - - // Also push in the work area inset for the dock if it is visible. - if (!dock_bounds_.IsEmpty()) { - gfx::Insets dock_insets( - 0, (dock_bounds_.x() > 0 ? 0 : dock_bounds_.width()), 0, - (dock_bounds_.x() > 0 ? dock_bounds_.width() : 0)); - target_bounds->work_area_insets += dock_insets; - } - - // Also push in the work area insets for the ChromeVox panel if it's visible. - if (chromevox_panel_height_) { - gfx::Insets chromevox_insets(chromevox_panel_height_, 0, 0, 0); - target_bounds->work_area_insets += chromevox_insets; - } - - target_bounds->opacity = ComputeTargetOpacity(state); - target_bounds->status_opacity = - (state.visibility_state == SHELF_AUTO_HIDE && - state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN && - gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) - ? 0.0f - : target_bounds->opacity; - - if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS) - UpdateTargetBoundsForGesture(target_bounds); - - // This needs to happen after calling UpdateTargetBoundsForGesture(), because - // that can change the size of the shelf. - target_bounds->shelf_bounds_in_shelf = SelectValueForShelfAlignment( - gfx::Rect(0, 0, shelf_width - status_size.width(), - target_bounds->shelf_bounds_in_root.height()), - gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(), - shelf_height - status_size.height()), - gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(), - shelf_height - status_size.height())); - - available_bounds.Subtract(target_bounds->shelf_bounds_in_root); - available_bounds.Subtract(keyboard_bounds_); - - WmWindow* root = shelf_window->GetRootWindow(); - user_work_area_bounds_ = root->ConvertRectToScreen(available_bounds); -} - -void ShelfLayoutManager::UpdateTargetBoundsForGesture( - TargetBounds* target_bounds) const { - CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_); - bool horizontal = wm_shelf_->IsHorizontalAlignment(); - WmWindow* window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - gfx::Rect available_bounds = wm::GetDisplayBoundsWithShelf(window); - int resistance_free_region = 0; - - if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN && - visibility_state() == SHELF_AUTO_HIDE && - auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) { - // If the shelf was hidden when the drag started (and the state hasn't - // changed since then, e.g. because the tray-menu was shown because of the - // drag), then allow the drag some resistance-free region at first to make - // sure the shelf sticks with the finger until the shelf is visible. - resistance_free_region = GetShelfConstant(SHELF_SIZE) - kShelfAutoHideSize; - } - - bool resist = SelectValueForShelfAlignment( - gesture_drag_amount_<-resistance_free_region, gesture_drag_amount_> - resistance_free_region, - gesture_drag_amount_ < -resistance_free_region); - - float translate = 0.f; - if (resist) { - float diff = fabsf(gesture_drag_amount_) - resistance_free_region; - diff = std::min(diff, sqrtf(diff)); - if (gesture_drag_amount_ < 0) - translate = -resistance_free_region - diff; - else - translate = resistance_free_region + diff; - } else { - translate = gesture_drag_amount_; - } - int shelf_insets = GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE); - if (horizontal) { - // Move and size the shelf with the gesture. - int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate; - shelf_height = std::max(shelf_height, shelf_insets); - target_bounds->shelf_bounds_in_root.set_height(shelf_height); - if (wm_shelf_->IsHorizontalAlignment()) { - target_bounds->shelf_bounds_in_root.set_y(available_bounds.bottom() - - shelf_height); - } - - target_bounds->status_bounds_in_shelf.set_y(0); - } else { - // Move and size the shelf with the gesture. - int shelf_width = target_bounds->shelf_bounds_in_root.width(); - bool right_aligned = wm_shelf_->GetAlignment() == SHELF_ALIGNMENT_RIGHT; - if (right_aligned) - shelf_width -= translate; - else - shelf_width += translate; - shelf_width = std::max(shelf_width, shelf_insets); - target_bounds->shelf_bounds_in_root.set_width(shelf_width); - if (right_aligned) { - target_bounds->shelf_bounds_in_root.set_x(available_bounds.right() - - shelf_width); - } - - if (right_aligned) { - target_bounds->status_bounds_in_shelf.set_x(0); - } else { - target_bounds->status_bounds_in_shelf.set_x( - target_bounds->shelf_bounds_in_root.width() - - GetShelfConstant(SHELF_SIZE)); - } - } -} - -void ShelfLayoutManager::MaybeUpdateShelfBackground(AnimationChangeType type) { - const ShelfBackgroundType new_background_type(GetShelfBackgroundType()); - - if (new_background_type == shelf_background_type_) - return; - - shelf_background_type_ = new_background_type; - for (auto& observer : observers_) - observer.OnBackgroundUpdated(shelf_background_type_, type); -} - -void ShelfLayoutManager::UpdateAutoHideStateNow() { - SetState(state_.visibility_state); - - // If the state did not change, the auto hide timer may still be running. - StopAutoHideTimer(); -} - -void ShelfLayoutManager::StopAutoHideTimer() { - auto_hide_timer_.Stop(); - mouse_over_shelf_when_auto_hide_timer_started_ = false; -} - -gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const { - gfx::Rect shelf_bounds_in_screen = shelf_widget_->GetWindowBoundsInScreen(); - gfx::Vector2d offset = SelectValueForShelfAlignment( - gfx::Vector2d(0, shelf_bounds_in_screen.height()), - gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0), - gfx::Vector2d(shelf_bounds_in_screen.width(), 0)); - - gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen; - show_shelf_region_in_screen += offset; - if (wm_shelf_->IsHorizontalAlignment()) - show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize); - else - show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize); - - // TODO: Figure out if we need any special handling when the keyboard is - // visible. - return show_shelf_region_in_screen; -} - -ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState( - ShelfVisibilityState visibility_state) const { - if (visibility_state != SHELF_AUTO_HIDE || !wm_shelf_->IsShelfInitialized()) - return SHELF_AUTO_HIDE_HIDDEN; - - if (shelf_widget_->IsShowingAppList()) - return SHELF_AUTO_HIDE_SHOWN; - - if (shelf_widget_->status_area_widget() && - shelf_widget_->status_area_widget()->ShouldShowShelf()) - return SHELF_AUTO_HIDE_SHOWN; - - if (shelf_widget_->IsShowingContextMenu()) - return SHELF_AUTO_HIDE_SHOWN; - - if (shelf_widget_->IsShowingOverflowBubble()) - return SHELF_AUTO_HIDE_SHOWN; - - if (shelf_widget_->IsActive() || - (shelf_widget_->status_area_widget() && - shelf_widget_->status_area_widget()->IsActive())) - return SHELF_AUTO_HIDE_SHOWN; - - const int64_t shelf_display_id = - WmWindow::Get(shelf_widget_->GetNativeWindow()) - ->GetDisplayNearestWindow() - .id(); - const std::vector<WmWindow*> windows = - WmShell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal(); - // Process the window list and check if there are any visible windows. - // Ignore app list windows that may be animating to hide after dismissal. - bool visible_window = false; - for (size_t i = 0; i < windows.size(); ++i) { - if (windows[i] && windows[i]->IsVisible() && !IsAppListWindow(windows[i]) && - !windows[i]->GetWindowState()->IsMinimized() && - windows[i]->GetDisplayNearestWindow().id() == shelf_display_id) { - visible_window = true; - break; - } - } - // If there are no visible windows do not hide the shelf. - if (!visible_window) - return SHELF_AUTO_HIDE_SHOWN; - - if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS) - return gesture_drag_auto_hide_state_; - - // Don't show if the user is dragging the mouse. - if (in_mouse_drag_) - return SHELF_AUTO_HIDE_HIDDEN; - - // Ignore the mouse position if mouse events are disabled. - if (!shelf_widget_->IsMouseEventsEnabled()) - return SHELF_AUTO_HIDE_HIDDEN; - - gfx::Rect shelf_region = shelf_widget_->GetWindowBoundsInScreen(); - if (shelf_widget_->status_area_widget() && - shelf_widget_->status_area_widget()->IsMessageBubbleShown() && - IsVisible()) { - // Increase the the hit test area to prevent the shelf from disappearing - // when the mouse is over the bubble gap. - ShelfAlignment alignment = wm_shelf_->GetAlignment(); - shelf_region.Inset( - alignment == SHELF_ALIGNMENT_RIGHT ? -kNotificationBubbleGapHeight : 0, - wm_shelf_->IsHorizontalAlignment() ? -kNotificationBubbleGapHeight : 0, - alignment == SHELF_ALIGNMENT_LEFT ? -kNotificationBubbleGapHeight : 0, - 0); - } - - gfx::Point cursor_position_in_screen = - display::Screen::GetScreen()->GetCursorScreenPoint(); - if (shelf_region.Contains(cursor_position_in_screen)) - return SHELF_AUTO_HIDE_SHOWN; - - // When the shelf is auto hidden and the shelf is on the boundary between two - // displays, it is hard to trigger showing the shelf. For instance, if a - // user's primary display is left of their secondary display, it is hard to - // unautohide a left aligned shelf on the secondary display. - // It is hard because: - // - It is hard to stop the cursor in the shelf "light bar" and not overshoot. - // - The cursor is warped to the other display if the cursor gets to the edge - // of the display. - // Show the shelf if the cursor started on the shelf and the user overshot the - // shelf slightly to make it easier to show the shelf in this situation. We - // do not check |auto_hide_timer_|.IsRunning() because it returns false when - // the timer's task is running. - if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN || - mouse_over_shelf_when_auto_hide_timer_started_) && - GetAutoHideShowShelfRegionInScreen().Contains( - cursor_position_in_screen)) { - return SHELF_AUTO_HIDE_SHOWN; - } - - return SHELF_AUTO_HIDE_HIDDEN; -} - -bool ShelfLayoutManager::IsShelfWindow(WmWindow* window) { - if (!window) - return false; - WmWindow* shelf_window = WmWindow::Get(shelf_widget_->GetNativeWindow()); - WmWindow* status_window = - WmWindow::Get(shelf_widget_->status_area_widget()->GetNativeWindow()); - return (shelf_window && shelf_window->Contains(window)) || - (status_window && status_window->Contains(window)); -} - -int ShelfLayoutManager::GetWorkAreaInsets(const State& state, int size) const { - if (state.visibility_state == SHELF_VISIBLE) - return size; - if (state.visibility_state == SHELF_AUTO_HIDE) - return GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE); - return 0; -} - -void ShelfLayoutManager::OnDockBoundsChanging( - const gfx::Rect& dock_bounds, - DockedWindowLayoutManagerObserver::Reason reason) { - // Skip shelf layout in case docked notification originates from this class. - if (reason == DISPLAY_INSETS_CHANGED) - return; - if (dock_bounds_ != dock_bounds) { - dock_bounds_ = dock_bounds; - OnWindowResized(); - UpdateVisibilityState(); - MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); - } -} - -void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event) { - if (event == EVENT_LOCK_ANIMATION_STARTED) { - // Enter the screen locked state and update the visibility to avoid an odd - // animation when transitioning the orientation from L/R to bottom. - state_.pre_lock_screen_animation_active = true; - UpdateShelfVisibilityAfterLoginUIChange(); - } else { - state_.pre_lock_screen_animation_active = false; - } - MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); -} - -void ShelfLayoutManager::SessionStateChanged( - session_manager::SessionState state) { - // Check transition changes to/from the add user to session and change the - // shelf alignment accordingly - const bool was_adding_user = state_.IsAddingSecondaryUser(); - const bool was_locked = state_.IsScreenLocked(); - state_.session_state = state; - MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); - if (was_adding_user != state_.IsAddingSecondaryUser()) { - UpdateShelfVisibilityAfterLoginUIChange(); - return; - } - - // Force the shelf to layout for alignment (bottom if locked, restore the - // previous alignment otherwise). - if (was_locked != state_.IsScreenLocked()) - UpdateShelfVisibilityAfterLoginUIChange(); - - TargetBounds target_bounds; - CalculateTargetBounds(state_, &target_bounds); - UpdateBoundsAndOpacity(target_bounds, true /* animate */, - true /* change_work_area */, NULL); - UpdateVisibilityState(); -} - -void ShelfLayoutManager::UpdateShelfVisibilityAfterLoginUIChange() { - UpdateVisibilityState(); - LayoutShelf(); -} - -float ShelfLayoutManager::ComputeTargetOpacity(const State& state) { - if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS || - state.visibility_state == SHELF_VISIBLE) { - return 1.0f; - } - // In Chrome OS Material Design, when shelf is hidden during auto hide state, - // target bounds are also hidden. So the window can extend to the edge of - // screen. - return (state.visibility_state == SHELF_AUTO_HIDE && - state.auto_hide_state == SHELF_AUTO_HIDE_SHOWN) - ? 1.0f - : 0.0f; -} - -bool ShelfLayoutManager::IsShelfHiddenForFullscreen() const { - const WmWindow* fullscreen_window = wm::GetWindowForFullscreenMode( - WmWindow::Get(shelf_widget_->GetNativeWindow())); - return fullscreen_window && - fullscreen_window->GetWindowState()->hide_shelf_when_fullscreen(); -} - -//////////////////////////////////////////////////////////////////////////////// -// ShelfLayoutManager, Gesture functions: - -void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) { - gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS; - gesture_drag_amount_ = 0.f; - gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE - ? auto_hide_state() - : SHELF_AUTO_HIDE_SHOWN; - MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE); -} - -void ShelfLayoutManager::UpdateGestureDrag(const ui::GestureEvent& gesture) { - gesture_drag_amount_ += PrimaryAxisValue(gesture.details().scroll_y(), - gesture.details().scroll_x()); - LayoutShelf(); -} - -void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) { - bool horizontal = wm_shelf_->IsHorizontalAlignment(); - bool should_change = false; - if (gesture.type() == ui::ET_GESTURE_SCROLL_END) { - // The visibility of the shelf changes only if the shelf was dragged X% - // along the correct axis. If the shelf was already visible, then the - // direction of the drag does not matter. - const float kDragHideThreshold = 0.4f; - gfx::Rect bounds = GetIdealBounds(); - float drag_ratio = fabs(gesture_drag_amount_) / - (horizontal ? bounds.height() : bounds.width()); - if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) { - should_change = drag_ratio > kDragHideThreshold; - } else { - bool correct_direction = false; - switch (wm_shelf_->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - case SHELF_ALIGNMENT_RIGHT: - correct_direction = gesture_drag_amount_ < 0; - break; - case SHELF_ALIGNMENT_LEFT: - correct_direction = gesture_drag_amount_ > 0; - break; - } - should_change = correct_direction && drag_ratio > kDragHideThreshold; - } - } else if (gesture.type() == ui::ET_SCROLL_FLING_START) { - if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) { - should_change = horizontal ? fabs(gesture.details().velocity_y()) > 0 - : fabs(gesture.details().velocity_x()) > 0; - } else { - should_change = - SelectValueForShelfAlignment(gesture.details().velocity_y() < 0, - gesture.details().velocity_x() > 0, - gesture.details().velocity_x() < 0); - } - } else { - NOTREACHED(); - } - - if (!should_change) { - CancelGestureDrag(); - return; - } - - shelf_widget_->Deactivate(); - shelf_widget_->status_area_widget()->Deactivate(); - - gesture_drag_auto_hide_state_ = - gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN - ? SHELF_AUTO_HIDE_HIDDEN - : SHELF_AUTO_HIDE_SHOWN; - ShelfAutoHideBehavior new_auto_hide_behavior = - gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN - ? SHELF_AUTO_HIDE_BEHAVIOR_NEVER - : SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS; - - // When in fullscreen and the shelf is forced to be auto hidden, the auto hide - // behavior affects neither the visibility state nor the auto hide state. Set - // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto - // hide state to |gesture_drag_auto_hide_state_|. - gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS; - if (wm_shelf_->auto_hide_behavior() != new_auto_hide_behavior) - wm_shelf_->SetAutoHideBehavior(new_auto_hide_behavior); - else - UpdateVisibilityState(); - gesture_drag_status_ = GESTURE_DRAG_NONE; -} - -void ShelfLayoutManager::CancelGestureDrag() { - gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS; - UpdateVisibilityState(); - gesture_drag_status_ = GESTURE_DRAG_NONE; -} - -} // namespace ash
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h deleted file mode 100644 index 505cf0e..0000000 --- a/ash/shelf/shelf_layout_manager.h +++ /dev/null
@@ -1,365 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_LAYOUT_MANAGER_H_ -#define ASH_SHELF_SHELF_LAYOUT_MANAGER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/session/session_state_observer.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_activation_observer.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/dock/docked_window_layout_manager_observer.h" -#include "ash/wm/lock_state_observer.h" -#include "ash/wm/wm_snap_to_pixel_layout_manager.h" -#include "ash/wm/workspace/workspace_types.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/timer/timer.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace ui { -class ImplicitAnimationObserver; -class MouseEvent; -} - -namespace ash { - -enum class AnimationChangeType; -class PanelLayoutManagerTest; -class ShelfLayoutManagerObserver; -class ShelfLayoutManagerTest; -class ShelfWidget; -class WmShelf; - -// ShelfLayoutManager is the layout manager responsible for the shelf and -// status widgets. The shelf is given the total available width and told the -// width of the status area. This allows the shelf to draw the background and -// layout to the status area. -// To respond to bounds changes in the status area StatusAreaLayoutManager works -// closely with ShelfLayoutManager. -// On mus, widget bounds management is handled by the window manager. -class ASH_EXPORT ShelfLayoutManager - : public ShellObserver, - public WmActivationObserver, - public DockedWindowLayoutManagerObserver, - public keyboard::KeyboardControllerObserver, - public LockStateObserver, - public wm::WmSnapToPixelLayoutManager, - public SessionStateObserver { - public: - ShelfLayoutManager(ShelfWidget* shelf_widget, WmShelf* wm_shelf); - ~ShelfLayoutManager() override; - - bool updating_bounds() const { return updating_bounds_; } - - // Clears internal data for shutdown process. - void PrepareForShutdown(); - - // Returns whether the shelf and its contents (shelf, status) are visible - // on the screen. - bool IsVisible() const; - - // Returns the ideal bounds of the shelf assuming it is visible. - gfx::Rect GetIdealBounds(); - - // Returns the preferred size of the shelf for the target visibility state. - gfx::Size GetPreferredSize(); - - // Returns the docked area bounds. - const gfx::Rect& dock_bounds() const { return dock_bounds_; } - - // Returns the bounds within the root window not occupied by the shelf nor the - // virtual keyboard. - const gfx::Rect& user_work_area_bounds() const { - return user_work_area_bounds_; - } - - // Stops any animations and sets the bounds of the shelf and status widgets. - void LayoutShelfAndUpdateBounds(bool change_work_area); - - // Stops any animations, sets the bounds of the shelf and status widgets, and - // changes the work area - void LayoutShelf(); - - // Returns shelf visibility state based on current value of auto hide - // behavior setting. - ShelfVisibilityState CalculateShelfVisibility(); - - // Updates the visibility state. - void UpdateVisibilityState(); - - // Invoked by the shelf when the auto-hide state may have changed. - void UpdateAutoHideState(); - - // Updates the auto-hide state for certain events. - // TODO(mash): Add similar event handling support for mash. - void UpdateAutoHideForMouseEvent(ui::MouseEvent* event, WmWindow* target); - void UpdateAutoHideForGestureEvent(ui::GestureEvent* event, WmWindow* target); - - ShelfVisibilityState visibility_state() const { - return state_.visibility_state; - } - ShelfAutoHideState auto_hide_state() const { return state_.auto_hide_state; } - - ShelfWidget* shelf_widget() { return shelf_widget_; } - - // Sets whether any windows overlap the shelf. If a window overlaps the shelf - // the shelf renders slightly differently. - void SetWindowOverlapsShelf(bool value); - bool window_overlaps_shelf() const { return window_overlaps_shelf_; } - - void AddObserver(ShelfLayoutManagerObserver* observer); - void RemoveObserver(ShelfLayoutManagerObserver* observer); - - // Processes a gesture event and updates the status of the shelf when - // appropriate. Returns true if the gesture has been handled and it should not - // be processed any further, false otherwise. - bool ProcessGestureEvent(const ui::GestureEvent& event); - - // Set an animation duration override for the show / hide animation of the - // shelf. Specifying 0 leads to use the default. - void SetAnimationDurationOverride(int duration_override_in_ms); - - // Overridden from wm::WmSnapToPixelLayoutManager: - void OnWindowResized() override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - // Overridden from ShellObserver: - void OnShelfAutoHideBehaviorChanged(WmWindow* root_window) override; - void OnPinnedStateChanged(WmWindow* pinned_window) override; - - // Overridden from WmActivationObserver: - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override; - - // Overridden from keyboard::KeyboardControllerObserver: - void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; - void OnKeyboardClosed() override; - - // Overridden from LockStateObserver: - void OnLockStateEvent(LockStateObserver::EventType event) override; - - // Overridden from SessionStateObserver: - void SessionStateChanged(session_manager::SessionState state) override; - - // TODO(harrym|oshima): These templates will be moved to a new Shelf class. - // A helper function for choosing values specific to a shelf alignment. - template <typename T> - T SelectValueForShelfAlignment(T bottom, T left, T right) const { - switch (wm_shelf_->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - return bottom; - case SHELF_ALIGNMENT_LEFT: - return left; - case SHELF_ALIGNMENT_RIGHT: - return right; - } - NOTREACHED(); - return right; - } - - template <typename T> - T PrimaryAxisValue(T horizontal, T vertical) const { - return wm_shelf_->IsHorizontalAlignment() ? horizontal : vertical; - } - - // Returns how the shelf background should be painted. - ShelfBackgroundType GetShelfBackgroundType() const; - - // Set the height of the ChromeVox panel, which takes away space from the - // available work area from the top of the screen. - void SetChromeVoxPanelHeight(int height); - - private: - class UpdateShelfObserver; - friend class PanelLayoutManagerTest; - friend class ShelfLayoutManagerTest; - friend class WebNotificationTrayTest; - - struct TargetBounds { - TargetBounds(); - ~TargetBounds(); - - float opacity; - float status_opacity; - gfx::Rect shelf_bounds_in_root; - gfx::Rect shelf_bounds_in_shelf; - gfx::Rect status_bounds_in_shelf; - gfx::Insets work_area_insets; - }; - - struct State { - State(); - - // Returns true when a secondary user is being added to an existing session. - bool IsAddingSecondaryUser() const; - - bool IsScreenLocked() const; - - // Returns true if the two states are considered equal. As - // |auto_hide_state| only matters if |visibility_state| is - // |SHELF_AUTO_HIDE|, Equals() ignores the |auto_hide_state| as - // appropriate. - bool Equals(const State& other) const; - - ShelfVisibilityState visibility_state; - ShelfAutoHideState auto_hide_state; - wm::WorkspaceWindowState window_state; - // True when the system is in the cancelable, pre-lock screen animation. - bool pre_lock_screen_animation_active; - session_manager::SessionState session_state; - }; - - // Sets the visibility of the shelf to |state|. - void SetState(ShelfVisibilityState visibility_state); - - // Updates the bounds and opacity of the shelf and status widgets. - // If |observer| is specified, it will be called back when the animations, if - // any, are complete. |change_work_area| specifies whether or not to update - // the work area of the screen. - void UpdateBoundsAndOpacity(const TargetBounds& target_bounds, - bool animate, - bool change_work_area, - ui::ImplicitAnimationObserver* observer); - - // Stops any animations and progresses them to the end. - void StopAnimating(); - - // Calculates the target bounds assuming visibility of |visible|. - void CalculateTargetBounds(const State& state, TargetBounds* target_bounds); - - // Updates the target bounds if a gesture-drag is in progress. This is only - // used by |CalculateTargetBounds()|. - void UpdateTargetBoundsForGesture(TargetBounds* target_bounds) const; - - // Updates the background of the shelf if it has changed. - void MaybeUpdateShelfBackground(AnimationChangeType change_type); - - // Updates the auto hide state immediately. - void UpdateAutoHideStateNow(); - - // Stops the auto hide timer and clears - // |mouse_over_shelf_when_auto_hide_timer_started_|. - void StopAutoHideTimer(); - - // Returns the bounds of an additional region which can trigger showing the - // shelf. This region exists to make it easier to trigger showing the shelf - // when the shelf is auto hidden and the shelf is on the boundary between - // two displays. - gfx::Rect GetAutoHideShowShelfRegionInScreen() const; - - // Returns the AutoHideState. This value is determined from the shelf and - // tray. - ShelfAutoHideState CalculateAutoHideState( - ShelfVisibilityState visibility_state) const; - - // Returns true if |window| is a descendant of the shelf. - bool IsShelfWindow(WmWindow* window); - - int GetWorkAreaInsets(const State& state, int size) const; - - // Overridden from DockedWindowLayoutManagerObserver: - void OnDockBoundsChanging( - const gfx::Rect& dock_bounds, - DockedWindowLayoutManagerObserver::Reason reason) override; - - // Called when the LoginUI changes from visible to invisible. - void UpdateShelfVisibilityAfterLoginUIChange(); - - // Compute |target_bounds| opacity based on gesture and shelf visibility. - float ComputeTargetOpacity(const State& state); - - // Returns true if there is a fullscreen window open that causes the shelf - // to be hidden. - bool IsShelfHiddenForFullscreen() const; - - // Gesture related functions: - void StartGestureDrag(const ui::GestureEvent& gesture); - void UpdateGestureDrag(const ui::GestureEvent& gesture); - void CompleteGestureDrag(const ui::GestureEvent& gesture); - void CancelGestureDrag(); - - // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling - // UpdateBoundsAndOpacity() again from SetChildBounds(). - bool updating_bounds_; - - bool in_shutdown_ = false; - - // True if the last mouse event was a mouse drag. - bool in_mouse_drag_ = false; - - // Current state. - State state_; - - ShelfWidget* shelf_widget_; - WmShelf* wm_shelf_; - - // Do any windows overlap the shelf? This is maintained by WorkspaceManager. - bool window_overlaps_shelf_; - - base::OneShotTimer auto_hide_timer_; - - // Whether the mouse was over the shelf when the auto hide timer started. - // False when neither the auto hide timer nor the timer task are running. - bool mouse_over_shelf_when_auto_hide_timer_started_; - - base::ObserverList<ShelfLayoutManagerObserver> observers_; - - // The shelf reacts to gesture-drags, and can be set to auto-hide for certain - // gestures. Some shelf behaviour (e.g. visibility state, background color - // etc.) are affected by various stages of the drag. The enum keeps track of - // the present status of the gesture drag. - enum GestureDragStatus { - GESTURE_DRAG_NONE, - GESTURE_DRAG_IN_PROGRESS, - GESTURE_DRAG_CANCEL_IN_PROGRESS, - GESTURE_DRAG_COMPLETE_IN_PROGRESS - }; - GestureDragStatus gesture_drag_status_; - - // Tracks the amount of the drag. The value is only valid when - // |gesture_drag_status_| is set to GESTURE_DRAG_IN_PROGRESS. - float gesture_drag_amount_; - - // Manage the auto-hide state during the gesture. - ShelfAutoHideState gesture_drag_auto_hide_state_; - - // Used to delay updating shelf background. - UpdateShelfObserver* update_shelf_observer_; - - // The bounds of the keyboard. - gfx::Rect keyboard_bounds_; - - // The bounds of the dock. - gfx::Rect dock_bounds_; - - // The bounds within the root window not occupied by the shelf nor the virtual - // keyboard. - gfx::Rect user_work_area_bounds_; - - // The height of the ChromeVox panel at the top of the screen, which - // needs to be removed from the available work area. - int chromevox_panel_height_; - - // The show hide animation duration override or 0 for default. - int duration_override_in_ms_; - - // The current shelf background. Should not be assigned to directly, use - // MaybeUpdateShelfBackground() instead. - ShelfBackgroundType shelf_background_type_; - - DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManager); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_LAYOUT_MANAGER_H_
diff --git a/ash/shelf/shelf_layout_manager_observer.h b/ash/shelf/shelf_layout_manager_observer.h deleted file mode 100644 index 8aac32d..0000000 --- a/ash/shelf/shelf_layout_manager_observer.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_LAYOUT_MANAGER_OBSERVER_H_ -#define ASH_SHELF_SHELF_LAYOUT_MANAGER_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_background_animator.h" - -namespace ash { - -enum class AnimationChangeType; - -class ASH_EXPORT ShelfLayoutManagerObserver { - public: - virtual ~ShelfLayoutManagerObserver() {} - - // Called when the target ShelfLayoutManager will be deleted. - virtual void WillDeleteShelfLayoutManager() {} - - // Called when the visibility change is scheduled. - virtual void WillChangeVisibilityState(ShelfVisibilityState new_state) {} - - // Called when the auto hide state is changed. - virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) {} - - // Called when shelf background animation is started. - virtual void OnBackgroundUpdated(ShelfBackgroundType background_type, - AnimationChangeType change_type) {} -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_LAYOUT_MANAGER_OBSERVER_H_
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc index cb32ca3..64983c19 100644 --- a/ash/shelf/shelf_layout_manager_unittest.cc +++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -2,30 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_layout_manager.h" -#include "ash/accelerators/accelerator_controller.h" -#include "ash/accelerators/accelerator_table.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_table.h" #include "ash/common/focus_cycler.h" #include "ash/common/session/session_controller.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_layout_manager_observer.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_layout_manager_observer.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_app_list_view_presenter_impl.h" #include "ash/test/test_system_tray_item.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/command_line.h"
diff --git a/ash/shelf/shelf_locking_manager.cc b/ash/shelf/shelf_locking_manager.cc deleted file mode 100644 index 362eedc..0000000 --- a/ash/shelf/shelf_locking_manager.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_locking_manager.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/shelf/wm_shelf.h" - -namespace ash { - -ShelfLockingManager::ShelfLockingManager(WmShelf* shelf) : shelf_(shelf) { - WmShell::Get()->AddLockStateObserver(this); - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - session_locked_ = - delegate->GetSessionState() != session_manager::SessionState::ACTIVE; - screen_locked_ = delegate->IsScreenLocked(); - delegate->AddSessionStateObserver(this); - WmShell::Get()->AddShellObserver(this); -} - -ShelfLockingManager::~ShelfLockingManager() { - WmShell::Get()->RemoveLockStateObserver(this); - WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); - WmShell::Get()->RemoveShellObserver(this); -} - -void ShelfLockingManager::OnLockStateChanged(bool locked) { - screen_locked_ = locked; - UpdateLockedState(); -} - -void ShelfLockingManager::SessionStateChanged( - session_manager::SessionState state) { - session_locked_ = state != session_manager::SessionState::ACTIVE; - UpdateLockedState(); -} - -void ShelfLockingManager::OnLockStateEvent(EventType event) { - // Lock when the animation starts, ignoring pre-lock. There's no unlock event. - screen_locked_ |= event == EVENT_LOCK_ANIMATION_STARTED; - UpdateLockedState(); -} - -void ShelfLockingManager::UpdateLockedState() { - const ShelfAlignment alignment = shelf_->GetAlignment(); - if (is_locked() && alignment != SHELF_ALIGNMENT_BOTTOM_LOCKED) { - stored_alignment_ = alignment; - shelf_->SetAlignment(SHELF_ALIGNMENT_BOTTOM_LOCKED); - } else if (!is_locked() && alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) { - shelf_->SetAlignment(stored_alignment_); - } -} - -} // namespace ash
diff --git a/ash/shelf/shelf_locking_manager.h b/ash/shelf/shelf_locking_manager.h deleted file mode 100644 index b40e2bb..0000000 --- a/ash/shelf/shelf_locking_manager.h +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_LOCKING_MANAGER_H_ -#define ASH_SHELF_SHELF_LOCKING_MANAGER_H_ - -#include "ash/ash_export.h" -#include "ash/common/session/session_state_observer.h" -#include "ash/common/shell_observer.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/wm/lock_state_observer.h" - -namespace ash { - -class WmShelf; - -// ShelfLockingManager observes screen and session events to [un]lock the shelf. -class ASH_EXPORT ShelfLockingManager : public ShellObserver, - public SessionStateObserver, - public LockStateObserver { - public: - explicit ShelfLockingManager(WmShelf* shelf); - ~ShelfLockingManager() override; - - bool is_locked() const { return session_locked_ || screen_locked_; } - void set_stored_alignment(ShelfAlignment value) { stored_alignment_ = value; } - - // ShellObserver: - void OnLockStateChanged(bool locked) override; - - // SessionStateObserver: - void SessionStateChanged(session_manager::SessionState state) override; - - // LockStateObserver: - void OnLockStateEvent(EventType event) override; - - private: - // Update the shelf state for session and screen lock changes. - void UpdateLockedState(); - - WmShelf* shelf_; - bool session_locked_ = false; - bool screen_locked_ = false; - ShelfAlignment stored_alignment_ = SHELF_ALIGNMENT_BOTTOM; - - DISALLOW_COPY_AND_ASSIGN(ShelfLockingManager); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_LOCKING_MANAGER_H_
diff --git a/ash/shelf/shelf_locking_manager_unittest.cc b/ash/shelf/shelf_locking_manager_unittest.cc deleted file mode 100644 index 7d57160e..0000000 --- a/ash/shelf/shelf_locking_manager_unittest.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_locking_manager.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/test/ash_test_base.h" - -namespace ash { -namespace test { - -// Tests the shelf behavior when the screen or session is locked. -class ShelfLockingManagerTest : public ash::test::AshTestBase { - public: - ShelfLockingManagerTest() {} - - ShelfLockingManager* GetShelfLockingManager() { - return GetPrimaryShelf()->GetShelfLockingManagerForTesting(); - } - - void SetScreenLocked(bool locked) { - GetShelfLockingManager()->OnLockStateChanged(locked); - } - - void SetSessionState(session_manager::SessionState state) { - GetShelfLockingManager()->SessionStateChanged(state); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ShelfLockingManagerTest); -}; - -// Makes sure shelf alignment is correct for lock screen. -TEST_F(ShelfLockingManagerTest, AlignmentLockedWhileScreenLocked) { - WmShelf* shelf = GetPrimaryShelf(); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->GetAlignment()); - - shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); - EXPECT_EQ(SHELF_ALIGNMENT_LEFT, shelf->GetAlignment()); - - SetScreenLocked(true); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); - SetScreenLocked(false); - EXPECT_EQ(SHELF_ALIGNMENT_LEFT, shelf->GetAlignment()); -} - -// Makes sure shelf alignment is correct for login and add user screens. -TEST_F(ShelfLockingManagerTest, AlignmentLockedWhileSessionLocked) { - WmShelf* shelf = GetPrimaryShelf(); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->GetAlignment()); - - shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); - EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); - - SetSessionState(session_manager::SessionState::LOGIN_PRIMARY); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); - SetSessionState(session_manager::SessionState::ACTIVE); - EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); - - SetSessionState(session_manager::SessionState::LOGIN_SECONDARY); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); - SetSessionState(session_manager::SessionState::ACTIVE); - EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); -} - -// Makes sure shelf alignment changes are stored, not set, while locked. -TEST_F(ShelfLockingManagerTest, AlignmentChangesDeferredWhileLocked) { - WmShelf* shelf = GetPrimaryShelf(); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->GetAlignment()); - - SetScreenLocked(true); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); - shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); - EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM_LOCKED, shelf->GetAlignment()); - SetScreenLocked(false); - EXPECT_EQ(SHELF_ALIGNMENT_RIGHT, shelf->GetAlignment()); -} - -} // namespace test -} // namespace ash
diff --git a/ash/shelf/shelf_model.cc b/ash/shelf/shelf_model.cc deleted file mode 100644 index 7c6e281f..0000000 --- a/ash/shelf/shelf_model.cc +++ /dev/null
@@ -1,211 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_model.h" - -#include <algorithm> - -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_model_observer.h" - -namespace ash { - -namespace { - -int ShelfItemTypeToWeight(ShelfItemType type) { - switch (type) { - case TYPE_APP_LIST: - // TODO(skuhne): If the app list item becomes movable again, this need - // to be a fallthrough. - return 0; - case TYPE_BROWSER_SHORTCUT: - case TYPE_APP_SHORTCUT: - return 1; - case TYPE_APP: - return 2; - case TYPE_DIALOG: - return 3; - case TYPE_APP_PANEL: - return 4; - case TYPE_UNDEFINED: - NOTREACHED() << "ShelfItemType must be set"; - return -1; - } - - NOTREACHED() << "Invalid type " << type; - return 1; -} - -bool CompareByWeight(const ShelfItem& a, const ShelfItem& b) { - return ShelfItemTypeToWeight(a.type) < ShelfItemTypeToWeight(b.type); -} - -} // namespace - -ShelfModel::ShelfModel() : next_id_(1) {} - -ShelfModel::~ShelfModel() {} - -void ShelfModel::DestroyItemDelegates() { - // Some ShelfItemDelegates access this model in their destructors and hence - // need early cleanup. - id_to_item_delegate_map_.clear(); -} - -int ShelfModel::Add(const ShelfItem& item) { - return AddAt(items_.size(), item); -} - -int ShelfModel::AddAt(int index, const ShelfItem& item) { - index = ValidateInsertionIndex(item.type, index); - items_.insert(items_.begin() + index, item); - items_[index].id = next_id_++; - for (auto& observer : observers_) - observer.ShelfItemAdded(index); - return index; -} - -void ShelfModel::RemoveItemAt(int index) { - DCHECK(index >= 0 && index < item_count()); - ShelfID id = items_[index].id; - items_.erase(items_.begin() + index); - RemoveShelfItemDelegate(id); - // TODO(jamescook): Fold this into ShelfItemRemoved in existing observers. - for (auto& observer : observers_) - observer.OnSetShelfItemDelegate(id, nullptr); - for (auto& observer : observers_) - observer.ShelfItemRemoved(index, id); -} - -void ShelfModel::Move(int index, int target_index) { - if (index == target_index) - return; - // TODO: this needs to enforce valid ranges. - ShelfItem item(items_[index]); - items_.erase(items_.begin() + index); - items_.insert(items_.begin() + target_index, item); - for (auto& observer : observers_) - observer.ShelfItemMoved(index, target_index); -} - -void ShelfModel::Set(int index, const ShelfItem& item) { - if (index < 0 || index >= item_count()) { - NOTREACHED(); - return; - } - - int new_index = item.type == items_[index].type - ? index - : ValidateInsertionIndex(item.type, index); - - ShelfItem old_item(items_[index]); - items_[index] = item; - items_[index].id = old_item.id; - for (auto& observer : observers_) - observer.ShelfItemChanged(index, old_item); - - // If the type changes confirm that the item is still in the right order. - if (new_index != index) { - // The move function works by removing one item and then inserting it at the - // new location. However - by removing the item first the order will change - // so that our target index needs to be corrected. - // TODO(skuhne): Moving this into the Move function breaks lots of unit - // tests. So several functions were already using this incorrectly. - // That needs to be cleaned up. - if (index < new_index) - new_index--; - - Move(index, new_index); - } -} - -int ShelfModel::ItemIndexByID(ShelfID id) const { - ShelfItems::const_iterator i = ItemByID(id); - return i == items_.end() ? -1 : static_cast<int>(i - items_.begin()); -} - -int ShelfModel::GetItemIndexForType(ShelfItemType type) { - for (size_t i = 0; i < items_.size(); ++i) { - if (items_[i].type == type) - return i; - } - return -1; -} - -ShelfItems::const_iterator ShelfModel::ItemByID(int id) const { - for (ShelfItems::const_iterator i = items_.begin(); i != items_.end(); ++i) { - if (i->id == id) - return i; - } - return items_.end(); -} - -int ShelfModel::FirstRunningAppIndex() const { - ShelfItem weight_dummy; - weight_dummy.type = TYPE_APP; - return std::lower_bound(items_.begin(), items_.end(), weight_dummy, - CompareByWeight) - - items_.begin(); -} - -int ShelfModel::FirstPanelIndex() const { - ShelfItem weight_dummy; - weight_dummy.type = TYPE_APP_PANEL; - return std::lower_bound(items_.begin(), items_.end(), weight_dummy, - CompareByWeight) - - items_.begin(); -} - -void ShelfModel::SetShelfItemDelegate( - ShelfID id, - std::unique_ptr<ShelfItemDelegate> item_delegate) { - // If another ShelfItemDelegate is already registered for |id|, we assume - // that this request is replacing ShelfItemDelegate for |id| with - // |item_delegate|. - RemoveShelfItemDelegate(id); - - for (auto& observer : observers_) - observer.OnSetShelfItemDelegate(id, item_delegate.get()); - - id_to_item_delegate_map_[id] = std::move(item_delegate); -} - -ShelfItemDelegate* ShelfModel::GetShelfItemDelegate(ShelfID id) { - if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) - return id_to_item_delegate_map_[id].get(); - return nullptr; -} - -void ShelfModel::AddObserver(ShelfModelObserver* observer) { - observers_.AddObserver(observer); -} - -void ShelfModel::RemoveObserver(ShelfModelObserver* observer) { - observers_.RemoveObserver(observer); -} - -int ShelfModel::ValidateInsertionIndex(ShelfItemType type, int index) const { - DCHECK(index >= 0 && index <= item_count() + 1); - - // Clamp |index| to the allowed range for the type as determined by |weight|. - ShelfItem weight_dummy; - weight_dummy.type = type; - index = std::max(std::lower_bound(items_.begin(), items_.end(), weight_dummy, - CompareByWeight) - - items_.begin(), - static_cast<ShelfItems::difference_type>(index)); - index = std::min(std::upper_bound(items_.begin(), items_.end(), weight_dummy, - CompareByWeight) - - items_.begin(), - static_cast<ShelfItems::difference_type>(index)); - - return index; -} - -void ShelfModel::RemoveShelfItemDelegate(ShelfID id) { - if (id_to_item_delegate_map_.find(id) != id_to_item_delegate_map_.end()) - id_to_item_delegate_map_.erase(id); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_model.h b/ash/shelf/shelf_model.h deleted file mode 100644 index 727e23fa..0000000 --- a/ash/shelf/shelf_model.h +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_MODEL_H_ -#define ASH_SHELF_SHELF_MODEL_H_ - -#include <map> -#include <memory> - -#include "ash/ash_export.h" -#include "ash/shelf/shelf_item_types.h" -#include "base/macros.h" -#include "base/observer_list.h" - -namespace ash { - -class ShelfItemDelegate; -class ShelfModelObserver; - -// Model used for shelf items. Owns ShelfItemDelegates but does not create them. -class ASH_EXPORT ShelfModel { - public: - ShelfModel(); - ~ShelfModel(); - - // Cleans up the ShelfItemDelegates. - void DestroyItemDelegates(); - - // Adds a new item to the model. Returns the resulting index. - int Add(const ShelfItem& item); - - // Adds the item. |index| is the requested insertion index, which may be - // modified to meet type-based ordering. Returns the actual insertion index. - int AddAt(int index, const ShelfItem& item); - - // Removes the item at |index|. - void RemoveItemAt(int index); - - // Moves the item at |index| to |target_index|. |target_index| is in terms - // of the model *after* the item at |index| is removed. - void Move(int index, int target_index); - - // Resets the item at the specified index. The item maintains its existing - // id and type. - void Set(int index, const ShelfItem& item); - - // Returns the index of the item by id. - int ItemIndexByID(ShelfID id) const; - - // Returns the |index| of the item matching |type| in |items_|. - // Returns -1 if the matching item is not found. - // Note: Requires a linear search. - int GetItemIndexForType(ShelfItemType type); - - // Returns the index of the first running application or the index where the - // first running application would go if there are no running (non pinned) - // applications yet. - int FirstRunningAppIndex() const; - - // Returns the index of the first panel or the index where the first panel - // would go if there are no panels. - int FirstPanelIndex() const; - - // Returns the id assigned to the next item added. - ShelfID next_id() const { return next_id_; } - - // Returns a reserved id which will not be used by the |ShelfModel|. - ShelfID reserve_external_id() { return next_id_++; } - - // Returns an iterator into items() for the item with the specified id, or - // items().end() if there is no item with the specified id. - ShelfItems::const_iterator ItemByID(ShelfID id) const; - - const ShelfItems& items() const { return items_; } - int item_count() const { return static_cast<int>(items_.size()); } - - // Set |item_delegate| for |id| and takes ownership. - void SetShelfItemDelegate(ShelfID id, - std::unique_ptr<ShelfItemDelegate> item_delegate); - - // Returns ShelfItemDelegate for |id|, or null if none exists. - ShelfItemDelegate* GetShelfItemDelegate(ShelfID id); - - void AddObserver(ShelfModelObserver* observer); - void RemoveObserver(ShelfModelObserver* observer); - - private: - // Makes sure |index| is in line with the type-based order of items. If that - // is not the case, adjusts index by shifting it to the valid range and - // returns the new value. - int ValidateInsertionIndex(ShelfItemType type, int index) const; - - // Remove and destroy ShelfItemDelegate for |id|. - void RemoveShelfItemDelegate(ShelfID id); - - // ID assigned to the next item. - ShelfID next_id_; - - ShelfItems items_; - base::ObserverList<ShelfModelObserver> observers_; - - std::map<ShelfID, std::unique_ptr<ShelfItemDelegate>> - id_to_item_delegate_map_; - - DISALLOW_COPY_AND_ASSIGN(ShelfModel); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_MODEL_H_
diff --git a/ash/shelf/shelf_model_observer.h b/ash/shelf/shelf_model_observer.h deleted file mode 100644 index 70e7156..0000000 --- a/ash/shelf/shelf_model_observer.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_MODEL_OBSERVER_H_ -#define ASH_SHELF_SHELF_MODEL_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "ash/shelf/shelf_item_types.h" - -namespace ash { - -struct ShelfItem; -class ShelfItemDelegate; - -class ASH_EXPORT ShelfModelObserver { - public: - // Invoked after an item has been added to the model. - virtual void ShelfItemAdded(int index) = 0; - - // Invoked after an item has been removed. |index| is the index the item was - // at. - virtual void ShelfItemRemoved(int index, ShelfID id) = 0; - - // Invoked after an item has been moved. See ShelfModel::Move() for details - // of the arguments. - virtual void ShelfItemMoved(int start_index, int target_index) = 0; - - // Invoked when the state of an item changes. |old_item| is the item - // before the change. - virtual void ShelfItemChanged(int index, const ShelfItem& old_item) = 0; - - // Gets called when a ShelfItemDelegate gets changed. Note that - // |item_delegate| can be null. - // NOTE: This is added a temporary fix for M39 to fix crbug.com/429870. - // TODO(skuhne): Find the real reason for this problem and remove this fix. - virtual void OnSetShelfItemDelegate(ShelfID id, - ShelfItemDelegate* item_delegate) = 0; - - protected: - virtual ~ShelfModelObserver() {} -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_MODEL_OBSERVER_H_
diff --git a/ash/shelf/shelf_model_unittest.cc b/ash/shelf/shelf_model_unittest.cc deleted file mode 100644 index 30e6af8..0000000 --- a/ash/shelf/shelf_model_unittest.cc +++ /dev/null
@@ -1,312 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_model.h" - -#include <set> -#include <string> - -#include "ash/shelf/shelf_model_observer.h" -#include "base/strings/stringprintf.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace ash { - -namespace { - -// ShelfModelObserver implementation that tracks what message are invoked. -class TestShelfModelObserver : public ShelfModelObserver { - public: - TestShelfModelObserver() - : added_count_(0), - removed_count_(0), - changed_count_(0), - moved_count_(0) {} - - // Returns a string description of the changes that have occurred since this - // was last invoked. Resets state to initial state. - std::string StateStringAndClear() { - std::string result; - AddToResult("added=%d", added_count_, &result); - AddToResult("removed=%d", removed_count_, &result); - AddToResult("changed=%d", changed_count_, &result); - AddToResult("moved=%d", moved_count_, &result); - added_count_ = removed_count_ = changed_count_ = moved_count_ = 0; - return result; - } - - // ShelfModelObserver overrides: - void ShelfItemAdded(int index) override { added_count_++; } - void ShelfItemRemoved(int index, ShelfID id) override { removed_count_++; } - void ShelfItemChanged(int index, const ShelfItem& old_item) override { - changed_count_++; - } - void ShelfItemMoved(int start_index, int target_index) override { - moved_count_++; - } - void OnSetShelfItemDelegate(ShelfID id, - ShelfItemDelegate* item_delegate) override {} - - private: - void AddToResult(const std::string& format, int count, std::string* result) { - if (!count) - return; - if (!result->empty()) - *result += " "; - *result += base::StringPrintf(format.c_str(), count); - } - - int added_count_; - int removed_count_; - int changed_count_; - int moved_count_; - - DISALLOW_COPY_AND_ASSIGN(TestShelfModelObserver); -}; - -} // namespace - -class ShelfModelTest : public testing::Test { - public: - ShelfModelTest() {} - ~ShelfModelTest() override {} - - void SetUp() override { - model_.reset(new ShelfModel); - observer_.reset(new TestShelfModelObserver); - EXPECT_EQ(0, model_->item_count()); - - ShelfItem item; - item.type = TYPE_APP_LIST; - model_->Add(item); - EXPECT_EQ(1, model_->item_count()); - - model_->AddObserver(observer_.get()); - } - - void TearDown() override { - observer_.reset(); - model_.reset(); - } - - std::unique_ptr<ShelfModel> model_; - std::unique_ptr<TestShelfModelObserver> observer_; - - private: - DISALLOW_COPY_AND_ASSIGN(ShelfModelTest); -}; - -TEST_F(ShelfModelTest, BasicAssertions) { - // Add an item. - ShelfItem item; - item.type = TYPE_APP_SHORTCUT; - int index = model_->Add(item); - EXPECT_EQ(2, model_->item_count()); - EXPECT_EQ("added=1", observer_->StateStringAndClear()); - - // Change to a platform app item. - ShelfID original_id = model_->items()[index].id; - item.type = TYPE_APP; - model_->Set(index, item); - EXPECT_EQ(original_id, model_->items()[index].id); - EXPECT_EQ("changed=1", observer_->StateStringAndClear()); - EXPECT_EQ(TYPE_APP, model_->items()[index].type); - - // Remove the item. - model_->RemoveItemAt(index); - EXPECT_EQ(1, model_->item_count()); - EXPECT_EQ("removed=1", observer_->StateStringAndClear()); - - // Add an app item. - item.type = TYPE_APP_SHORTCUT; - index = model_->Add(item); - observer_->StateStringAndClear(); - - // Change everything. - model_->Set(index, item); - EXPECT_EQ("changed=1", observer_->StateStringAndClear()); - EXPECT_EQ(TYPE_APP_SHORTCUT, model_->items()[index].type); - - // Add another item. - item.type = TYPE_APP_SHORTCUT; - model_->Add(item); - observer_->StateStringAndClear(); - - // Move the second to the first. - model_->Move(1, 0); - EXPECT_EQ("moved=1", observer_->StateStringAndClear()); - - // And back. - model_->Move(0, 1); - EXPECT_EQ("moved=1", observer_->StateStringAndClear()); - - // Verifies all the items get unique ids. - std::set<ShelfID> ids; - for (int i = 0; i < model_->item_count(); ++i) - ids.insert(model_->items()[i].id); - EXPECT_EQ(model_->item_count(), static_cast<int>(ids.size())); -} - -// Assertions around where items are added. -TEST_F(ShelfModelTest, AddIndices) { - // Insert browser short cut at index 1. - ShelfItem browser_shortcut; - browser_shortcut.type = TYPE_BROWSER_SHORTCUT; - int browser_shortcut_index = model_->Add(browser_shortcut); - EXPECT_EQ(1, browser_shortcut_index); - - // App items should be after the browser shortcut. - ShelfItem item; - item.type = TYPE_APP; - int platform_app_index1 = model_->Add(item); - EXPECT_EQ(2, platform_app_index1); - - // Add another platform app item, it should follow first. - int platform_app_index2 = model_->Add(item); - EXPECT_EQ(3, platform_app_index2); - - // APP_SHORTCUT priority is higher than PLATFORM_APP but same as - // BROWSER_SHORTCUT. So APP_SHORTCUT is located after BROWSER_SHORCUT. - item.type = TYPE_APP_SHORTCUT; - int app_shortcut_index1 = model_->Add(item); - EXPECT_EQ(2, app_shortcut_index1); - - item.type = TYPE_APP_SHORTCUT; - int app_shortcut_index2 = model_->Add(item); - EXPECT_EQ(3, app_shortcut_index2); - - // Check that AddAt() figures out the correct indexes for app shortcuts. - // APP_SHORTCUT and BROWSER_SHORTCUT has the same weight. - // So APP_SHORTCUT is located at index 0. And, BROWSER_SHORTCUT is located at - // index 1. - item.type = TYPE_APP_SHORTCUT; - int app_shortcut_index3 = model_->AddAt(1, item); - EXPECT_EQ(1, app_shortcut_index3); - - item.type = TYPE_APP_SHORTCUT; - int app_shortcut_index4 = model_->AddAt(6, item); - EXPECT_EQ(5, app_shortcut_index4); - - item.type = TYPE_APP_SHORTCUT; - int app_shortcut_index5 = model_->AddAt(3, item); - EXPECT_EQ(3, app_shortcut_index5); - - // Before there are any panels, no icons should be right aligned. - EXPECT_EQ(model_->item_count(), model_->FirstPanelIndex()); - - // Check that AddAt() figures out the correct indexes for apps and panels. - item.type = TYPE_APP; - int platform_app_index3 = model_->AddAt(3, item); - EXPECT_EQ(7, platform_app_index3); - - item.type = TYPE_APP_PANEL; - int app_panel_index1 = model_->AddAt(2, item); - EXPECT_EQ(10, app_panel_index1); - - item.type = TYPE_APP; - int platform_app_index4 = model_->AddAt(11, item); - EXPECT_EQ(10, platform_app_index4); - - item.type = TYPE_APP_PANEL; - int app_panel_index2 = model_->AddAt(12, item); - EXPECT_EQ(12, app_panel_index2); - - item.type = TYPE_APP; - int platform_app_index5 = model_->AddAt(7, item); - EXPECT_EQ(7, platform_app_index5); - - item.type = TYPE_APP_PANEL; - int app_panel_index3 = model_->AddAt(13, item); - EXPECT_EQ(13, app_panel_index3); - - // Right aligned index should be the first app panel index. - EXPECT_EQ(12, model_->FirstPanelIndex()); - - EXPECT_EQ(TYPE_BROWSER_SHORTCUT, model_->items()[2].type); - EXPECT_EQ(TYPE_APP_LIST, model_->items()[0].type); -} - -// Test that the indexes for the running applications are properly determined. -TEST_F(ShelfModelTest, FirstRunningAppIndex) { - // Insert the browser shortcut at index 1 and check that the running - // application index would be behind it. - ShelfItem item; - item.type = TYPE_BROWSER_SHORTCUT; - EXPECT_EQ(1, model_->Add(item)); - EXPECT_EQ(2, model_->FirstRunningAppIndex()); - - // Insert a panel application at the end and check that the running - // application index would be at / before the application panel. - item.type = TYPE_APP_PANEL; - EXPECT_EQ(2, model_->Add(item)); - EXPECT_EQ(2, model_->FirstRunningAppIndex()); - - // Insert an application shortcut and make sure that the running application - // index would be behind it. - item.type = TYPE_APP_SHORTCUT; - EXPECT_EQ(2, model_->Add(item)); - EXPECT_EQ(3, model_->FirstRunningAppIndex()); - - // Insert a two app items and check the first running app index. - item.type = TYPE_APP; - EXPECT_EQ(3, model_->Add(item)); - EXPECT_EQ(3, model_->FirstRunningAppIndex()); - EXPECT_EQ(4, model_->Add(item)); - EXPECT_EQ(3, model_->FirstRunningAppIndex()); -} - -// Assertions around id generation and usage. -TEST_F(ShelfModelTest, ShelfIDTests) { - // Get the next to use ID counter. - ShelfID id = model_->next_id(); - - // Calling this function multiple times does not change the returned ID. - EXPECT_EQ(model_->next_id(), id); - - // Check that when we reserve a value it will be the previously retrieved ID, - // but it will not change the item count and retrieving the next ID should - // produce something new. - EXPECT_EQ(model_->reserve_external_id(), id); - EXPECT_EQ(1, model_->item_count()); - ShelfID id2 = model_->next_id(); - EXPECT_NE(id2, id); - - // Adding another item to the list should also produce a new ID. - ShelfItem item; - item.type = TYPE_APP; - model_->Add(item); - EXPECT_NE(model_->next_id(), id2); -} - -// This verifies that converting an existing item into a lower weight category -// (e.g. shortcut to running but not pinned app) will move it to the proper -// location. See crbug.com/248769. -TEST_F(ShelfModelTest, CorrectMoveItemsWhenStateChange) { - // The first item is the app list and last item is the browser. - ShelfItem browser_shortcut; - browser_shortcut.type = TYPE_BROWSER_SHORTCUT; - int browser_shortcut_index = model_->Add(browser_shortcut); - EXPECT_EQ(TYPE_APP_LIST, model_->items()[0].type); - EXPECT_EQ(1, browser_shortcut_index); - - // Add three shortcuts. They should all be moved between the two. - ShelfItem item; - item.type = TYPE_APP_SHORTCUT; - int app1_index = model_->Add(item); - EXPECT_EQ(2, app1_index); - int app2_index = model_->Add(item); - EXPECT_EQ(3, app2_index); - int app3_index = model_->Add(item); - EXPECT_EQ(4, app3_index); - - // Now change the type of the second item and make sure that it is moving - // behind the shortcuts. - item.type = TYPE_APP; - model_->Set(app2_index, item); - - // The item should have moved in front of the app launcher. - EXPECT_EQ(TYPE_APP, model_->items()[4].type); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_tooltip_manager.cc b/ash/shelf/shelf_tooltip_manager.cc deleted file mode 100644 index 59988c8..0000000 --- a/ash/shelf/shelf_tooltip_manager.cc +++ /dev/null
@@ -1,263 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_tooltip_manager.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/tray/tray_constants.h" -#include "base/bind.h" -#include "base/strings/string16.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/events/event.h" -#include "ui/events/event_constants.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/views/bubble/bubble_dialog_delegate.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -const int kTooltipAppearanceDelay = 1000; // msec - -// Tooltip layout constants. - -// Shelf item tooltip height. -const int kTooltipHeight = 24; - -// The maximum width of the tooltip bubble. Borrowed the value from -// ash/tooltip/tooltip_controller.cc -const int kTooltipMaxWidth = 250; - -// Shelf item tooltip internal text margins. -const int kTooltipTopBottomMargin = 4; -const int kTooltipLeftRightMargin = 8; - -// The offset for the tooltip bubble - making sure that the bubble is spaced -// with a fixed gap. The gap is accounted for by the transparent arrow in the -// bubble and an additional 1px padding for the shelf item views. -const int kArrowTopBottomOffset = 1; -const int kArrowLeftRightOffset = 1; - -// Tooltip's border interior thickness that defines its minimum height. -const int kBorderInteriorThickness = kTooltipHeight / 2; - -} // namespace - -// The implementation of tooltip of the launcher. -class ShelfTooltipManager::ShelfTooltipBubble - : public views::BubbleDialogDelegateView { - public: - ShelfTooltipBubble(views::View* anchor, - views::BubbleBorder::Arrow arrow, - const base::string16& text) - : views::BubbleDialogDelegateView(anchor, arrow) { - set_close_on_deactivate(false); - set_can_activate(false); - set_accept_events(false); - set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin)); - set_shadow(views::BubbleBorder::NO_ASSETS); - SetLayoutManager(new views::FillLayout()); - views::Label* label = new views::Label(text); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - ui::NativeTheme* theme = anchor->GetWidget()->GetNativeTheme(); - label->SetEnabledColor( - theme->GetSystemColor(ui::NativeTheme::kColorId_TooltipText)); - SkColor background_color = - theme->GetSystemColor(ui::NativeTheme::kColorId_TooltipBackground); - set_color(background_color); - label->SetBackgroundColor(background_color); - // The background is not opaque, so we can't do subpixel rendering. - label->SetSubpixelRenderingEnabled(false); - AddChildView(label); - - gfx::Insets insets(kArrowTopBottomOffset, kArrowLeftRightOffset); - // Adjust the anchor location for asymmetrical borders of shelf item. - if (anchor->border()) - insets += anchor->border()->GetInsets(); - if (ui::MaterialDesignController::IsSecondaryUiMaterial()) - insets += gfx::Insets(-kBubblePaddingHorizontalBottom); - set_anchor_view_insets(insets); - - views::BubbleDialogDelegateView::CreateBubble(this); - if (!ui::MaterialDesignController::IsSecondaryUiMaterial()) { - // These must both be called after CreateBubble. - SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT); - SetBorderInteriorThickness(kBorderInteriorThickness); - } - } - - private: - // BubbleDialogDelegateView overrides: - gfx::Size GetPreferredSize() const override { - const gfx::Size size = BubbleDialogDelegateView::GetPreferredSize(); - const int kTooltipMinHeight = kTooltipHeight - 2 * kTooltipTopBottomMargin; - return gfx::Size(std::min(size.width(), kTooltipMaxWidth), - std::max(size.height(), kTooltipMinHeight)); - } - - void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, - views::Widget* bubble_widget) const override { - // Place the bubble in the same display as the anchor. - WmWindow::Get(anchor_widget()->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - bubble_widget, kShellWindowId_SettingBubbleContainer, params); - } - - int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; } - - DISALLOW_COPY_AND_ASSIGN(ShelfTooltipBubble); -}; - -ShelfTooltipManager::ShelfTooltipManager(ShelfView* shelf_view) - : timer_delay_(kTooltipAppearanceDelay), - shelf_view_(shelf_view), - bubble_(nullptr), - weak_factory_(this) { - shelf_view_->wm_shelf()->AddObserver(this); - WmShell::Get()->AddPointerWatcher(this, - views::PointerWatcherEventTypes::BASIC); -} - -ShelfTooltipManager::~ShelfTooltipManager() { - WmShell::Get()->RemovePointerWatcher(this); - shelf_view_->wm_shelf()->RemoveObserver(this); - WmWindow* window = nullptr; - if (shelf_view_->GetWidget()) - window = WmWindow::Get(shelf_view_->GetWidget()->GetNativeWindow()); - if (window) - window->RemoveLimitedPreTargetHandler(this); -} - -void ShelfTooltipManager::Init() { - WmWindow* window = WmWindow::Get(shelf_view_->GetWidget()->GetNativeWindow()); - window->AddLimitedPreTargetHandler(this); -} - -void ShelfTooltipManager::Close() { - timer_.Stop(); - if (bubble_) - bubble_->GetWidget()->Close(); - bubble_ = nullptr; -} - -bool ShelfTooltipManager::IsVisible() const { - return bubble_ && bubble_->GetWidget()->IsVisible(); -} - -views::View* ShelfTooltipManager::GetCurrentAnchorView() const { - return bubble_ ? bubble_->GetAnchorView() : nullptr; -} - -void ShelfTooltipManager::ShowTooltip(views::View* view) { - timer_.Stop(); - if (bubble_) { - // Cancel the hiding animation to hide the old bubble immediately. - WmWindow::Get(bubble_->GetWidget()->GetNativeWindow()) - ->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); - Close(); - } - - if (!ShouldShowTooltipForView(view)) - return; - - views::BubbleBorder::Arrow arrow = views::BubbleBorder::Arrow::NONE; - switch (shelf_view_->wm_shelf()->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - arrow = views::BubbleBorder::BOTTOM_CENTER; - break; - case SHELF_ALIGNMENT_LEFT: - arrow = views::BubbleBorder::LEFT_CENTER; - break; - case SHELF_ALIGNMENT_RIGHT: - arrow = views::BubbleBorder::RIGHT_CENTER; - break; - } - - base::string16 text = shelf_view_->GetTitleForView(view); - bubble_ = new ShelfTooltipBubble(view, arrow, text); - WmWindow* window = WmWindow::Get(bubble_->GetWidget()->GetNativeWindow()); - window->SetVisibilityAnimationType( - ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); - window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE); - bubble_->GetWidget()->Show(); -} - -void ShelfTooltipManager::ShowTooltipWithDelay(views::View* view) { - if (ShouldShowTooltipForView(view)) { - timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timer_delay_), - base::Bind(&ShelfTooltipManager::ShowTooltip, - weak_factory_.GetWeakPtr(), view)); - } -} - -void ShelfTooltipManager::OnPointerEventObserved( - const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - // Close on any press events inside or outside the tooltip. - if (event.type() == ui::ET_POINTER_DOWN) - Close(); -} - -void ShelfTooltipManager::OnMouseEvent(ui::MouseEvent* event) { - if (event->type() == ui::ET_MOUSE_EXITED) { - Close(); - return; - } - - if (event->type() != ui::ET_MOUSE_MOVED) - return; - - gfx::Point point = event->location(); - views::View::ConvertPointFromWidget(shelf_view_, &point); - views::View* view = shelf_view_->GetTooltipHandlerForPoint(point); - const bool should_show = ShouldShowTooltipForView(view); - - timer_.Stop(); - if (IsVisible() && should_show && bubble_->GetAnchorView() != view) - ShowTooltip(view); - else if (!IsVisible() && should_show) - ShowTooltipWithDelay(view); - else if (IsVisible() && shelf_view_->ShouldHideTooltip(point)) - Close(); -} - -void ShelfTooltipManager::WillChangeVisibilityState( - ShelfVisibilityState new_state) { - if (new_state == SHELF_HIDDEN) - Close(); -} - -void ShelfTooltipManager::OnAutoHideStateChanged(ShelfAutoHideState new_state) { - if (new_state == SHELF_AUTO_HIDE_HIDDEN) { - timer_.Stop(); - // AutoHide state change happens during an event filter, so immediate close - // may cause a crash in the HandleMouseEvent() after the filter. So we just - // schedule the Close here. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr())); - } -} - -bool ShelfTooltipManager::ShouldShowTooltipForView(views::View* view) { - WmShelf* shelf = shelf_view_ ? shelf_view_->wm_shelf() : nullptr; - return shelf && shelf_view_->ShouldShowTooltipForView(view) && - (shelf->GetVisibilityState() == SHELF_VISIBLE || - (shelf->GetVisibilityState() == SHELF_AUTO_HIDE && - shelf->GetAutoHideState() == SHELF_AUTO_HIDE_SHOWN)); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_tooltip_manager.h b/ash/shelf/shelf_tooltip_manager.h deleted file mode 100644 index b2619aa..0000000 --- a/ash/shelf/shelf_tooltip_manager.h +++ /dev/null
@@ -1,90 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_TOOLTIP_MANAGER_H_ -#define ASH_SHELF_SHELF_TOOLTIP_MANAGER_H_ - -#include "ash/ash_export.h" -#include "ash/shelf/wm_shelf_observer.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/timer/timer.h" -#include "ui/events/event_handler.h" -#include "ui/views/pointer_watcher.h" - -namespace views { -class BubbleDialogDelegateView; -class View; -} - -namespace ash { -class ShelfView; - -namespace test { -class ShelfTooltipManagerTest; -class ShelfViewTest; -} - -// ShelfTooltipManager manages the tooltip bubble that appears for shelf items. -class ASH_EXPORT ShelfTooltipManager : public ui::EventHandler, - public views::PointerWatcher, - public WmShelfObserver { - public: - explicit ShelfTooltipManager(ShelfView* shelf_view); - ~ShelfTooltipManager() override; - - // Initializes the tooltip manager once the shelf is shown. - void Init(); - - // Closes the tooltip. - void Close(); - - // Returns true if the tooltip is currently visible. - bool IsVisible() const; - - // Returns the view to which the tooltip bubble is anchored. May be null. - views::View* GetCurrentAnchorView() const; - - // Show the tooltip bubble for the specified view. - void ShowTooltip(views::View* view); - void ShowTooltipWithDelay(views::View* view); - - // Set the timer delay in ms for testing. - void set_timer_delay_for_test(int timer_delay) { timer_delay_ = timer_delay; } - - protected: - // ui::EventHandler overrides: - void OnMouseEvent(ui::MouseEvent* event) override; - - // views::PointerWatcher overrides: - void OnPointerEventObserved(const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - - // WmShelfObserver overrides: - void WillChangeVisibilityState(ShelfVisibilityState new_state) override; - void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; - - private: - class ShelfTooltipBubble; - friend class test::ShelfViewTest; - friend class test::ShelfTooltipManagerTest; - - // A helper function to check for shelf visibility and view validity. - bool ShouldShowTooltipForView(views::View* view); - - int timer_delay_; - base::OneShotTimer timer_; - - ShelfView* shelf_view_; - views::BubbleDialogDelegateView* bubble_; - - base::WeakPtrFactory<ShelfTooltipManager> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManager); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_TOOLTIP_MANAGER_H_
diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc deleted file mode 100644 index 9f308d3..0000000 --- a/ash/shelf/shelf_tooltip_manager_unittest.cc +++ /dev/null
@@ -1,246 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_tooltip_manager.h" - -#include "ash/common/wm_shell.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/shelf_view_test_api.h" -#include "ash/test/test_shelf_item_delegate.h" -#include "base/memory/ptr_util.h" -#include "ui/events/event_constants.h" -#include "ui/events/test/event_generator.h" -#include "ui/views/bubble/bubble_dialog_delegate.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace test { - -class ShelfTooltipManagerTest : public AshTestBase { - public: - ShelfTooltipManagerTest() {} - ~ShelfTooltipManagerTest() override {} - - void SetUp() override { - AshTestBase::SetUp(); - shelf_view_ = GetPrimaryShelf()->GetShelfViewForTesting(); - tooltip_manager_ = test::ShelfViewTestAPI(shelf_view_).tooltip_manager(); - tooltip_manager_->set_timer_delay_for_test(0); - } - - bool IsTimerRunning() { return tooltip_manager_->timer_.IsRunning(); } - views::Widget* GetTooltip() { return tooltip_manager_->bubble_->GetWidget(); } - - std::unique_ptr<views::Widget> CreateTestWidget() { - std::unique_ptr<views::Widget> widget = base::MakeUnique<views::Widget>(); - views::Widget::InitParams params; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.context = CurrentContext(); - widget->Init(params); - widget->Show(); - return widget; - } - - protected: - ShelfView* shelf_view_; - ShelfTooltipManager* tooltip_manager_; - - private: - DISALLOW_COPY_AND_ASSIGN(ShelfTooltipManagerTest); -}; - -TEST_F(ShelfTooltipManagerTest, ShowTooltip) { - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - EXPECT_TRUE(tooltip_manager_->IsVisible()); - EXPECT_FALSE(IsTimerRunning()); -} - -TEST_F(ShelfTooltipManagerTest, ShowTooltipWithDelay) { - // ShowTooltipWithDelay should start the timer instead of showing immediately. - tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - EXPECT_TRUE(IsTimerRunning()); - // TODO: Test that the delayed tooltip is shown, without flaky failures. -} - -TEST_F(ShelfTooltipManagerTest, DoNotShowForInvalidView) { - // The manager should not show or start the timer for a null view. - tooltip_manager_->ShowTooltip(nullptr); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - tooltip_manager_->ShowTooltipWithDelay(nullptr); - EXPECT_FALSE(IsTimerRunning()); - - // The manager should not show or start the timer for a non-shelf view. - views::View view; - tooltip_manager_->ShowTooltip(&view); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - tooltip_manager_->ShowTooltipWithDelay(&view); - EXPECT_FALSE(IsTimerRunning()); - - // The manager should start the timer for a view on the shelf. - ShelfModel* model = shelf_view_->model(); - ShelfItem item; - item.type = TYPE_APP_SHORTCUT; - const int index = model->Add(item); - const ShelfID id = model->items()[index].id; - model->SetShelfItemDelegate(id, - base::MakeUnique<TestShelfItemDelegate>(nullptr)); - // Note: There's no easy way to correlate shelf a model index/id to its view. - tooltip_manager_->ShowTooltipWithDelay( - shelf_view_->child_at(shelf_view_->child_count() - 1)); - EXPECT_TRUE(IsTimerRunning()); - - // Removing the view won't stop the timer, but the tooltip shouldn't be shown. - model->RemoveItemAt(index); - EXPECT_TRUE(IsTimerRunning()); - RunAllPendingInMessageLoop(); - EXPECT_FALSE(IsTimerRunning()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); -} - -TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsHidden) { - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - - // Create a full-screen window to hide the shelf. - std::unique_ptr<views::Widget> widget = CreateTestWidget(); - widget->SetFullscreen(true); - - // Once the shelf is hidden, the tooltip should be invisible. - ASSERT_EQ(SHELF_HIDDEN, GetPrimaryShelf()->GetVisibilityState()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // Do not show the view if the shelf is hidden. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // ShowTooltipWithDelay doesn't even start the timer for the hidden shelf. - tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); - EXPECT_FALSE(IsTimerRunning()); -} - -TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHideHidden) { - // Create a visible window so auto-hide behavior can actually hide the shelf. - std::unique_ptr<views::Widget> widget = CreateTestWidget(); - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - - GetPrimaryShelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); - GetPrimaryShelf()->UpdateAutoHideState(); - ASSERT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, - GetPrimaryShelf()->auto_hide_behavior()); - ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); - - // Tooltip visibility change for auto hide may take time. - EXPECT_TRUE(tooltip_manager_->IsVisible()); - RunAllPendingInMessageLoop(); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // Do not show the view if the shelf is hidden. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // ShowTooltipWithDelay doesn't even run the timer for the hidden shelf. - tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); - EXPECT_FALSE(IsTimerRunning()); - - // Close the window to show the auto-hide shelf; tooltips should now show. - widget.reset(); - GetPrimaryShelf()->UpdateAutoHideState(); - ASSERT_EQ(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, - GetPrimaryShelf()->auto_hide_behavior()); - ASSERT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); - - // The tooltip should show for an auto-hide-shown shelf. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - EXPECT_TRUE(tooltip_manager_->IsVisible()); - - // ShowTooltipWithDelay should run the timer for an auto-hide-shown shelf. - tooltip_manager_->ShowTooltipWithDelay(shelf_view_->GetAppListButton()); - EXPECT_TRUE(IsTimerRunning()); -} - -TEST_F(ShelfTooltipManagerTest, HideForEvents) { - // TODO: investigate failure in mash. http://crbug.com/695563. - if (WmShell::Get()->IsRunningInMash()) - return; - - ui::test::EventGenerator& generator = GetEventGenerator(); - gfx::Rect shelf_bounds = shelf_view_->GetBoundsInScreen(); - - // Should hide if the mouse exits the shelf area. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.MoveMouseTo(shelf_bounds.CenterPoint()); - generator.SendMouseExit(); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // Should hide if the mouse is pressed in the shelf area. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.MoveMouseTo(shelf_bounds.CenterPoint()); - generator.PressLeftButton(); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // Should hide for touch events in the shelf. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.set_current_location(shelf_bounds.CenterPoint()); - generator.PressTouch(); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - - // Should hide for gesture events in the shelf. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.GestureTapDownAndUp(shelf_bounds.CenterPoint()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); -} - -TEST_F(ShelfTooltipManagerTest, HideForExternalEvents) { - // TODO: investigate failure in mash. http://crbug.com/695563. - if (WmShell::Get()->IsRunningInMash()) - return; - - ui::test::EventGenerator& generator = GetEventGenerator(); - - // Should hide for touches outside the shelf. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.set_current_location(gfx::Point()); - generator.PressTouch(); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - generator.ReleaseTouch(); - - // Should hide for touch events on the tooltip. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.set_current_location( - GetTooltip()->GetWindowBoundsInScreen().CenterPoint()); - generator.PressTouch(); - EXPECT_FALSE(tooltip_manager_->IsVisible()); - generator.ReleaseTouch(); - - // Should hide for gestures outside the shelf. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.GestureTapDownAndUp(gfx::Point()); - EXPECT_FALSE(tooltip_manager_->IsVisible()); -} - -TEST_F(ShelfTooltipManagerTest, DoNotHideForKeyEvents) { - ui::test::EventGenerator& generator = GetEventGenerator(); - - // Should not hide for key events. - tooltip_manager_->ShowTooltip(shelf_view_->GetAppListButton()); - ASSERT_TRUE(tooltip_manager_->IsVisible()); - generator.PressKey(ui::VKEY_A, ui::EF_NONE); - EXPECT_TRUE(tooltip_manager_->IsVisible()); -} - -} // namespace test -} // namespace ash
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc index a483cd8..060018c6 100644 --- a/ash/shelf/shelf_unittest.cc +++ b/ash/shelf/shelf_unittest.cc
@@ -4,14 +4,14 @@ #include <utility> -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" +#include "ash/common/shelf/shelf_button.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/test/test_shelf_item_delegate.h" #include "ash/test/ash_test_base.h" #include "ash/test/shelf_view_test_api.h" -#include "ash/test/test_shelf_item_delegate.h" namespace ash {
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc deleted file mode 100644 index 95e8ced..0000000 --- a/ash/shelf/shelf_view.cc +++ /dev/null
@@ -1,1779 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_view.h" - -#include <algorithm> -#include <memory> - -#include "ash/common/ash_constants.h" -#include "ash/common/scoped_root_window_for_new_windows.h" -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/drag_drop/drag_image_view.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/overflow_bubble.h" -#include "ash/shelf/overflow_bubble_view.h" -#include "ash/shelf/overflow_button.h" -#include "ash/shelf/shelf_application_menu_model.h" -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/wm/root_window_finder.h" -#include "base/auto_reset.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animator.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/events/event_utils.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/point.h" -#include "ui/views/animation/bounds_animator.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/image_button.h" -#include "ui/views/controls/menu/menu_model_adapter.h" -#include "ui/views/controls/menu/menu_runner.h" -#include "ui/views/focus/focus_search.h" -#include "ui/views/view_model.h" -#include "ui/views/view_model_utils.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/core/coordinate_conversion.h" - -using gfx::Animation; -using views::View; - -namespace ash { - -const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM = 0; -const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT = 1; -const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT = 2; -const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT = 3; - -// Default amount content is inset on the left edge. -const int kDefaultLeadingInset = 8; - -// The proportion of the shelf space reserved for non-panel icons. Panels -// may flow into this space but will be put into the overflow bubble if there -// is contention for the space. -const float kReservedNonPanelIconProportion = 0.67f; - -// The distance of the cursor from the outer rim of the shelf before it -// separates. -const int kRipOffDistance = 48; - -// The rip off drag and drop proxy image should get scaled by this factor. -const float kDragAndDropProxyScale = 1.5f; - -// The opacity represents that this partially disappeared item will get removed. -const float kDraggedImageOpacity = 0.5f; - -namespace { - -// A class to temporarily disable a given bounds animator. -class BoundsAnimatorDisabler { - public: - explicit BoundsAnimatorDisabler(views::BoundsAnimator* bounds_animator) - : old_duration_(bounds_animator->GetAnimationDuration()), - bounds_animator_(bounds_animator) { - bounds_animator_->SetAnimationDuration(1); - } - - ~BoundsAnimatorDisabler() { - bounds_animator_->SetAnimationDuration(old_duration_); - } - - private: - // The previous animation duration. - int old_duration_; - // The bounds animator which gets used. - views::BoundsAnimator* bounds_animator_; - - DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorDisabler); -}; - -// Custom FocusSearch used to navigate the shelf in the order items are in -// the ViewModel. -class ShelfFocusSearch : public views::FocusSearch { - public: - explicit ShelfFocusSearch(views::ViewModel* view_model) - : FocusSearch(nullptr, true, true), view_model_(view_model) {} - ~ShelfFocusSearch() override {} - - // views::FocusSearch overrides: - View* FindNextFocusableView(View* starting_view, - bool reverse, - Direction direction, - bool check_starting_view, - views::FocusTraversable** focus_traversable, - View** focus_traversable_view) override { - int index = view_model_->GetIndexOfView(starting_view); - if (index == -1) - return view_model_->view_at(0); - - if (reverse) { - --index; - if (index < 0) - index = view_model_->view_size() - 1; - } else { - ++index; - if (index >= view_model_->view_size()) - index = 0; - } - return view_model_->view_at(index); - } - - private: - views::ViewModel* view_model_; - - DISALLOW_COPY_AND_ASSIGN(ShelfFocusSearch); -}; - -// AnimationDelegate used when inserting a new item. This steadily increases the -// opacity of the layer as the animation progress. -class FadeInAnimationDelegate : public gfx::AnimationDelegate { - public: - explicit FadeInAnimationDelegate(views::View* view) : view_(view) {} - ~FadeInAnimationDelegate() override {} - - // AnimationDelegate overrides: - void AnimationProgressed(const Animation* animation) override { - view_->layer()->SetOpacity(animation->GetCurrentValue()); - view_->layer()->ScheduleDraw(); - } - void AnimationEnded(const Animation* animation) override { - view_->layer()->SetOpacity(1.0f); - view_->layer()->ScheduleDraw(); - } - void AnimationCanceled(const Animation* animation) override { - view_->layer()->SetOpacity(1.0f); - view_->layer()->ScheduleDraw(); - } - - private: - views::View* view_; - - DISALLOW_COPY_AND_ASSIGN(FadeInAnimationDelegate); -}; - -void ReflectItemStatus(const ShelfItem& item, ShelfButton* button) { - switch (item.status) { - case STATUS_CLOSED: - button->ClearState(ShelfButton::STATE_ACTIVE); - button->ClearState(ShelfButton::STATE_RUNNING); - button->ClearState(ShelfButton::STATE_ATTENTION); - break; - case STATUS_RUNNING: - button->ClearState(ShelfButton::STATE_ACTIVE); - button->AddState(ShelfButton::STATE_RUNNING); - button->ClearState(ShelfButton::STATE_ATTENTION); - break; - case STATUS_ACTIVE: - button->AddState(ShelfButton::STATE_ACTIVE); - button->ClearState(ShelfButton::STATE_RUNNING); - button->ClearState(ShelfButton::STATE_ATTENTION); - break; - case STATUS_ATTENTION: - button->ClearState(ShelfButton::STATE_ACTIVE); - button->ClearState(ShelfButton::STATE_RUNNING); - button->AddState(ShelfButton::STATE_ATTENTION); - break; - } -} - -} // namespace - -// AnimationDelegate used when deleting an item. This steadily decreased the -// opacity of the layer as the animation progress. -class ShelfView::FadeOutAnimationDelegate : public gfx::AnimationDelegate { - public: - FadeOutAnimationDelegate(ShelfView* host, views::View* view) - : shelf_view_(host), view_(view) {} - ~FadeOutAnimationDelegate() override {} - - // AnimationDelegate overrides: - void AnimationProgressed(const Animation* animation) override { - view_->layer()->SetOpacity(1 - animation->GetCurrentValue()); - view_->layer()->ScheduleDraw(); - } - void AnimationEnded(const Animation* animation) override { - shelf_view_->OnFadeOutAnimationEnded(); - } - void AnimationCanceled(const Animation* animation) override {} - - private: - ShelfView* shelf_view_; - std::unique_ptr<views::View> view_; - - DISALLOW_COPY_AND_ASSIGN(FadeOutAnimationDelegate); -}; - -// AnimationDelegate used to trigger fading an element in. When an item is -// inserted this delegate is attached to the animation that expands the size of -// the item. When done it kicks off another animation to fade the item in. -class ShelfView::StartFadeAnimationDelegate : public gfx::AnimationDelegate { - public: - StartFadeAnimationDelegate(ShelfView* host, views::View* view) - : shelf_view_(host), view_(view) {} - ~StartFadeAnimationDelegate() override {} - - // AnimationDelegate overrides: - void AnimationEnded(const Animation* animation) override { - shelf_view_->FadeIn(view_); - } - void AnimationCanceled(const Animation* animation) override { - view_->layer()->SetOpacity(1.0f); - } - - private: - ShelfView* shelf_view_; - views::View* view_; - - DISALLOW_COPY_AND_ASSIGN(StartFadeAnimationDelegate); -}; - -// static -const int ShelfView::kMinimumDragDistance = 8; - -ShelfView::ShelfView(ShelfModel* model, - ShelfDelegate* delegate, - WmShelf* wm_shelf, - ShelfWidget* shelf_widget) - : model_(model), - delegate_(delegate), - wm_shelf_(wm_shelf), - shelf_widget_(shelf_widget), - view_model_(new views::ViewModel), - first_visible_index_(0), - last_visible_index_(-1), - overflow_button_(nullptr), - owner_overflow_bubble_(nullptr), - tooltip_(this), - drag_pointer_(NONE), - drag_view_(nullptr), - start_drag_index_(-1), - context_menu_id_(0), - leading_inset_(kDefaultLeadingInset), - cancelling_drag_model_changed_(false), - last_hidden_index_(0), - closing_event_time_(base::TimeTicks()), - drag_and_drop_item_pinned_(false), - drag_and_drop_shelf_id_(0), - drag_replaced_view_(nullptr), - dragged_off_shelf_(false), - snap_back_from_rip_off_view_(nullptr), - overflow_mode_(false), - main_shelf_(nullptr), - dragged_off_from_overflow_to_shelf_(false), - is_repost_event_on_same_item_(false), - last_pressed_index_(-1) { - DCHECK(model_); - DCHECK(delegate_); - DCHECK(wm_shelf_); - DCHECK(shelf_widget_); - bounds_animator_.reset(new views::BoundsAnimator(this)); - bounds_animator_->AddObserver(this); - set_context_menu_controller(this); - focus_search_.reset(new ShelfFocusSearch(view_model_.get())); -} - -ShelfView::~ShelfView() { - bounds_animator_->RemoveObserver(this); - model_->RemoveObserver(this); -} - -void ShelfView::Init() { - model_->AddObserver(this); - - const ShelfItems& items(model_->items()); - for (ShelfItems::const_iterator i = items.begin(); i != items.end(); ++i) { - views::View* child = CreateViewForItem(*i); - child->SetPaintToLayer(); - view_model_->Add(child, static_cast<int>(i - items.begin())); - AddChildView(child); - } - overflow_button_ = new OverflowButton(this, wm_shelf_); - overflow_button_->set_context_menu_controller(this); - ConfigureChildView(overflow_button_); - AddChildView(overflow_button_); - - // We'll layout when our bounds change. -} - -void ShelfView::OnShelfAlignmentChanged() { - overflow_button_->OnShelfAlignmentChanged(); - LayoutToIdealBounds(); - for (int i = 0; i < view_model_->view_size(); ++i) { - if (i >= first_visible_index_ && i <= last_visible_index_) - view_model_->view_at(i)->Layout(); - } - tooltip_.Close(); - if (overflow_bubble_) - overflow_bubble_->Hide(); - // For crbug.com/587931, because AppListButton layout logic is in OnPaint. - AppListButton* app_list_button = GetAppListButton(); - if (app_list_button) - app_list_button->SchedulePaint(); -} - -gfx::Rect ShelfView::GetIdealBoundsOfItemIcon(ShelfID id) { - int index = model_->ItemIndexByID(id); - if (index == -1) - return gfx::Rect(); - // Map all items from overflow area to the overflow button. Note that the - // section between last_index_hidden_ and model_->FirstPanelIndex() is the - // list of invisible panel items. However, these items are currently nowhere - // represented and get dropped instead - see (crbug.com/378907). As such there - // is no way to address them or place them. We therefore move them over the - // overflow button. - if (index > last_visible_index_ && index < model_->FirstPanelIndex()) - index = last_visible_index_ + 1; - const gfx::Rect& ideal_bounds(view_model_->ideal_bounds(index)); - DCHECK_NE(TYPE_APP_LIST, model_->items()[index].type); - views::View* view = view_model_->view_at(index); - CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); - ShelfButton* button = static_cast<ShelfButton*>(view); - gfx::Rect icon_bounds = button->GetIconBounds(); - return gfx::Rect(GetMirroredXWithWidthInView( - ideal_bounds.x() + icon_bounds.x(), icon_bounds.width()), - ideal_bounds.y() + icon_bounds.y(), icon_bounds.width(), - icon_bounds.height()); -} - -void ShelfView::UpdatePanelIconPosition(ShelfID id, - const gfx::Point& midpoint) { - int current_index = model_->ItemIndexByID(id); - int first_panel_index = model_->FirstPanelIndex(); - if (current_index < first_panel_index) - return; - - gfx::Point midpoint_in_view(GetMirroredXInView(midpoint.x()), midpoint.y()); - int target_index = current_index; - while ( - target_index > first_panel_index && - wm_shelf_->PrimaryAxisValue(view_model_->ideal_bounds(target_index).x(), - view_model_->ideal_bounds(target_index).y()) > - wm_shelf_->PrimaryAxisValue(midpoint_in_view.x(), - midpoint_in_view.y())) { - --target_index; - } - while (target_index < view_model_->view_size() - 1 && - wm_shelf_->PrimaryAxisValue( - view_model_->ideal_bounds(target_index).right(), - view_model_->ideal_bounds(target_index).bottom()) < - wm_shelf_->PrimaryAxisValue(midpoint_in_view.x(), - midpoint_in_view.y())) { - ++target_index; - } - if (current_index != target_index) - model_->Move(current_index, target_index); -} - -bool ShelfView::IsShowingMenu() const { - return launcher_menu_runner_.get() && launcher_menu_runner_->IsRunning(); -} - -bool ShelfView::IsShowingOverflowBubble() const { - return overflow_bubble_.get() && overflow_bubble_->IsShowing(); -} - -AppListButton* ShelfView::GetAppListButton() const { - for (int i = 0; i < model_->item_count(); ++i) { - if (model_->items()[i].type == TYPE_APP_LIST) { - views::View* view = view_model_->view_at(i); - CHECK_EQ(AppListButton::kViewClassName, view->GetClassName()); - return static_cast<AppListButton*>(view); - } - } - - NOTREACHED() << "Applist button not found"; - return nullptr; -} - -bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) const { - gfx::Rect tooltip_bounds; - for (int i = 0; i < child_count(); ++i) { - const views::View* child = child_at(i); - if (child != overflow_button_ && ShouldShowTooltipForView(child)) - tooltip_bounds.Union(child->GetMirroredBounds()); - } - return !tooltip_bounds.Contains(cursor_location); -} - -bool ShelfView::ShouldShowTooltipForView(const views::View* view) const { - // TODO(msw): Push this app list state into ShelfItem::shows_tooltip. - if (view == GetAppListButton() && GetAppListButton()->is_showing_app_list()) - return false; - const ShelfItem* item = ShelfItemForView(view); - return item && item->shows_tooltip; -} - -base::string16 ShelfView::GetTitleForView(const views::View* view) const { - const ShelfItem* item = ShelfItemForView(view); - return item ? item->title : base::string16(); -} - -gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() { - gfx::Size preferred_size = GetPreferredSize(); - gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0); - ConvertPointToScreen(this, &origin); - return gfx::Rect(origin, preferred_size); -} - -void ShelfView::ButtonPressed(views::Button* sender, - const ui::Event& event, - views::InkDrop* ink_drop) { - if (sender == overflow_button_) { - ToggleOverflowBubble(); - shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender, - SHELF_ACTION_NONE); - return; - } - - // None of the checks in ShouldEventActivateButton() affects overflow button. - // So, it is safe to be checked after handling overflow button. - if (!ShouldEventActivateButton(sender, event)) - return; - - // Record the index for the last pressed shelf item. - last_pressed_index_ = view_model_->GetIndexOfView(sender); - DCHECK_LT(-1, last_pressed_index_); - - // Place new windows on the same display as the button. - WmWindow* window = WmWindow::Get(sender->GetWidget()->GetNativeWindow()); - scoped_root_window_for_new_windows_.reset( - new ScopedRootWindowForNewWindows(window->GetRootWindow())); - - // Slow down activation animations if shift key is pressed. - std::unique_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations; - if (event.IsShiftDown()) { - slowing_animations.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); - } - - // Collect usage statistics before we decide what to do with the click. - switch (model_->items()[last_pressed_index_].type) { - case TYPE_APP_SHORTCUT: - case TYPE_BROWSER_SHORTCUT: - case TYPE_APP: - WmShell::Get()->RecordUserMetricsAction(UMA_LAUNCHER_CLICK_ON_APP); - break; - - case TYPE_APP_LIST: - WmShell::Get()->RecordUserMetricsAction( - UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON); - break; - - case TYPE_APP_PANEL: - case TYPE_DIALOG: - break; - - case TYPE_UNDEFINED: - NOTREACHED() << "ShelfItemType must be set."; - break; - } - - const int64_t display_id = window->GetDisplayNearestWindow().id(); - ShelfAction performed_action = - model_->GetShelfItemDelegate(model_->items()[last_pressed_index_].id) - ->ItemSelected(event.type(), event.flags(), display_id, - LAUNCH_FROM_UNKNOWN); - - shelf_button_pressed_metric_tracker_.ButtonPressed(event, sender, - performed_action); - - // For the app list menu no TRIGGERED ink drop effect is needed and it - // handles its own ACTIVATED/DEACTIVATED states. - if (performed_action == SHELF_ACTION_NEW_WINDOW_CREATED || - (performed_action != SHELF_ACTION_APP_LIST_SHOWN && - !ShowListMenuForView(model_->items()[last_pressed_index_], sender, event, - ink_drop))) { - ink_drop->AnimateToState(views::InkDropState::ACTION_TRIGGERED); - } - // Allow the menu to clear |scoped_root_window_for_new_windows_| during - // OnMenuClosed. - if (!IsShowingMenu()) - scoped_root_window_for_new_windows_.reset(); -} - -//////////////////////////////////////////////////////////////////////////////// -// ShelfView, FocusTraversable implementation: - -views::FocusSearch* ShelfView::GetFocusSearch() { - return focus_search_.get(); -} - -views::FocusTraversable* ShelfView::GetFocusTraversableParent() { - return parent()->GetFocusTraversable(); -} - -View* ShelfView::GetFocusTraversableParentView() { - return this; -} - -void ShelfView::CreateDragIconProxy( - const gfx::Point& location_in_screen_coordinates, - const gfx::ImageSkia& icon, - views::View* replaced_view, - const gfx::Vector2d& cursor_offset_from_center, - float scale_factor) { - drag_replaced_view_ = replaced_view; - WmWindow* root_window = - WmWindow::Get(drag_replaced_view_->GetWidget()->GetNativeWindow()) - ->GetRootWindow(); - drag_image_.reset(new DragImageView( - root_window, ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE)); - drag_image_->SetImage(icon); - gfx::Size size = drag_image_->GetPreferredSize(); - size.set_width(size.width() * scale_factor); - size.set_height(size.height() * scale_factor); - drag_image_offset_ = gfx::Vector2d(size.width() / 2, size.height() / 2) + - cursor_offset_from_center; - gfx::Rect drag_image_bounds( - location_in_screen_coordinates - drag_image_offset_, size); - drag_image_->SetBoundsInScreen(drag_image_bounds); - drag_image_->SetWidgetVisible(true); -} - -void ShelfView::UpdateDragIconProxy( - const gfx::Point& location_in_screen_coordinates) { - // TODO(jennyz): Investigate why drag_image_ becomes null at this point per - // crbug.com/34722, while the app list item is still being dragged around. - if (drag_image_) { - drag_image_->SetScreenPosition(location_in_screen_coordinates - - drag_image_offset_); - } -} - -void ShelfView::DestroyDragIconProxy() { - drag_image_.reset(); - drag_image_offset_ = gfx::Vector2d(0, 0); -} - -bool ShelfView::StartDrag(const std::string& app_id, - const gfx::Point& location_in_screen_coordinates) { - // Bail if an operation is already going on - or the cursor is not inside. - // This could happen if mouse / touch operations overlap. - if (drag_and_drop_shelf_id_ || - !GetBoundsInScreen().Contains(location_in_screen_coordinates)) - return false; - - // If the AppsGridView (which was dispatching this event) was opened by our - // button, ShelfView dragging operations are locked and we have to unlock. - CancelDrag(-1); - drag_and_drop_item_pinned_ = false; - drag_and_drop_app_id_ = app_id; - drag_and_drop_shelf_id_ = - delegate_->GetShelfIDForAppID(drag_and_drop_app_id_); - // Check if the application is known and pinned - if not, we have to pin it so - // that we can re-arrange the shelf order accordingly. Note that items have - // to be pinned to give them the same (order) possibilities as a shortcut. - // When an item is dragged from overflow to shelf, IsShowingOverflowBubble() - // returns true. At this time, we don't need to pin the item. - if (!IsShowingOverflowBubble() && - (!drag_and_drop_shelf_id_ || !delegate_->IsAppPinned(app_id))) { - delegate_->PinAppWithID(app_id); - drag_and_drop_shelf_id_ = - delegate_->GetShelfIDForAppID(drag_and_drop_app_id_); - if (!drag_and_drop_shelf_id_) - return false; - drag_and_drop_item_pinned_ = true; - } - views::View* drag_and_drop_view = - view_model_->view_at(model_->ItemIndexByID(drag_and_drop_shelf_id_)); - DCHECK(drag_and_drop_view); - - // Since there is already an icon presented by the caller, we hide this item - // for now. That has to be done by reducing the size since the visibility will - // change once a regrouping animation is performed. - pre_drag_and_drop_size_ = drag_and_drop_view->size(); - drag_and_drop_view->SetSize(gfx::Size()); - - // First we have to center the mouse cursor over the item. - gfx::Point pt = drag_and_drop_view->GetBoundsInScreen().CenterPoint(); - views::View::ConvertPointFromScreen(drag_and_drop_view, &pt); - gfx::Point point_in_root = - wm::GetRootWindowAt(location_in_screen_coordinates) - ->ConvertPointFromScreen(location_in_screen_coordinates); - ui::MouseEvent event(ui::ET_MOUSE_PRESSED, pt, point_in_root, - ui::EventTimeForNow(), 0, 0); - PointerPressedOnButton(drag_and_drop_view, DRAG_AND_DROP, event); - - // Drag the item where it really belongs. - Drag(location_in_screen_coordinates); - return true; -} - -bool ShelfView::Drag(const gfx::Point& location_in_screen_coordinates) { - if (!drag_and_drop_shelf_id_ || - !GetBoundsInScreen().Contains(location_in_screen_coordinates)) - return false; - - gfx::Point pt = location_in_screen_coordinates; - views::View* drag_and_drop_view = - view_model_->view_at(model_->ItemIndexByID(drag_and_drop_shelf_id_)); - ConvertPointFromScreen(drag_and_drop_view, &pt); - gfx::Point point_in_root = - wm::GetRootWindowAt(location_in_screen_coordinates) - ->ConvertPointFromScreen(location_in_screen_coordinates); - ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, point_in_root, - ui::EventTimeForNow(), 0, 0); - PointerDraggedOnButton(drag_and_drop_view, DRAG_AND_DROP, event); - return true; -} - -void ShelfView::EndDrag(bool cancel) { - if (!drag_and_drop_shelf_id_) - return; - - views::View* drag_and_drop_view = - view_model_->view_at(model_->ItemIndexByID(drag_and_drop_shelf_id_)); - PointerReleasedOnButton(drag_and_drop_view, DRAG_AND_DROP, cancel); - - // Either destroy the temporarily created item - or - make the item visible. - if (drag_and_drop_item_pinned_ && cancel) { - delegate_->UnpinAppWithID(drag_and_drop_app_id_); - } else if (drag_and_drop_view) { - if (cancel) { - // When a hosted drag gets canceled, the item can remain in the same slot - // and it might have moved within the bounds. In that case the item need - // to animate back to its correct location. - AnimateToIdealBounds(); - } else { - drag_and_drop_view->SetSize(pre_drag_and_drop_size_); - } - } - - drag_and_drop_shelf_id_ = 0; -} - -bool ShelfView::ShouldEventActivateButton(View* view, const ui::Event& event) { - if (dragging()) - return false; - - // Ignore if we are already in a pointer event sequence started with a repost - // event on the same shelf item. See crbug.com/343005 for more detail. - if (is_repost_event_on_same_item_) - return false; - - // Don't activate the item twice on double-click. Otherwise the window starts - // animating open due to the first click, then immediately minimizes due to - // the second click. The user most likely intended to open or minimize the - // item once, not do both. - if (event.flags() & ui::EF_IS_DOUBLE_CLICK) - return false; - - // Ignore if this is a repost event on the last pressed shelf item. - int index = view_model_->GetIndexOfView(view); - if (index == -1) - return false; - return !IsRepostEvent(event) || last_pressed_index_ != index; -} - -void ShelfView::PointerPressedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) { - if (drag_view_) - return; - - int index = view_model_->GetIndexOfView(view); - if (index == -1 || view_model_->view_size() <= 1) - return; // View is being deleted, ignore request. - - if (view == GetAppListButton()) - return; // View is not draggable, ignore request. - - // Only when the repost event occurs on the same shelf item, we should ignore - // the call in ShelfView::ButtonPressed(...). - is_repost_event_on_same_item_ = - IsRepostEvent(event) && (last_pressed_index_ == index); - - CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); - drag_view_ = static_cast<ShelfButton*>(view); - drag_origin_ = gfx::Point(event.x(), event.y()); - UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage", - wm_shelf_->SelectValueForShelfAlignment( - SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM, - SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT, - SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT), - SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT); -} - -void ShelfView::PointerDraggedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) { - // To prepare all drag types (moving an item in the shelf and dragging off), - // we should check the x-axis and y-axis offset. - if (!dragging() && drag_view_ && - ((std::abs(event.x() - drag_origin_.x()) >= kMinimumDragDistance) || - (std::abs(event.y() - drag_origin_.y()) >= kMinimumDragDistance))) { - PrepareForDrag(pointer, event); - } - if (drag_pointer_ == pointer) - ContinueDrag(event); -} - -void ShelfView::PointerReleasedOnButton(views::View* view, - Pointer pointer, - bool canceled) { - is_repost_event_on_same_item_ = false; - - if (canceled) { - CancelDrag(-1); - } else if (drag_pointer_ == pointer) { - FinalizeRipOffDrag(false); - drag_pointer_ = NONE; - AnimateToIdealBounds(); - } - // If the drag pointer is NONE, no drag operation is going on and the - // drag_view can be released. - if (drag_pointer_ == NONE) - drag_view_ = nullptr; -} - -void ShelfView::LayoutToIdealBounds() { - if (bounds_animator_->IsAnimating()) { - AnimateToIdealBounds(); - return; - } - - IdealBounds ideal_bounds; - CalculateIdealBounds(&ideal_bounds); - views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); - overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds); -} - -void ShelfView::UpdateShelfItemBackground(SkColor color) { - GetAppListButton()->UpdateShelfItemBackground(color); - overflow_button_->UpdateShelfItemBackground(color); -} - -void ShelfView::UpdateAllButtonsVisibilityInOverflowMode() { - // The overflow button is not shown in overflow mode. - overflow_button_->SetVisible(false); - DCHECK_LT(last_visible_index_, view_model_->view_size()); - for (int i = 0; i < view_model_->view_size(); ++i) { - bool visible = i >= first_visible_index_ && i <= last_visible_index_; - // To track the dragging of |drag_view_| continuously, its visibility - // should be always true regardless of its position. - if (dragged_off_from_overflow_to_shelf_ && - view_model_->view_at(i) == drag_view_) - view_model_->view_at(i)->SetVisible(true); - else - view_model_->view_at(i)->SetVisible(visible); - } -} - -void ShelfView::CalculateIdealBounds(IdealBounds* bounds) const { - int available_size = wm_shelf_->PrimaryAxisValue(width(), height()); - DCHECK(model_->item_count() == view_model_->view_size()); - if (!available_size) - return; - - int first_panel_index = model_->FirstPanelIndex(); - int last_button_index = first_panel_index - 1; - - int x = 0; - int y = 0; - - int w = wm_shelf_->PrimaryAxisValue(kShelfButtonSize, width()); - int h = wm_shelf_->PrimaryAxisValue(height(), kShelfButtonSize); - for (int i = 0; i < view_model_->view_size(); ++i) { - if (i < first_visible_index_) { - view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0)); - continue; - } - - view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); - x = wm_shelf_->PrimaryAxisValue(x + w + kShelfButtonSpacing, x); - y = wm_shelf_->PrimaryAxisValue(y, y + h + kShelfButtonSpacing); - } - - if (is_overflow_mode()) { - const_cast<ShelfView*>(this)->UpdateAllButtonsVisibilityInOverflowMode(); - return; - } - - // Right aligned icons. - int end_position = available_size; - x = wm_shelf_->PrimaryAxisValue(end_position, 0); - y = wm_shelf_->PrimaryAxisValue(0, end_position); - for (int i = view_model_->view_size() - 1; i >= first_panel_index; --i) { - x = wm_shelf_->PrimaryAxisValue(x - w - kShelfButtonSpacing, x); - y = wm_shelf_->PrimaryAxisValue(y, y - h - kShelfButtonSpacing); - view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); - end_position = wm_shelf_->PrimaryAxisValue(x, y); - } - - // Icons on the left / top are guaranteed up to kLeftIconProportion of - // the available space. - int last_icon_position = - wm_shelf_->PrimaryAxisValue( - view_model_->ideal_bounds(last_button_index).right(), - view_model_->ideal_bounds(last_button_index).bottom()) + - kShelfButtonSpacing; - int reserved_icon_space = available_size * kReservedNonPanelIconProportion; - if (last_icon_position < reserved_icon_space) - end_position = last_icon_position; - else - end_position = std::max(end_position, reserved_icon_space); - - bounds->overflow_bounds.set_size( - gfx::Size(wm_shelf_->PrimaryAxisValue(w, width()), - wm_shelf_->PrimaryAxisValue(height(), h))); - - last_visible_index_ = - DetermineLastVisibleIndex(end_position - kShelfButtonSpacing); - last_hidden_index_ = DetermineFirstVisiblePanelIndex(end_position) - 1; - bool show_overflow = last_visible_index_ < last_button_index || - last_hidden_index_ >= first_panel_index; - - // Create Space for the overflow button - if (show_overflow) { - // The following code makes sure that platform apps icons (aligned to left / - // top) are favored over panel apps icons (aligned to right / bottom). - if (last_visible_index_ > 0 && last_visible_index_ < last_button_index) { - // This condition means that we will take one platform app and replace it - // with the overflow button and put the app in the overflow bubble. - // This happens when the space needed for platform apps exceeds the - // reserved area for non-panel icons, - // (i.e. |last_icon_position| > |reserved_icon_space|). - --last_visible_index_; - } else if (last_hidden_index_ >= first_panel_index && - last_hidden_index_ < view_model_->view_size() - 1) { - // This condition means that we will take a panel app icon and replace it - // with the overflow button. - // This happens when there is still room for platform apps in the reserved - // area for non-panel icons, - // (i.e. |last_icon_position| < |reserved_icon_space|). - ++last_hidden_index_; - } - } - - for (int i = 0; i < view_model_->view_size(); ++i) { - bool visible = i <= last_visible_index_ || i > last_hidden_index_; - // To receive drag event continuously from |drag_view_| during the dragging - // off from the shelf, don't make |drag_view_| invisible. It will be - // eventually invisible and removed from the |view_model_| by - // FinalizeRipOffDrag(). - if (dragged_off_shelf_ && view_model_->view_at(i) == drag_view_) - continue; - view_model_->view_at(i)->SetVisible(visible); - } - - overflow_button_->SetVisible(show_overflow); - if (show_overflow) { - DCHECK_NE(0, view_model_->view_size()); - if (last_visible_index_ == -1) { - x = 0; - y = 0; - } else { - x = wm_shelf_->PrimaryAxisValue( - view_model_->ideal_bounds(last_visible_index_).right(), - view_model_->ideal_bounds(last_visible_index_).x()); - y = wm_shelf_->PrimaryAxisValue( - view_model_->ideal_bounds(last_visible_index_).y(), - view_model_->ideal_bounds(last_visible_index_).bottom()); - } - - if (last_visible_index_ >= 0) { - // Add more space between last visible item and overflow button. - // Without this, two buttons look too close compared with other items. - x = wm_shelf_->PrimaryAxisValue(x + kShelfButtonSpacing, x); - y = wm_shelf_->PrimaryAxisValue(y, y + kShelfButtonSpacing); - } - - // Set all hidden panel icon positions to be on the overflow button. - for (int i = first_panel_index; i <= last_hidden_index_; ++i) - view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h)); - - bounds->overflow_bounds.set_x(x); - bounds->overflow_bounds.set_y(y); - if (overflow_bubble_.get() && overflow_bubble_->IsShowing()) - UpdateOverflowRange(overflow_bubble_->shelf_view()); - } else { - if (overflow_bubble_) - overflow_bubble_->Hide(); - } -} - -int ShelfView::DetermineLastVisibleIndex(int max_value) const { - int index = model_->FirstPanelIndex() - 1; - while (index >= 0 && - wm_shelf_->PrimaryAxisValue( - view_model_->ideal_bounds(index).right(), - view_model_->ideal_bounds(index).bottom()) > max_value) { - index--; - } - return index; -} - -int ShelfView::DetermineFirstVisiblePanelIndex(int min_value) const { - int index = model_->FirstPanelIndex(); - while (index < view_model_->view_size() && - wm_shelf_->PrimaryAxisValue(view_model_->ideal_bounds(index).x(), - view_model_->ideal_bounds(index).y()) < - min_value) { - ++index; - } - return index; -} - -void ShelfView::AnimateToIdealBounds() { - IdealBounds ideal_bounds; - CalculateIdealBounds(&ideal_bounds); - for (int i = 0; i < view_model_->view_size(); ++i) { - View* view = view_model_->view_at(i); - bounds_animator_->AnimateViewTo(view, view_model_->ideal_bounds(i)); - // Now that the item animation starts, we have to make sure that the - // padding of the first gets properly transferred to the new first item. - if (i && view->border()) - view->SetBorder(views::NullBorder()); - } - overflow_button_->SetBoundsRect(ideal_bounds.overflow_bounds); -} - -views::View* ShelfView::CreateViewForItem(const ShelfItem& item) { - views::View* view = nullptr; - switch (item.type) { - case TYPE_APP_PANEL: - case TYPE_APP_SHORTCUT: - case TYPE_BROWSER_SHORTCUT: - case TYPE_APP: - case TYPE_DIALOG: { - ShelfButton* button = new ShelfButton(this, this); - button->SetImage(item.image); - ReflectItemStatus(item, button); - view = button; - break; - } - - case TYPE_APP_LIST: { - view = new AppListButton(this, this, wm_shelf_); - break; - } - - case TYPE_UNDEFINED: - return nullptr; - } - - view->set_context_menu_controller(this); - ConfigureChildView(view); - return view; -} - -void ShelfView::FadeIn(views::View* view) { - view->SetVisible(true); - view->layer()->SetOpacity(0); - AnimateToIdealBounds(); - bounds_animator_->SetAnimationDelegate( - view, std::unique_ptr<gfx::AnimationDelegate>( - new FadeInAnimationDelegate(view))); -} - -void ShelfView::PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event) { - DCHECK(!dragging()); - DCHECK(drag_view_); - drag_pointer_ = pointer; - start_drag_index_ = view_model_->GetIndexOfView(drag_view_); - - if (start_drag_index_ == -1) { - CancelDrag(-1); - return; - } - - // Move the view to the front so that it appears on top of other views. - ReorderChildView(drag_view_, -1); - bounds_animator_->StopAnimatingView(drag_view_); - - drag_view_->OnDragStarted(&event); -} - -void ShelfView::ContinueDrag(const ui::LocatedEvent& event) { - DCHECK(dragging()); - DCHECK(drag_view_); - // Due to a syncing operation the application might have been removed. - // Bail if it is gone. - int current_index = view_model_->GetIndexOfView(drag_view_); - DCHECK_NE(-1, current_index); - - // If this is not a drag and drop host operation and not the app list item, - // check if the item got ripped off the shelf - if it did we are done. - if (!drag_and_drop_shelf_id_ && - RemovableByRipOff(current_index) != NOT_REMOVABLE) { - if (HandleRipOffDrag(event)) - return; - // The rip off handler could have changed the location of the item. - current_index = view_model_->GetIndexOfView(drag_view_); - } - - // TODO: I don't think this works correctly with RTL. - gfx::Point drag_point(event.location()); - ConvertPointToTarget(drag_view_, this, &drag_point); - - // Constrain the location to the range of valid indices for the type. - std::pair<int, int> indices(GetDragRange(current_index)); - int first_drag_index = indices.first; - int last_drag_index = indices.second; - // If the last index isn't valid, we're overflowing. Constrain to the app list - // (which is the last visible item). - if (first_drag_index < model_->FirstPanelIndex() && - last_drag_index > last_visible_index_) - last_drag_index = last_visible_index_; - int x = 0, y = 0; - if (wm_shelf_->IsHorizontalAlignment()) { - x = std::max(view_model_->ideal_bounds(indices.first).x(), - drag_point.x() - drag_origin_.x()); - x = std::min(view_model_->ideal_bounds(last_drag_index).right() - - view_model_->ideal_bounds(current_index).width(), - x); - if (drag_view_->x() == x) - return; - drag_view_->SetX(x); - } else { - y = std::max(view_model_->ideal_bounds(indices.first).y(), - drag_point.y() - drag_origin_.y()); - y = std::min(view_model_->ideal_bounds(last_drag_index).bottom() - - view_model_->ideal_bounds(current_index).height(), - y); - if (drag_view_->y() == y) - return; - drag_view_->SetY(y); - } - - int target_index = views::ViewModelUtils::DetermineMoveIndex( - *view_model_, drag_view_, - wm_shelf_->IsHorizontalAlignment() ? views::ViewModelUtils::HORIZONTAL - : views::ViewModelUtils::VERTICAL, - x, y); - target_index = - std::min(indices.second, std::max(target_index, indices.first)); - - // The app list button is always first, and it is the only non-draggable item. - int first_draggable_item = model_->GetItemIndexForType(TYPE_APP_LIST) + 1; - DCHECK_EQ(1, first_draggable_item); - target_index = std::max(target_index, first_draggable_item); - DCHECK_LT(target_index, model_->item_count()); - - if (target_index == current_index) - return; - - // Change the model, the ShelfItemMoved() callback will handle the - // |view_model_| update. - model_->Move(current_index, target_index); - bounds_animator_->StopAnimatingView(drag_view_); -} - -bool ShelfView::HandleRipOffDrag(const ui::LocatedEvent& event) { - int current_index = view_model_->GetIndexOfView(drag_view_); - DCHECK_NE(-1, current_index); - std::string dragged_app_id = - delegate_->GetAppIDForShelfID(model_->items()[current_index].id); - - gfx::Point screen_location = - WmWindow::Get(GetWidget()->GetNativeWindow()) - ->GetRootWindow() - ->ConvertPointToScreen(event.root_location()); - - // To avoid ugly forwards and backwards flipping we use different constants - // for ripping off / re-inserting the items. - if (dragged_off_shelf_) { - // If the shelf/overflow bubble bounds contains |screen_location| we insert - // the item back into the shelf. - if (GetBoundsForDragInsertInScreen().Contains(screen_location)) { - if (dragged_off_from_overflow_to_shelf_) { - // During the dragging an item from Shelf to Overflow, it can enter here - // directly because both are located very closly. - main_shelf_->EndDrag(true); - // Stops the animation of |drag_view_| and sets its bounds explicitly - // becase ContinueDrag() stops its animation. Without this, unexpected - // bounds will be set. - bounds_animator_->StopAnimatingView(drag_view_); - int drag_view_index = view_model_->GetIndexOfView(drag_view_); - drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index)); - dragged_off_from_overflow_to_shelf_ = false; - } - // Destroy our proxy view item. - DestroyDragIconProxy(); - // Re-insert the item and return simply false since the caller will handle - // the move as in any normal case. - dragged_off_shelf_ = false; - drag_view_->layer()->SetOpacity(1.0f); - // The size of Overflow bubble should be updated immediately when an item - // is re-inserted. - if (is_overflow_mode()) - PreferredSizeChanged(); - return false; - } else if (is_overflow_mode() && - main_shelf_->GetBoundsForDragInsertInScreen().Contains( - screen_location)) { - if (!dragged_off_from_overflow_to_shelf_) { - dragged_off_from_overflow_to_shelf_ = true; - drag_image_->SetOpacity(1.0f); - main_shelf_->StartDrag(dragged_app_id, screen_location); - } else { - main_shelf_->Drag(screen_location); - } - } else if (dragged_off_from_overflow_to_shelf_) { - // Makes the |drag_image_| partially disappear again. - dragged_off_from_overflow_to_shelf_ = false; - drag_image_->SetOpacity(kDraggedImageOpacity); - main_shelf_->EndDrag(true); - bounds_animator_->StopAnimatingView(drag_view_); - int drag_view_index = view_model_->GetIndexOfView(drag_view_); - drag_view_->SetBoundsRect(view_model_->ideal_bounds(drag_view_index)); - } - // Move our proxy view item. - UpdateDragIconProxy(screen_location); - return true; - } - // Check if we are too far away from the shelf to enter the ripped off state. - // Determine the distance to the shelf. - int delta = CalculateShelfDistance(screen_location); - if (delta > kRipOffDistance) { - // Create a proxy view item which can be moved anywhere. - CreateDragIconProxy(event.root_location(), drag_view_->GetImage(), - drag_view_, gfx::Vector2d(0, 0), - kDragAndDropProxyScale); - drag_view_->layer()->SetOpacity(0.0f); - dragged_off_shelf_ = true; - if (RemovableByRipOff(current_index) == REMOVABLE) { - // Move the item to the front of the first panel item and hide it. - // ShelfItemMoved() callback will handle the |view_model_| update and - // call AnimateToIdealBounds(). - if (current_index != model_->FirstPanelIndex() - 1) { - model_->Move(current_index, model_->FirstPanelIndex() - 1); - StartFadeInLastVisibleItem(); - } else if (is_overflow_mode()) { - // Overflow bubble should be shrunk when an item is ripped off. - PreferredSizeChanged(); - } - // Make the item partially disappear to show that it will get removed if - // dropped. - drag_image_->SetOpacity(kDraggedImageOpacity); - } - return true; - } - return false; -} - -void ShelfView::FinalizeRipOffDrag(bool cancel) { - if (!dragged_off_shelf_) - return; - // Make sure we do not come in here again. - dragged_off_shelf_ = false; - - // Coming here we should always have a |drag_view_|. - DCHECK(drag_view_); - int current_index = view_model_->GetIndexOfView(drag_view_); - // If the view isn't part of the model anymore (|current_index| == -1), a sync - // operation must have removed it. In that case we shouldn't change the model - // and only delete the proxy image. - if (current_index == -1) { - DestroyDragIconProxy(); - return; - } - - // Set to true when the animation should snap back to where it was before. - bool snap_back = false; - // Items which cannot be dragged off will be handled as a cancel. - if (!cancel) { - if (dragged_off_from_overflow_to_shelf_) { - dragged_off_from_overflow_to_shelf_ = false; - main_shelf_->EndDrag(false); - drag_view_->layer()->SetOpacity(1.0f); - } else if (RemovableByRipOff(current_index) != REMOVABLE) { - // Make sure we do not try to remove un-removable items like items which - // were not pinned or have to be always there. - cancel = true; - snap_back = true; - } else { - // Make sure the item stays invisible upon removal. - drag_view_->SetVisible(false); - std::string app_id = - delegate_->GetAppIDForShelfID(model_->items()[current_index].id); - delegate_->UnpinAppWithID(app_id); - } - } - if (cancel || snap_back) { - if (dragged_off_from_overflow_to_shelf_) { - dragged_off_from_overflow_to_shelf_ = false; - // Main shelf handles revert of dragged item. - main_shelf_->EndDrag(true); - drag_view_->layer()->SetOpacity(1.0f); - } else if (!cancelling_drag_model_changed_) { - // Only do something if the change did not come through a model change. - gfx::Rect drag_bounds = drag_image_->GetBoundsInScreen(); - gfx::Point relative_to = GetBoundsInScreen().origin(); - gfx::Rect target( - gfx::PointAtOffsetFromOrigin(drag_bounds.origin() - relative_to), - drag_bounds.size()); - drag_view_->SetBoundsRect(target); - // Hide the status from the active item since we snap it back now. Upon - // animation end the flag gets cleared if |snap_back_from_rip_off_view_| - // is set. - snap_back_from_rip_off_view_ = drag_view_; - drag_view_->AddState(ShelfButton::STATE_HIDDEN); - // When a canceling drag model is happening, the view model is diverged - // from the menu model and movements / animations should not be done. - model_->Move(current_index, start_drag_index_); - AnimateToIdealBounds(); - } - drag_view_->layer()->SetOpacity(1.0f); - } - DestroyDragIconProxy(); -} - -ShelfView::RemovableState ShelfView::RemovableByRipOff(int index) const { - DCHECK(index >= 0 && index < model_->item_count()); - ShelfItemType type = model_->items()[index].type; - if (type == TYPE_APP_LIST || type == TYPE_DIALOG) - return NOT_REMOVABLE; - - if (model_->items()[index].pinned_by_policy) - return NOT_REMOVABLE; - - // Note: Only pinned app shortcuts can be removed! - std::string app_id = delegate_->GetAppIDForShelfID(model_->items()[index].id); - return (type == TYPE_APP_SHORTCUT && delegate_->IsAppPinned(app_id)) - ? REMOVABLE - : DRAGGABLE; -} - -bool ShelfView::SameDragType(ShelfItemType typea, ShelfItemType typeb) const { - switch (typea) { - case TYPE_APP_SHORTCUT: - case TYPE_BROWSER_SHORTCUT: - return (typeb == TYPE_APP_SHORTCUT || typeb == TYPE_BROWSER_SHORTCUT); - case TYPE_APP_PANEL: - case TYPE_APP_LIST: - case TYPE_APP: - case TYPE_DIALOG: - return typeb == typea; - case TYPE_UNDEFINED: - NOTREACHED() << "ShelfItemType must be set."; - return false; - } - NOTREACHED(); - return false; -} - -std::pair<int, int> ShelfView::GetDragRange(int index) { - int min_index = -1; - int max_index = -1; - ShelfItemType type = model_->items()[index].type; - for (int i = 0; i < model_->item_count(); ++i) { - if (SameDragType(model_->items()[i].type, type)) { - if (min_index == -1) - min_index = i; - max_index = i; - } - } - return std::pair<int, int>(min_index, max_index); -} - -void ShelfView::ConfigureChildView(views::View* view) { - view->SetPaintToLayer(); - view->layer()->SetFillsBoundsOpaquely(false); -} - -void ShelfView::ToggleOverflowBubble() { - if (IsShowingOverflowBubble()) { - overflow_bubble_->Hide(); - return; - } - - if (!overflow_bubble_) - overflow_bubble_.reset(new OverflowBubble(wm_shelf_)); - - ShelfView* overflow_view = - new ShelfView(model_, delegate_, wm_shelf_, shelf_widget_); - overflow_view->overflow_mode_ = true; - overflow_view->Init(); - overflow_view->set_owner_overflow_bubble(overflow_bubble_.get()); - overflow_view->OnShelfAlignmentChanged(); - overflow_view->main_shelf_ = this; - UpdateOverflowRange(overflow_view); - - overflow_bubble_->Show(overflow_button_, overflow_view); - - wm_shelf_->UpdateVisibilityState(); -} - -void ShelfView::OnFadeOutAnimationEnded() { - AnimateToIdealBounds(); - StartFadeInLastVisibleItem(); -} - -void ShelfView::StartFadeInLastVisibleItem() { - // If overflow button is visible and there is a valid new last item, fading - // the new last item in after sliding animation is finished. - if (overflow_button_->visible() && last_visible_index_ >= 0) { - views::View* last_visible_view = view_model_->view_at(last_visible_index_); - last_visible_view->layer()->SetOpacity(0); - bounds_animator_->SetAnimationDelegate( - last_visible_view, - std::unique_ptr<gfx::AnimationDelegate>( - new StartFadeAnimationDelegate(this, last_visible_view))); - } -} - -void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const { - const int first_overflow_index = last_visible_index_ + 1; - const int last_overflow_index = last_hidden_index_; - DCHECK_LE(first_overflow_index, last_overflow_index); - DCHECK_LT(last_overflow_index, view_model_->view_size()); - - overflow_view->first_visible_index_ = first_overflow_index; - overflow_view->last_visible_index_ = last_overflow_index; -} - -gfx::Rect ShelfView::GetBoundsForDragInsertInScreen() { - gfx::Size preferred_size; - if (is_overflow_mode()) { - DCHECK(owner_overflow_bubble_); - gfx::Rect bubble_bounds = - owner_overflow_bubble_->bubble_view()->GetBubbleBounds(); - preferred_size = bubble_bounds.size(); - } else { - const int last_button_index = view_model_->view_size() - 1; - gfx::Rect last_button_bounds = - view_model_->view_at(last_button_index)->bounds(); - if (overflow_button_->visible() && - model_->GetItemIndexForType(TYPE_APP_PANEL) == -1) { - // When overflow button is visible and shelf has no panel items, - // last_button_bounds should be overflow button's bounds. - last_button_bounds = overflow_button_->bounds(); - } - - if (wm_shelf_->IsHorizontalAlignment()) { - preferred_size = gfx::Size(last_button_bounds.right() + leading_inset_, - GetShelfConstant(SHELF_SIZE)); - } else { - preferred_size = gfx::Size(GetShelfConstant(SHELF_SIZE), - last_button_bounds.bottom() + leading_inset_); - } - } - gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0); - - // In overflow mode, we should use OverflowBubbleView as a source for - // converting |origin| to screen coordinates. When a scroll operation is - // occurred in OverflowBubble, the bounds of ShelfView in OverflowBubble can - // be changed. - if (is_overflow_mode()) - ConvertPointToScreen(owner_overflow_bubble_->bubble_view(), &origin); - else - ConvertPointToScreen(this, &origin); - - return gfx::Rect(origin, preferred_size); -} - -int ShelfView::CancelDrag(int modified_index) { - FinalizeRipOffDrag(true); - if (!drag_view_) - return modified_index; - bool was_dragging = dragging(); - int drag_view_index = view_model_->GetIndexOfView(drag_view_); - drag_pointer_ = NONE; - drag_view_ = nullptr; - if (drag_view_index == modified_index) { - // The view that was being dragged is being modified. Don't do anything. - return modified_index; - } - if (!was_dragging) - return modified_index; - - // Restore previous position, tracking the position of the modified view. - bool at_end = modified_index == view_model_->view_size(); - views::View* modified_view = (modified_index >= 0 && !at_end) - ? view_model_->view_at(modified_index) - : nullptr; - model_->Move(drag_view_index, start_drag_index_); - - // If the modified view will be at the end of the list, return the new end of - // the list. - if (at_end) - return view_model_->view_size(); - return modified_view ? view_model_->GetIndexOfView(modified_view) : -1; -} - -gfx::Size ShelfView::GetPreferredSize() const { - IdealBounds ideal_bounds; - CalculateIdealBounds(&ideal_bounds); - const int shelf_size = GetShelfConstant(SHELF_SIZE); - - int last_button_index = last_visible_index_; - if (!is_overflow_mode()) { - if (last_hidden_index_ < view_model_->view_size() - 1) - last_button_index = view_model_->view_size() - 1; - else if (overflow_button_ && overflow_button_->visible()) - last_button_index++; - } - - // When an item is dragged off from the overflow bubble, it is moved to last - // position and and changed to invisible. Overflow bubble size should be - // shrunk to fit only for visible items. - // If |dragged_off_from_overflow_to_shelf_| is set, there will be no invisible - // items in the shelf. - if (is_overflow_mode() && dragged_off_shelf_ && - !dragged_off_from_overflow_to_shelf_ && - RemovableByRipOff(view_model_->GetIndexOfView(drag_view_)) == REMOVABLE) - last_button_index--; - - const gfx::Rect last_button_bounds = - last_button_index >= first_visible_index_ - ? view_model_->ideal_bounds(last_button_index) - : gfx::Rect(gfx::Size(shelf_size, shelf_size)); - - if (wm_shelf_->IsHorizontalAlignment()) - return gfx::Size(last_button_bounds.right() + leading_inset_, shelf_size); - - return gfx::Size(shelf_size, last_button_bounds.bottom() + leading_inset_); -} - -void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) { - // This bounds change is produced by the shelf movement and all content has - // to follow. Using an animation at that time would produce a time lag since - // the animation of the BoundsAnimator has itself a delay before it arrives - // at the required location. As such we tell the animator to go there - // immediately. - BoundsAnimatorDisabler disabler(bounds_animator_.get()); - LayoutToIdealBounds(); - wm_shelf_->NotifyShelfIconPositionsChanged(); - - if (IsShowingOverflowBubble()) - overflow_bubble_->Hide(); -} - -views::FocusTraversable* ShelfView::GetPaneFocusTraversable() { - return this; -} - -void ShelfView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_TOOLBAR; - node_data->SetName(l10n_util::GetStringUTF8(IDS_ASH_SHELF_ACCESSIBLE_NAME)); -} - -void ShelfView::ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) { - if (details.is_add && details.child == this) - tooltip_.Init(); -} - -void ShelfView::OnGestureEvent(ui::GestureEvent* event) { - if (wm_shelf_->ProcessGestureEvent(*event)) - event->StopPropagation(); -} - -void ShelfView::ShelfItemAdded(int model_index) { - { - base::AutoReset<bool> cancelling_drag(&cancelling_drag_model_changed_, - true); - model_index = CancelDrag(model_index); - } - views::View* view = CreateViewForItem(model_->items()[model_index]); - AddChildView(view); - // Hide the view, it'll be made visible when the animation is done. Using - // opacity 0 here to avoid messing with CalculateIdealBounds which touches - // the view's visibility. - view->layer()->SetOpacity(0); - view_model_->Add(view, model_index); - - // Give the button its ideal bounds. That way if we end up animating the - // button before this animation completes it doesn't appear at some random - // spot (because it was in the middle of animating from 0,0 0x0 to its - // target). - IdealBounds ideal_bounds; - CalculateIdealBounds(&ideal_bounds); - view->SetBoundsRect(view_model_->ideal_bounds(model_index)); - - // The first animation moves all the views to their target position. |view| - // is hidden, so it visually appears as though we are providing space for - // it. When done we'll fade the view in. - AnimateToIdealBounds(); - if (model_index <= last_visible_index_ || - model_index >= model_->FirstPanelIndex()) { - bounds_animator_->SetAnimationDelegate( - view, std::unique_ptr<gfx::AnimationDelegate>( - new StartFadeAnimationDelegate(this, view))); - } else { - // Undo the hiding if animation does not run. - view->layer()->SetOpacity(1.0f); - } -} - -void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) { - if (id == context_menu_id_) - launcher_menu_runner_->Cancel(); - { - base::AutoReset<bool> cancelling_drag(&cancelling_drag_model_changed_, - true); - model_index = CancelDrag(model_index); - } - views::View* view = view_model_->view_at(model_index); - view_model_->Remove(model_index); - - // When the overflow bubble is visible, the overflow range needs to be set - // before CalculateIdealBounds() gets called. Otherwise CalculateIdealBounds() - // could trigger a ShelfItemChanged() by hiding the overflow bubble and - // since the overflow bubble is not yet synced with the ShelfModel this - // could cause a crash. - if (overflow_bubble_ && overflow_bubble_->IsShowing()) { - last_hidden_index_ = - std::min(last_hidden_index_, view_model_->view_size() - 1); - UpdateOverflowRange(overflow_bubble_->shelf_view()); - } - - if (view->visible()) { - // The first animation fades out the view. When done we'll animate the rest - // of the views to their target location. - bounds_animator_->AnimateViewTo(view, view->bounds()); - bounds_animator_->SetAnimationDelegate( - view, std::unique_ptr<gfx::AnimationDelegate>( - new FadeOutAnimationDelegate(this, view))); - } else { - // We don't need to show a fade out animation for invisible |view|. When an - // item is ripped out from the shelf, its |view| is already invisible. - AnimateToIdealBounds(); - } - - if (view == tooltip_.GetCurrentAnchorView()) - tooltip_.Close(); -} - -void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) { - const ShelfItem& item(model_->items()[model_index]); - if (old_item.type != item.type) { - // Type changed, swap the views. - model_index = CancelDrag(model_index); - std::unique_ptr<views::View> old_view(view_model_->view_at(model_index)); - bounds_animator_->StopAnimatingView(old_view.get()); - // Removing and re-inserting a view in our view model will strip the ideal - // bounds from the item. To avoid recalculation of everything the bounds - // get remembered and restored after the insertion to the previous value. - gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index); - view_model_->Remove(model_index); - views::View* new_view = CreateViewForItem(item); - AddChildView(new_view); - view_model_->Add(new_view, model_index); - view_model_->set_ideal_bounds(model_index, old_ideal_bounds); - new_view->SetBoundsRect(old_view->bounds()); - if (overflow_button_ && overflow_button_->visible()) - AnimateToIdealBounds(); - else - bounds_animator_->AnimateViewTo(new_view, old_ideal_bounds); - return; - } - - views::View* view = view_model_->view_at(model_index); - switch (item.type) { - case TYPE_APP_PANEL: - case TYPE_APP_SHORTCUT: - case TYPE_BROWSER_SHORTCUT: - case TYPE_APP: - case TYPE_DIALOG: { - CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); - ShelfButton* button = static_cast<ShelfButton*>(view); - ReflectItemStatus(item, button); - button->SetImage(item.image); - button->SchedulePaint(); - break; - } - - default: - break; - } -} - -void ShelfView::ShelfItemMoved(int start_index, int target_index) { - view_model_->Move(start_index, target_index); - // When cancelling a drag due to a shelf item being added, the currently - // dragged item is moved back to its initial position. AnimateToIdealBounds - // will be called again when the new item is added to the |view_model_| but - // at this time the |view_model_| is inconsistent with the |model_|. - if (!cancelling_drag_model_changed_) - AnimateToIdealBounds(); -} - -void ShelfView::OnSetShelfItemDelegate(ShelfID id, - ShelfItemDelegate* item_delegate) {} - -bool ShelfView::ShowListMenuForView(const ShelfItem& item, - views::View* source, - const ui::Event& event, - views::InkDrop* ink_drop) { - ShelfItemDelegate* item_delegate = model_->GetShelfItemDelegate(item.id); - ShelfAppMenuItemList items = item_delegate->GetAppMenuItems(event.flags()); - - // The application list menu should only show for two or more items; return - // false here to ensure that other behavior is triggered (eg. activating or - // minimizing a single associated window, or launching a pinned shelf item). - if (items.size() < 2) - return false; - - ink_drop->AnimateToState(views::InkDropState::ACTIVATED); - context_menu_id_ = item.id; - ShowMenu(base::MakeUnique<ShelfApplicationMenuModel>( - item.title, std::move(items), item_delegate), - source, gfx::Point(), false, ui::GetMenuSourceTypeForEvent(event), - ink_drop); - return true; -} - -void ShelfView::ShowContextMenuForView(views::View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) { - last_pressed_index_ = -1; - - const ShelfItem* item = ShelfItemForView(source); - if (!item) { - WmShell::Get()->ShowContextMenu(point, source_type); - return; - } - - std::unique_ptr<ui::MenuModel> context_menu_model( - WmShell::Get()->delegate()->CreateContextMenu(wm_shelf_, item)); - if (!context_menu_model) - return; - - context_menu_id_ = item ? item->id : 0; - ShowMenu(std::move(context_menu_model), source, point, true, source_type, - nullptr); -} - -void ShelfView::ShowMenu(std::unique_ptr<ui::MenuModel> menu_model, - views::View* source, - const gfx::Point& click_point, - bool context_menu, - ui::MenuSourceType source_type, - views::InkDrop* ink_drop) { - menu_model_ = std::move(menu_model); - menu_model_adapter_.reset(new views::MenuModelAdapter( - menu_model_.get(), - base::Bind(&ShelfView::OnMenuClosed, base::Unretained(this), ink_drop))); - - closing_event_time_ = base::TimeTicks(); - int run_types = views::MenuRunner::ASYNC; - if (context_menu) - run_types |= views::MenuRunner::CONTEXT_MENU; - launcher_menu_runner_.reset( - new views::MenuRunner(menu_model_adapter_->CreateMenu(), run_types)); - - // Place new windows on the same display as the button that spawned the menu. - WmWindow* window = WmWindow::Get(source->GetWidget()->GetNativeWindow()); - scoped_root_window_for_new_windows_.reset( - new ScopedRootWindowForNewWindows(window->GetRootWindow())); - - views::MenuAnchorPosition menu_alignment = views::MENU_ANCHOR_TOPLEFT; - gfx::Rect anchor = gfx::Rect(click_point, gfx::Size()); - - if (!context_menu) { - // Application lists use a bubble. - // It is possible to invoke the menu while it is sliding into view. To cover - // that case, the screen coordinates are offsetted by the animation delta. - anchor = source->GetBoundsInScreen() + (window->GetTargetBounds().origin() - - window->GetBounds().origin()); - - // Adjust the anchor location for shelf items with asymmetrical borders. - if (source->border()) - anchor.Inset(source->border()->GetInsets()); - - // Determine the menu alignment dependent on the shelf. - switch (wm_shelf_->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - menu_alignment = views::MENU_ANCHOR_BUBBLE_ABOVE; - break; - case SHELF_ALIGNMENT_LEFT: - menu_alignment = views::MENU_ANCHOR_BUBBLE_RIGHT; - break; - case SHELF_ALIGNMENT_RIGHT: - menu_alignment = views::MENU_ANCHOR_BUBBLE_LEFT; - break; - } - } - - // NOTE: if you convert to HAS_MNEMONICS be sure to update menu building code. - launcher_menu_runner_->RunMenuAt(source->GetWidget(), nullptr, anchor, - menu_alignment, source_type); -} - -void ShelfView::OnMenuClosed(views::InkDrop* ink_drop) { - context_menu_id_ = 0; - - // Hide the hide overflow bubble after showing a context menu for its items. - if (owner_overflow_bubble_) - owner_overflow_bubble_->Hide(); - - closing_event_time_ = launcher_menu_runner_->closing_event_time(); - - if (ink_drop) - ink_drop->AnimateToState(views::InkDropState::DEACTIVATED); - - launcher_menu_runner_.reset(); - menu_model_adapter_.reset(); - menu_model_.reset(); - scoped_root_window_for_new_windows_.reset(); - - // Auto-hide or alignment might have changed, but only for this shelf. - wm_shelf_->UpdateVisibilityState(); -} - -void ShelfView::OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) { - wm_shelf_->NotifyShelfIconPositionsChanged(); - PreferredSizeChanged(); -} - -void ShelfView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { - if (snap_back_from_rip_off_view_ && animator == bounds_animator_.get()) { - if (!animator->IsAnimating(snap_back_from_rip_off_view_)) { - // Coming here the animation of the ShelfButton is finished and the - // previously hidden status can be shown again. Since the button itself - // might have gone away or changed locations we check that the button - // is still in the shelf and show its status again. - for (int index = 0; index < view_model_->view_size(); index++) { - views::View* view = view_model_->view_at(index); - if (view == snap_back_from_rip_off_view_) { - CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); - ShelfButton* button = static_cast<ShelfButton*>(view); - button->ClearState(ShelfButton::STATE_HIDDEN); - break; - } - } - snap_back_from_rip_off_view_ = nullptr; - } - } -} - -bool ShelfView::IsRepostEvent(const ui::Event& event) { - if (closing_event_time_.is_null()) - return false; - - // If the current (press down) event is a repost event, the time stamp of - // these two events should be the same. - return closing_event_time_ == event.time_stamp(); -} - -const ShelfItem* ShelfView::ShelfItemForView(const views::View* view) const { - const int view_index = view_model_->GetIndexOfView(view); - return (view_index < 0) ? nullptr : &(model_->items()[view_index]); -} - -int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const { - const gfx::Rect bounds = GetBoundsInScreen(); - int distance = wm_shelf_->SelectValueForShelfAlignment( - bounds.y() - coordinate.y(), coordinate.x() - bounds.right(), - bounds.x() - coordinate.x()); - return distance > 0 ? distance : 0; -} - -} // namespace ash
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h deleted file mode 100644 index 1355fc7..0000000 --- a/ash/shelf/shelf_view.h +++ /dev/null
@@ -1,470 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_VIEW_H_ -#define ASH_SHELF_SHELF_VIEW_H_ - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "ash/shelf/ink_drop_button_listener.h" -#include "ash/shelf/shelf_button_pressed_metric_tracker.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_model_observer.h" -#include "ash/shelf/shelf_tooltip_manager.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/app_list/views/app_list_drag_and_drop_host.h" -#include "ui/views/animation/bounds_animator_observer.h" -#include "ui/views/animation/ink_drop_state.h" -#include "ui/views/context_menu_controller.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/focus/focus_manager.h" -#include "ui/views/view.h" -#include "ui/views/view_model.h" - -namespace ui { -class MenuModel; -} - -namespace views { -class BoundsAnimator; -class MenuModelAdapter; -class MenuRunner; -} - -namespace ash { -class AppListButton; -class DragImageView; -class OverflowBubble; -class OverflowButton; -class ScopedRootWindowForNewWindows; -class ShelfButton; -class ShelfDelegate; -class ShelfModel; -struct ShelfItem; -class ShelfWidget; -class WmShelf; - -namespace test { -class ShelfViewTestAPI; -} - -extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM; -extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT; -extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT; -extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT; - -class ASH_EXPORT ShelfView : public views::View, - public ShelfModelObserver, - public InkDropButtonListener, - public views::ContextMenuController, - public views::FocusTraversable, - public views::BoundsAnimatorObserver, - public app_list::ApplicationDragAndDropHost { - public: - ShelfView(ShelfModel* model, - ShelfDelegate* delegate, - WmShelf* wm_shelf, - ShelfWidget* shelf_widget); - ~ShelfView() override; - - WmShelf* wm_shelf() const { return wm_shelf_; } - ShelfModel* model() const { return model_; } - - void Init(); - - void OnShelfAlignmentChanged(); - - // Returns the ideal bounds of the specified item, or an empty rect if id - // isn't know. If the item is in an overflow shelf, the overflow icon location - // will be returned. - gfx::Rect GetIdealBoundsOfItemIcon(ShelfID id); - - // Repositions the icon for the specified item by the midpoint of the window. - void UpdatePanelIconPosition(ShelfID id, const gfx::Point& midpoint); - - // Returns true if we're showing a menu. - bool IsShowingMenu() const; - - // Returns true if overflow bubble is shown. - bool IsShowingOverflowBubble() const; - - // Sets owner overflow bubble instance from which this shelf view pops - // out as overflow. - void set_owner_overflow_bubble(OverflowBubble* owner) { - owner_overflow_bubble_ = owner; - } - - AppListButton* GetAppListButton() const; - - // Returns true if the mouse cursor exits the area for launcher tooltip. - // There are thin gaps between launcher buttons but the tooltip shouldn't hide - // in the gaps, but the tooltip should hide if the mouse moved totally outside - // of the buttons area. - bool ShouldHideTooltip(const gfx::Point& cursor_location) const; - - // Returns true if a tooltip should be shown for the shelf item |view|. - bool ShouldShowTooltipForView(const views::View* view) const; - - // Returns the title of the shelf item |view|. - base::string16 GetTitleForView(const views::View* view) const; - - // Returns rectangle bounding all visible launcher items. Used screen - // coordinate system. - gfx::Rect GetVisibleItemsBoundsInScreen(); - - // InkDropButtonListener: - void ButtonPressed(views::Button* sender, - const ui::Event& event, - views::InkDrop* ink_drop) override; - - // Overridden from FocusTraversable: - views::FocusSearch* GetFocusSearch() override; - FocusTraversable* GetFocusTraversableParent() override; - View* GetFocusTraversableParentView() override; - - // Overridden from app_list::ApplicationDragAndDropHost: - void CreateDragIconProxy(const gfx::Point& location_in_screen_coordinates, - const gfx::ImageSkia& icon, - views::View* replaced_view, - const gfx::Vector2d& cursor_offset_from_center, - float scale_factor) override; - void UpdateDragIconProxy( - const gfx::Point& location_in_screen_coordinates) override; - void DestroyDragIconProxy() override; - bool StartDrag(const std::string& app_id, - const gfx::Point& location_in_screen_coordinates) override; - bool Drag(const gfx::Point& location_in_screen_coordinates) override; - void EndDrag(bool cancel) override; - - // Returns true if |event| on the shelf item is going to activate the item. - // Used to determine whether a pending ink drop should be shown or not. - bool ShouldEventActivateButton(views::View* view, const ui::Event& event); - - // The shelf buttons use the Pointer interface to enable item reordering. - enum Pointer { NONE, DRAG_AND_DROP, MOUSE, TOUCH }; - void PointerPressedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event); - void PointerDraggedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event); - void PointerReleasedOnButton(views::View* view, - Pointer pointer, - bool canceled); - - // Updates the background for the shelf items. - void UpdateShelfItemBackground(SkColor color); - - // Return the view model for test purposes. - const views::ViewModel* view_model_for_test() const { - return view_model_.get(); - } - - private: - friend class ash::test::ShelfViewTestAPI; - - class FadeOutAnimationDelegate; - class StartFadeAnimationDelegate; - - struct IdealBounds { - gfx::Rect overflow_bounds; - }; - - enum RemovableState { - REMOVABLE, // Item can be removed when dragged away. - DRAGGABLE, // Item can be dragged, but will snap always back to origin. - NOT_REMOVABLE, // Item is fixed and can never be removed. - }; - - // Minimum distance before drag starts. - static const int kMinimumDragDistance; - - // Returns true when this ShelfView is used for Overflow Bubble. - // In this mode, it does not show app list, panel and overflow button. - // Note: - // * When Shelf can contain only one item (overflow button) due to very - // small resolution screen, overflow bubble can show app list and panel - // button. - bool is_overflow_mode() const { return overflow_mode_; } - - bool dragging() const { return drag_pointer_ != NONE; } - - // Sets the bounds of each view to its ideal bounds. - void LayoutToIdealBounds(); - - // Update all button's visibility in overflow. - void UpdateAllButtonsVisibilityInOverflowMode(); - - // Calculates the ideal bounds. The bounds of each button corresponding to an - // item in the model is set in |view_model_|. - void CalculateIdealBounds(IdealBounds* bounds) const; - - // Returns the index of the last view whose max primary axis coordinate is - // less than |max_value|. Returns -1 if nothing fits, or there are no views. - int DetermineLastVisibleIndex(int max_value) const; - - // Returns the index of the first panel whose min primary axis coordinate is - // at least |min_value|. Returns the index past the last panel if none fit. - int DetermineFirstVisiblePanelIndex(int min_value) const; - - // Animates the bounds of each view to its ideal bounds. - void AnimateToIdealBounds(); - - // Creates the view used to represent |item|. - views::View* CreateViewForItem(const ShelfItem& item); - - // Fades |view| from an opacity of 0 to 1. This is when adding a new item. - void FadeIn(views::View* view); - - // Invoked when the pointer has moved enough to trigger a drag. Sets - // internal state in preparation for the drag. - void PrepareForDrag(Pointer pointer, const ui::LocatedEvent& event); - - // Invoked when the mouse is dragged. Updates the models as appropriate. - void ContinueDrag(const ui::LocatedEvent& event); - - // Handles ripping off an item from the shelf. Returns true when the item got - // removed. - bool HandleRipOffDrag(const ui::LocatedEvent& event); - - // Finalize the rip off dragging by either |cancel| the action or validating. - void FinalizeRipOffDrag(bool cancel); - - // Check if an item can be ripped off or not. - RemovableState RemovableByRipOff(int index) const; - - // Returns true if |typea| and |typeb| should be in the same drag range. - bool SameDragType(ShelfItemType typea, ShelfItemType typeb) const; - - // Returns the range (in the model) the item at the specified index can be - // dragged to. - std::pair<int, int> GetDragRange(int index); - - // If there is a drag operation in progress it's canceled. If |modified_index| - // is valid, the new position of the corresponding item is returned. - int CancelDrag(int modified_index); - - // Returns rectangle bounds used for drag insertion. - // Note: - // * When overflow button is visible, returns bounds from first item - // to overflow button. - // * When overflow button is visible and one or more panel items exists, - // returns bounds from first item to last panel item. - // * In the overflow mode, returns only bubble's bounds. - gfx::Rect GetBoundsForDragInsertInScreen(); - - // Common setup done for all children. - void ConfigureChildView(views::View* view); - - // Toggles the overflow menu. - void ToggleOverflowBubble(); - - // Invoked after the fading out animation for item deletion is ended. - void OnFadeOutAnimationEnded(); - - // Fade in last visible item. - void StartFadeInLastVisibleItem(); - - // Updates the visible range of overflow items in |overflow_view|. - void UpdateOverflowRange(ShelfView* overflow_view) const; - - // Overridden from views::View: - gfx::Size GetPreferredSize() const override; - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - FocusTraversable* GetPaneFocusTraversable() override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) override; - - // Overridden from ui::EventHandler: - void OnGestureEvent(ui::GestureEvent* event) override; - - // Overridden from ShelfModelObserver: - void ShelfItemAdded(int model_index) override; - void ShelfItemRemoved(int model_index, ShelfID id) override; - void ShelfItemChanged(int model_index, const ShelfItem& old_item) override; - void ShelfItemMoved(int start_index, int target_index) override; - void OnSetShelfItemDelegate(ShelfID id, - ShelfItemDelegate* item_delegate) override; - - // Show a list of all running items for this shelf |item|; it only shows a - // menu if there are multiple running items. |source| specifies the view - // responsible for showing the menu, and the bubble will point towards it. - // The |event_flags| are the flags of the event which triggered this menu. - // Returns |true| if a menu is shown. - bool ShowListMenuForView(const ShelfItem& item, - views::View* source, - const ui::Event& event, - views::InkDrop* ink_drop); - - // Overridden from views::ContextMenuController: - void ShowContextMenuForView(views::View* source, - const gfx::Point& point, - ui::MenuSourceType source_type) override; - - // Show either a context or normal click menu of given |menu_model|. - // If |context_menu| is set, the displayed menu is a context menu and not - // a menu listing one or more running applications. - // The |click_point| is only used for |context_menu|'s. - void ShowMenu(std::unique_ptr<ui::MenuModel> menu_model, - views::View* source, - const gfx::Point& click_point, - bool context_menu, - ui::MenuSourceType source_type, - views::InkDrop* ink_drop); - - // Callback for MenuModelAdapter. - void OnMenuClosed(views::InkDrop* ink_drop); - - // Overridden from views::BoundsAnimatorObserver: - void OnBoundsAnimatorProgressed(views::BoundsAnimator* animator) override; - void OnBoundsAnimatorDone(views::BoundsAnimator* animator) override; - - // Returns true if the (press down) |event| is a repost event from an event - // which just closed the menu of a shelf item. If it occurs on the same shelf - // item, we should ignore the call. - bool IsRepostEvent(const ui::Event& event); - - // Convenience accessor to model_->items(). - const ShelfItem* ShelfItemForView(const views::View* view) const; - - // Get the distance from the given |coordinate| to the closest point on this - // launcher/shelf. - int CalculateShelfDistance(const gfx::Point& coordinate) const; - - // The model; owned by Launcher. - ShelfModel* model_; - - // Delegate; owned by Launcher. - ShelfDelegate* delegate_; - - // The shelf controller; owned by RootWindowController. - WmShelf* wm_shelf_; - - // The shelf widget for this view. For overflow bubbles, this is the widget - // for the shelf, not for the bubble. - ShelfWidget* shelf_widget_; - - // Used to manage the set of active launcher buttons. There is a view per - // item in |model_|. - std::unique_ptr<views::ViewModel> view_model_; - - // Index of first visible launcher item. - int first_visible_index_; - - // Last index of a launcher button that is visible - // (does not go into overflow). - mutable int last_visible_index_; - - std::unique_ptr<views::BoundsAnimator> bounds_animator_; - - OverflowButton* overflow_button_; - - std::unique_ptr<OverflowBubble> overflow_bubble_; - - OverflowBubble* owner_overflow_bubble_; - - ShelfTooltipManager tooltip_; - - // Pointer device that initiated the current drag operation. If there is no - // current dragging operation, this is NONE. - Pointer drag_pointer_; - - // The view being dragged. This is set immediately when the mouse is pressed. - // |dragging_| is set only if the mouse is dragged far enough. - ShelfButton* drag_view_; - - // Position of the mouse down event in |drag_view_|'s coordinates. - gfx::Point drag_origin_; - - // Index |drag_view_| was initially at. - int start_drag_index_; - - // Used for the context menu of a particular item. - ShelfID context_menu_id_; - - std::unique_ptr<views::FocusSearch> focus_search_; - - // Manages the context menu, and the list menu. - std::unique_ptr<ui::MenuModel> menu_model_; - std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_; - std::unique_ptr<views::MenuRunner> launcher_menu_runner_; - std::unique_ptr<ScopedRootWindowForNewWindows> - scoped_root_window_for_new_windows_; - - // Amount content is inset on the left edge (or top edge for vertical - // alignment). - int leading_inset_; - - // True when an item being inserted or removed in the model cancels a drag. - bool cancelling_drag_model_changed_; - - // Index of the last hidden launcher item. If there are no hidden items this - // will be equal to last_visible_index_ + 1. - mutable int last_hidden_index_; - - // The timestamp of the event which closed the last menu - or 0. - base::TimeTicks closing_event_time_; - - // True if a drag and drop operation created/pinned the item in the launcher - // and it needs to be deleted/unpinned again if the operation gets cancelled. - bool drag_and_drop_item_pinned_; - - // The ShelfItem which is currently used for a drag and a drop operation - // or 0 otherwise. - ShelfID drag_and_drop_shelf_id_; - - // The application ID of the application which we drag and drop. - std::string drag_and_drop_app_id_; - - // The original launcher item's size before the dragging operation. - gfx::Size pre_drag_and_drop_size_; - - // The image proxy for drag operations when a drag and drop host exists and - // the item can be dragged outside the app grid. - std::unique_ptr<ash::DragImageView> drag_image_; - - // The cursor offset to the middle of the dragged item. - gfx::Vector2d drag_image_offset_; - - // The view which gets replaced by our drag icon proxy. - views::View* drag_replaced_view_; - - // True when the icon was dragged off the shelf. - bool dragged_off_shelf_; - - // The rip off view when a snap back operation is underway. - views::View* snap_back_from_rip_off_view_; - - // True when this ShelfView is used for Overflow Bubble. - bool overflow_mode_; - - // Holds a pointer to main ShelfView when a ShelfView is in overflow mode. - ShelfView* main_shelf_; - - // True when ripped item from overflow bubble is entered into Shelf. - bool dragged_off_from_overflow_to_shelf_; - - // True if the event is a repost event from a event which has just closed the - // menu of the same shelf item. - bool is_repost_event_on_same_item_; - - // Record the index for the last pressed shelf item. This variable is used to - // check if a repost event occurs on the same shelf item as previous one. If - // so, the repost event should be ignored. - int last_pressed_index_; - - // Tracks UMA metrics based on shelf button press actions. - ShelfButtonPressedMetricTracker shelf_button_pressed_metric_tracker_; - - DISALLOW_COPY_AND_ASSIGN(ShelfView); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_VIEW_H_
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index e2716f91..a4d70724 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -2,38 +2,38 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/shelf/shelf_view.h" +#include "ash/common/shelf/shelf_view.h" #include <algorithm> #include <memory> #include <utility> #include <vector> +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/overflow_bubble.h" +#include "ash/common/shelf/overflow_bubble_view.h" +#include "ash/common/shelf/overflow_button.h" +#include "ash/common/shelf/shelf_button.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_tooltip_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/shelf/wm_shelf_observer.h" +#include "ash/common/system/web_notification/web_notification_tray.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/test/test_shelf_item_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/overflow_bubble.h" -#include "ash/shelf/overflow_bubble_view.h" -#include "ash/shelf/overflow_button.h" -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_tooltip_manager.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_observer.h" #include "ash/shell.h" -#include "ash/system/web_notification/web_notification_tray.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test/overflow_bubble_view_test_api.h" #include "ash/test/shelf_view_test_api.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/test/test_shelf_item_delegate.h" #include "ash/test/test_shell_delegate.h" -#include "ash/test/test_system_tray_delegate.h" #include "base/i18n/rtl.h" #include "base/macros.h" #include "base/memory/ptr_util.h"
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc deleted file mode 100644 index 8568cea6..0000000 --- a/ash/shelf/shelf_widget.cc +++ /dev/null
@@ -1,358 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_widget.h" - -#include "ash/animation/animation_change_type.h" -#include "ash/common/focus_cycler.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/status_area_layout_manager.h" -#include "ash/system/status_area_widget.h" -#include "ash/wm/window_properties.h" -#include "base/memory/ptr_util.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/skbitmap_operations.h" -#include "ui/views/accessible_pane_view.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { - -// The contents view of the Shelf. This view contains ShelfView and -// sizes it to the width of the shelf minus the size of the status area. -class ShelfWidget::DelegateView : public views::WidgetDelegate, - public views::AccessiblePaneView, - public ShelfBackgroundAnimatorObserver { - public: - explicit DelegateView(ShelfWidget* shelf); - ~DelegateView() override; - - void set_focus_cycler(FocusCycler* focus_cycler) { - focus_cycler_ = focus_cycler; - } - FocusCycler* focus_cycler() { return focus_cycler_; } - - ui::Layer* opaque_background() { return &opaque_background_; } - ui::Layer* opaque_foreground() { return &opaque_foreground_; } - - void SetParentLayer(ui::Layer* layer); - - // views::WidgetDelegateView overrides: - views::Widget* GetWidget() override { return View::GetWidget(); } - const views::Widget* GetWidget() const override { return View::GetWidget(); } - - bool CanActivate() const override; - void ReorderChildLayers(ui::Layer* parent_layer) override; - // This will be called when the parent local bounds change. - void OnBoundsChanged(const gfx::Rect& old_bounds) override; - - // ShelfBackgroundAnimatorObserver: - void UpdateShelfBackground(SkColor color) override; - - private: - ShelfWidget* shelf_widget_; - FocusCycler* focus_cycler_; - // A black background layer that may be visible depending on a - // ShelfBackgroundAnimator. - // TODO(bruthig): Remove opaque_background_ (see https://crbug.com/621551). - ui::Layer opaque_background_; - // A black foreground layer which is shown while transitioning between users. - // Note: Since the back- and foreground layers have different functions they - // can be used simultaneously - so no repurposing possible. - ui::Layer opaque_foreground_; - - DISALLOW_COPY_AND_ASSIGN(DelegateView); -}; - -ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf_widget) - : shelf_widget_(shelf_widget), - focus_cycler_(nullptr), - opaque_background_(ui::LAYER_SOLID_COLOR), - opaque_foreground_(ui::LAYER_SOLID_COLOR) { - DCHECK(shelf_widget_); - SetLayoutManager(new views::FillLayout()); - set_allow_deactivate_on_esc(true); - opaque_background_.SetColor(SK_ColorBLACK); - opaque_background_.SetBounds(GetLocalBounds()); - opaque_foreground_.SetColor(SK_ColorBLACK); - opaque_foreground_.SetBounds(GetLocalBounds()); - opaque_foreground_.SetOpacity(0.0f); -} - -ShelfWidget::DelegateView::~DelegateView() {} - -void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) { - layer->Add(&opaque_background_); - layer->Add(&opaque_foreground_); - ReorderLayers(); -} - -bool ShelfWidget::DelegateView::CanActivate() const { - // Allow to activate as fallback. - if (shelf_widget_->activating_as_fallback_) - return true; - // Allow to activate from the focus cycler. - if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget()) - return true; - // Disallow activating in other cases, especially when using mouse. - return false; -} - -void ShelfWidget::DelegateView::ReorderChildLayers(ui::Layer* parent_layer) { - views::View::ReorderChildLayers(parent_layer); - parent_layer->StackAtBottom(&opaque_background_); - parent_layer->StackAtTop(&opaque_foreground_); -} - -void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect& old_bounds) { - opaque_background_.SetBounds(GetLocalBounds()); - opaque_foreground_.SetBounds(GetLocalBounds()); -} - -void ShelfWidget::DelegateView::UpdateShelfBackground(SkColor color) { - opaque_background_.SetColor(color); -} - -ShelfWidget::ShelfWidget(WmWindow* shelf_container, WmShelf* wm_shelf) - : wm_shelf_(wm_shelf), - status_area_widget_(nullptr), - delegate_view_(new DelegateView(this)), - shelf_view_(nullptr), - background_animator_(SHELF_BACKGROUND_DEFAULT, - wm_shelf_, - WmShell::Get()->wallpaper_controller()), - activating_as_fallback_(false) { - DCHECK(wm_shelf_); - background_animator_.AddObserver(this); - background_animator_.AddObserver(delegate_view_); - - views::Widget::InitParams params( - views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.name = "ShelfWidget"; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.delegate = delegate_view_; - shelf_container->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - this, shelf_container->GetShellWindowId(), ¶ms); - Init(params); - - // The shelf should not take focus when initially shown. - set_focus_on_creation(false); - SetContentsView(delegate_view_); - delegate_view_->SetParentLayer(GetLayer()); - - shelf_layout_manager_ = new ShelfLayoutManager(this, wm_shelf_); - shelf_layout_manager_->AddObserver(this); - shelf_container->SetLayoutManager(base::WrapUnique(shelf_layout_manager_)); - background_animator_.PaintBackground( - shelf_layout_manager_->GetShelfBackgroundType(), - AnimationChangeType::IMMEDIATE); - - views::Widget::AddObserver(this); -} - -ShelfWidget::~ShelfWidget() { - // Must call Shutdown() before destruction. - DCHECK(!status_area_widget_); - WmShell::Get()->focus_cycler()->RemoveWidget(this); - SetFocusCycler(nullptr); - RemoveObserver(this); - background_animator_.RemoveObserver(delegate_view_); - background_animator_.RemoveObserver(this); -} - -void ShelfWidget::CreateStatusAreaWidget(WmWindow* status_container) { - DCHECK(status_container); - DCHECK(!status_area_widget_); - // TODO(jamescook): Move ownership to RootWindowController. - status_area_widget_ = new StatusAreaWidget(status_container, wm_shelf_); - status_area_widget_->CreateTrayViews(); - if (WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()) - status_area_widget_->Show(); - WmShell::Get()->focus_cycler()->AddWidget(status_area_widget_); - background_animator_.AddObserver(status_area_widget_); - status_container->SetLayoutManager( - base::MakeUnique<StatusAreaLayoutManager>(this)); -} - -void ShelfWidget::SetPaintsBackground(ShelfBackgroundType background_type, - AnimationChangeType change_type) { - background_animator_.PaintBackground(background_type, change_type); -} - -ShelfBackgroundType ShelfWidget::GetBackgroundType() const { - return background_animator_.target_background_type(); -} - -void ShelfWidget::HideShelfBehindBlackBar(bool hide, int animation_time_ms) { - if (IsShelfHiddenBehindBlackBar() == hide) - return; - - ui::Layer* opaque_foreground = delegate_view_->opaque_foreground(); - float target_opacity = hide ? 1.0f : 0.0f; - std::unique_ptr<ui::ScopedLayerAnimationSettings> opaque_foreground_animation; - opaque_foreground_animation.reset( - new ui::ScopedLayerAnimationSettings(opaque_foreground->GetAnimator())); - opaque_foreground_animation->SetTransitionDuration( - base::TimeDelta::FromMilliseconds(animation_time_ms)); - opaque_foreground_animation->SetPreemptionStrategy( - ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); - - opaque_foreground->SetOpacity(target_opacity); -} - -bool ShelfWidget::IsShelfHiddenBehindBlackBar() const { - return delegate_view_->opaque_foreground()->GetTargetOpacity() != 0.0f; -} - -void ShelfWidget::OnShelfAlignmentChanged() { - shelf_view_->OnShelfAlignmentChanged(); - // TODO(jamescook): Status area should not cache alignment. - status_area_widget_->SetShelfAlignment(wm_shelf_->GetAlignment()); - delegate_view_->SchedulePaint(); -} - -ShelfView* ShelfWidget::CreateShelfView() { - DCHECK(!shelf_view_); - - shelf_view_ = - new ShelfView(WmShell::Get()->shelf_model(), - WmShell::Get()->shelf_delegate(), wm_shelf_, this); - shelf_view_->Init(); - GetContentsView()->AddChildView(shelf_view_); - return shelf_view_; -} - -void ShelfWidget::PostCreateShelf() { - SetFocusCycler(WmShell::Get()->focus_cycler()); - - // Ensure the newly created |shelf_| gets current values. - background_animator_.NotifyObserver(this); - - // TODO(jamescook): The IsActiveUserSessionStarted() check may not be needed - // because the shelf is only created after the first user session is active. - // The ShelfView seems to always be visible after login. At the lock screen - // the shelf is hidden because its container is hidden. During auto-hide it is - // hidden because ShelfWidget is transparent. Some of the ShelfView visibility - // code could be simplified. http://crbug.com/674773 - shelf_view_->SetVisible( - WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()); - shelf_layout_manager_->LayoutShelf(); - shelf_layout_manager_->UpdateAutoHideState(); - Show(); -} - -bool ShelfWidget::IsShelfVisible() const { - return shelf_view_ && shelf_view_->visible(); -} - -bool ShelfWidget::IsShowingAppList() const { - return GetAppListButton() && GetAppListButton()->is_showing_app_list(); -} - -bool ShelfWidget::IsShowingContextMenu() const { - return shelf_view_ && shelf_view_->IsShowingMenu(); -} - -bool ShelfWidget::IsShowingOverflowBubble() const { - return shelf_view_ && shelf_view_->IsShowingOverflowBubble(); -} - -void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) { - delegate_view_->set_focus_cycler(focus_cycler); - if (focus_cycler) - focus_cycler->AddWidget(this); -} - -FocusCycler* ShelfWidget::GetFocusCycler() { - return delegate_view_->focus_cycler(); -} - -void ShelfWidget::Shutdown() { - // Shutting down the status area widget may cause some widgets (e.g. bubbles) - // to close, so uninstall the ShelfLayoutManager event filters first. Don't - // reset the pointer until later because other widgets (e.g. app list) may - // access it later in shutdown. - if (shelf_layout_manager_) - shelf_layout_manager_->PrepareForShutdown(); - - if (status_area_widget_) { - background_animator_.RemoveObserver(status_area_widget_); - WmShell::Get()->focus_cycler()->RemoveWidget(status_area_widget_); - status_area_widget_->Shutdown(); - status_area_widget_ = nullptr; - } - - CloseNow(); -} - -void ShelfWidget::UpdateIconPositionForPanel(WmWindow* panel) { - if (!shelf_view_) - return; - - WmWindow* shelf_window = WmWindow::Get(this->GetNativeWindow()); - shelf_view_->UpdatePanelIconPosition( - panel->aura_window()->GetProperty(kShelfIDKey), - shelf_window->ConvertRectFromScreen(panel->GetBoundsInScreen()) - .CenterPoint()); -} - -gfx::Rect ShelfWidget::GetScreenBoundsOfItemIconForWindow(WmWindow* window) { - // Window animations can be triggered during session restore before the shelf - // view is created. In that case, return default empty bounds. - if (!shelf_view_) - return gfx::Rect(); - - ShelfID id = window->aura_window()->GetProperty(kShelfIDKey); - gfx::Rect bounds(shelf_view_->GetIdealBoundsOfItemIcon(id)); - gfx::Point screen_origin; - views::View::ConvertPointToScreen(shelf_view_, &screen_origin); - return gfx::Rect(screen_origin.x() + bounds.x(), - screen_origin.y() + bounds.y(), bounds.width(), - bounds.height()); -} - -AppListButton* ShelfWidget::GetAppListButton() const { - return shelf_view_ ? shelf_view_->GetAppListButton() : nullptr; -} - -app_list::ApplicationDragAndDropHost* -ShelfWidget::GetDragAndDropHostForAppList() { - return shelf_view_; -} - -void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget, - bool active) { - activating_as_fallback_ = false; - if (active) - delegate_view_->SetPaneFocusAndFocusDefault(); - else - delegate_view_->GetFocusManager()->ClearFocus(); -} - -void ShelfWidget::UpdateShelfItemBackground(SkColor color) { - if (shelf_view_) - shelf_view_->UpdateShelfItemBackground(color); -} - -void ShelfWidget::WillDeleteShelfLayoutManager() { - shelf_layout_manager_->RemoveObserver(this); - shelf_layout_manager_ = nullptr; -} - -} // namespace ash
diff --git a/ash/shelf/shelf_widget.h b/ash/shelf/shelf_widget.h deleted file mode 100644 index 0b9097cc..0000000 --- a/ash/shelf/shelf_widget.h +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_WIDGET_H_ -#define ASH_SHELF_SHELF_WIDGET_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_background_animator.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "ash/shelf/shelf_layout_manager_observer.h" -#include "base/macros.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" - -namespace app_list { -class ApplicationDragAndDropHost; -} - -namespace ash { -enum class AnimationChangeType; -class AppListButton; -class FocusCycler; -class ShelfLayoutManager; -class ShelfView; -class StatusAreaWidget; -class WmShelf; -class WmWindow; - -// The ShelfWidget manages the shelf view (which contains the shelf icons) and -// the status area widget. There is one ShelfWidget per display. It is created -// early during RootWindowController initialization. -class ASH_EXPORT ShelfWidget : public views::Widget, - public views::WidgetObserver, - public ShelfBackgroundAnimatorObserver, - public ShelfLayoutManagerObserver { - public: - ShelfWidget(WmWindow* shelf_container, WmShelf* wm_shelf); - ~ShelfWidget() override; - - void CreateStatusAreaWidget(WmWindow* status_container); - - void OnShelfAlignmentChanged(); - - // Sets the shelf's background type. - void SetPaintsBackground(ShelfBackgroundType background_type, - AnimationChangeType change_type); - ShelfBackgroundType GetBackgroundType() const; - - // Hide the shelf behind a black bar during e.g. a user transition when |hide| - // is true. The |animation_time_ms| will be used as animation duration. - void HideShelfBehindBlackBar(bool hide, int animation_time_ms); - bool IsShelfHiddenBehindBlackBar() const; - - ShelfLayoutManager* shelf_layout_manager() { return shelf_layout_manager_; } - StatusAreaWidget* status_area_widget() const { return status_area_widget_; } - - // Creates the shelf view and populates it with icons. Called after the user - // session is active (and hence the user profile is available). - ShelfView* CreateShelfView(); - void PostCreateShelf(); - - bool IsShelfVisible() const; - - bool IsShowingAppList() const; - bool IsShowingContextMenu() const; - bool IsShowingOverflowBubble() const; - - // Sets the focus cycler. Also adds the shelf to the cycle. - void SetFocusCycler(FocusCycler* focus_cycler); - FocusCycler* GetFocusCycler(); - - // Called by the activation delegate, before the shelf is activated - // when no other windows are visible. - void WillActivateAsFallback() { activating_as_fallback_ = true; } - - // Clean up prior to deletion. - void Shutdown(); - - // See WmShelf::UpdateIconPositionForPanel(). - void UpdateIconPositionForPanel(WmWindow* panel); - - // See WmShelf::GetScreenBoundsOfItemIconForWindow(). - gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window); - - // Returns the button that opens the app launcher. - AppListButton* GetAppListButton() const; - - // Returns the ApplicationDragAndDropHost for this shelf. - app_list::ApplicationDragAndDropHost* GetDragAndDropHostForAppList(); - - // Overridden from views::WidgetObserver: - void OnWidgetActivationChanged(views::Widget* widget, bool active) override; - - // ShelfBackgroundAnimatorObserver overrides: - void UpdateShelfItemBackground(SkColor color) override; - - // ShelfLayoutManagerObserver overrides: - void WillDeleteShelfLayoutManager() override; - - private: - class DelegateView; - friend class DelegateView; - - WmShelf* wm_shelf_; - - // Owned by the shelf container's window. - ShelfLayoutManager* shelf_layout_manager_; - - // Owned by the native widget. - StatusAreaWidget* status_area_widget_; - - // |delegate_view_| is the contents view of this widget and is cleaned up - // during CloseChildWindows of the associated RootWindowController. - DelegateView* delegate_view_; - // View containing the shelf items. Owned by the views hierarchy. Null when - // at the login screen. - ShelfView* shelf_view_; - ShelfBackgroundAnimator background_animator_; - bool activating_as_fallback_; - - DISALLOW_COPY_AND_ASSIGN(ShelfWidget); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_WIDGET_H_
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc index 4e4f4f8..2e8941af 100644 --- a/ash/shelf/shelf_widget_unittest.cc +++ b/ash/shelf/shelf_widget_unittest.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/shelf/shelf_widget.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test/shelf_view_test_api.h"
diff --git a/ash/shelf/shelf_window_targeter.cc b/ash/shelf/shelf_window_targeter.cc index d881be7..24ba0e8 100644 --- a/ash/shelf/shelf_window_targeter.cc +++ b/ash/shelf/shelf_window_targeter.cc
@@ -4,10 +4,10 @@ #include "ash/shelf/shelf_window_targeter.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" #include "ui/aura/window.h" namespace ash {
diff --git a/ash/shelf/shelf_window_targeter.h b/ash/shelf/shelf_window_targeter.h index d8c58673..fd14fe1 100644 --- a/ash/shelf/shelf_window_targeter.h +++ b/ash/shelf/shelf_window_targeter.h
@@ -5,7 +5,7 @@ #ifndef ASH_SHELF_SHELF_WINDOW_TARGETER_H_ #define ASH_SHELF_SHELF_WINDOW_TARGETER_H_ -#include "ash/shelf/wm_shelf_observer.h" +#include "ash/common/shelf/wm_shelf_observer.h" #include "base/macros.h" #include "ui/aura/window_observer.h" #include "ui/wm/core/easy_resize_window_targeter.h"
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc deleted file mode 100644 index 2f607f8..0000000 --- a/ash/shelf/shelf_window_watcher.cc +++ /dev/null
@@ -1,262 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_window_watcher.h" - -#include <memory> -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_window_watcher_item_delegate.h" -#include "ash/shell.h" -#include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_aura.h" -#include "ash/wm/window_util.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/env.h" -#include "ui/aura/window.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/wm/public/activation_client.h" - -namespace ash { -namespace { - -// Returns the shelf item type, with special temporary behavior for Mash: -// Mash provides a default shelf item type (TYPE_APP) for non-ignored windows. -ShelfItemType GetShelfItemType(aura::Window* window) { - if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL || - window->GetProperty(kShelfItemTypeKey) != TYPE_UNDEFINED) { - return static_cast<ShelfItemType>(window->GetProperty(kShelfItemTypeKey)); - } - return wm::GetWindowState(window)->ignored_by_shelf() ? TYPE_UNDEFINED - : TYPE_APP; -} - -// Update the ShelfItem from relevant window properties. -void UpdateShelfItemForWindow(ShelfItem* item, aura::Window* window) { - item->type = GetShelfItemType(window); - - item->status = STATUS_RUNNING; - if (wm::IsActiveWindow(window)) - item->status = STATUS_ACTIVE; - else if (window->GetProperty(aura::client::kDrawAttentionKey)) - item->status = STATUS_ATTENTION; - - const std::string* app_id = window->GetProperty(aura::client::kAppIdKey); - item->app_id = app_id ? *app_id : std::string(); - - // Prefer app icons over window icons, they're typically larger. - gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconKey); - if (!image || image->isNull()) - image = window->GetProperty(aura::client::kWindowIconKey); - item->image = image ? *image : gfx::ImageSkia(); - - item->title = window->GetTitle(); - - // Do not show tooltips for visible attached app panel windows. - item->shows_tooltip = item->type != TYPE_APP_PANEL || !window->IsVisible() || - !window->GetProperty(kPanelAttachedKey); -} - -} // namespace - -ShelfWindowWatcher::ContainerWindowObserver::ContainerWindowObserver( - ShelfWindowWatcher* window_watcher) - : window_watcher_(window_watcher) {} - -ShelfWindowWatcher::ContainerWindowObserver::~ContainerWindowObserver() {} - -void ShelfWindowWatcher::ContainerWindowObserver::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - if (!params.old_parent && params.new_parent && - (params.new_parent->id() == kShellWindowId_DefaultContainer || - params.new_parent->id() == kShellWindowId_PanelContainer)) { - // A new window was created in the default container or the panel container. - window_watcher_->OnUserWindowAdded(params.target); - } -} - -void ShelfWindowWatcher::ContainerWindowObserver::OnWindowDestroying( - aura::Window* window) { - window_watcher_->OnContainerWindowDestroying(window); -} - -//////////////////////////////////////////////////////////////////////////////// - -ShelfWindowWatcher::UserWindowObserver::UserWindowObserver( - ShelfWindowWatcher* window_watcher) - : window_watcher_(window_watcher) {} - -ShelfWindowWatcher::UserWindowObserver::~UserWindowObserver() {} - -void ShelfWindowWatcher::UserWindowObserver::OnWindowPropertyChanged( - aura::Window* window, - const void* key, - intptr_t old) { - if (key == aura::client::kAppIconKey || key == aura::client::kAppIdKey || - key == aura::client::kDrawAttentionKey || - key == aura::client::kWindowIconKey || key == kPanelAttachedKey || - key == kShelfItemTypeKey) { - window_watcher_->OnUserWindowPropertyChanged(window); - } -} - -void ShelfWindowWatcher::UserWindowObserver::OnWindowDestroying( - aura::Window* window) { - window_watcher_->OnUserWindowDestroying(window); -} - -void ShelfWindowWatcher::UserWindowObserver::OnWindowVisibilityChanged( - aura::Window* window, - bool visible) { - // OnWindowVisibilityChanged() is called for descendants too. We only care - // about changes to the visibility of windows we know about. - if (!window_watcher_->observed_user_windows_.IsObserving(window)) - return; - - // The tooltip behavior for panel windows depends on the panel visibility. - window_watcher_->OnUserWindowPropertyChanged(window); -} - -void ShelfWindowWatcher::UserWindowObserver::OnWindowTitleChanged( - aura::Window* window) { - window_watcher_->OnUserWindowPropertyChanged(window); -} - -//////////////////////////////////////////////////////////////////////////////// - -ShelfWindowWatcher::ShelfWindowWatcher(ShelfModel* model) - : model_(model), - container_window_observer_(this), - user_window_observer_(this), - observed_container_windows_(&container_window_observer_), - observed_user_windows_(&user_window_observer_) { - Shell::GetInstance()->activation_client()->AddObserver(this); - for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) - OnDisplayAdded(display); - display::Screen::GetScreen()->AddObserver(this); -} - -ShelfWindowWatcher::~ShelfWindowWatcher() { - display::Screen::GetScreen()->RemoveObserver(this); - Shell::GetInstance()->activation_client()->RemoveObserver(this); -} - -void ShelfWindowWatcher::AddShelfItem(aura::Window* window) { - user_windows_with_items_.insert(window); - ShelfItem item; - ShelfID id = model_->next_id(); - UpdateShelfItemForWindow(&item, window); - window->SetProperty(kShelfIDKey, id); - std::unique_ptr<ShelfItemDelegate> item_delegate( - new ShelfWindowWatcherItemDelegate(id, WmWindow::Get(window))); - model_->SetShelfItemDelegate(id, std::move(item_delegate)); - // Panels are inserted on the left so as not to push all existing panels over. - model_->AddAt(item.type == TYPE_APP_PANEL ? 0 : model_->item_count(), item); -} - -void ShelfWindowWatcher::RemoveShelfItem(aura::Window* window) { - user_windows_with_items_.erase(window); - int shelf_id = window->GetProperty(kShelfIDKey); - DCHECK_NE(shelf_id, kInvalidShelfID); - int index = model_->ItemIndexByID(shelf_id); - DCHECK_GE(index, 0); - model_->RemoveItemAt(index); - window->SetProperty(kShelfIDKey, kInvalidShelfID); -} - -void ShelfWindowWatcher::OnContainerWindowDestroying(aura::Window* container) { - observed_container_windows_.Remove(container); -} - -int ShelfWindowWatcher::GetShelfItemIndexForWindow(aura::Window* window) const { - return model_->ItemIndexByID(window->GetProperty(kShelfIDKey)); -} - -void ShelfWindowWatcher::OnUserWindowAdded(aura::Window* window) { - // The window may already be tracked from a prior display or parent container. - if (observed_user_windows_.IsObserving(window)) - return; - - observed_user_windows_.Add(window); - - // Add, update, or remove a ShelfItem for |window|, as needed. - OnUserWindowPropertyChanged(window); -} - -void ShelfWindowWatcher::OnUserWindowDestroying(aura::Window* window) { - if (observed_user_windows_.IsObserving(window)) - observed_user_windows_.Remove(window); - - if (user_windows_with_items_.count(window) > 0) - RemoveShelfItem(window); - DCHECK_EQ(0u, user_windows_with_items_.count(window)); -} - -void ShelfWindowWatcher::OnUserWindowPropertyChanged(aura::Window* window) { - if (GetShelfItemType(window) == TYPE_UNDEFINED) { - // Remove |window|'s ShelfItem if it was added by this ShelfWindowWatcher. - if (user_windows_with_items_.count(window) > 0) - RemoveShelfItem(window); - return; - } - - // Update an existing ShelfItem for |window| when a property has changed. - int index = GetShelfItemIndexForWindow(window); - if (index > 0) { - ShelfItem item = model_->items()[index]; - UpdateShelfItemForWindow(&item, window); - model_->Set(index, item); - return; - } - - // Creates a new ShelfItem for |window|. - AddShelfItem(window); -} - -void ShelfWindowWatcher::OnWindowActivated(ActivationReason reason, - aura::Window* gained_active, - aura::Window* lost_active) { - if (gained_active && user_windows_with_items_.count(gained_active) > 0) - OnUserWindowPropertyChanged(gained_active); - if (lost_active && user_windows_with_items_.count(lost_active) > 0) - OnUserWindowPropertyChanged(lost_active); -} - -void ShelfWindowWatcher::OnDisplayAdded(const display::Display& new_display) { - WmWindow* root = WmShell::Get()->GetRootWindowForDisplayId(new_display.id()); - aura::Window* aura_root = WmWindow::GetAuraWindow(root); - - // When the primary root window's display is removed, the existing root window - // is taken over by the new display, and the observer is already set. - aura::Window* default_container = - aura_root->GetChildById(kShellWindowId_DefaultContainer); - if (!observed_container_windows_.IsObserving(default_container)) { - for (aura::Window* window : default_container->children()) - OnUserWindowAdded(window); - observed_container_windows_.Add(default_container); - } - aura::Window* panel_container = - aura_root->GetChildById(kShellWindowId_PanelContainer); - if (!observed_container_windows_.IsObserving(panel_container)) { - for (aura::Window* window : panel_container->children()) - OnUserWindowAdded(window); - observed_container_windows_.Add(panel_container); - } -} - -void ShelfWindowWatcher::OnDisplayRemoved(const display::Display& old_display) { -} - -void ShelfWindowWatcher::OnDisplayMetricsChanged(const display::Display&, - uint32_t) {} - -} // namespace ash
diff --git a/ash/shelf/shelf_window_watcher.h b/ash/shelf/shelf_window_watcher.h deleted file mode 100644 index 31c18f2..0000000 --- a/ash/shelf/shelf_window_watcher.h +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_WINDOW_WATCHER_H_ -#define ASH_SHELF_SHELF_WINDOW_WATCHER_H_ - -#include <set> - -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "ui/aura/window_observer.h" -#include "ui/display/display_observer.h" -#include "ui/wm/public/activation_change_observer.h" - -namespace ash { - -class ShelfModel; - -// ShelfWindowWatcher creates and handles a ShelfItem for windows in the default -// container and panels in the panel container that have a valid ShelfItemType -// property (e.g. the task manager dialog or the OS settings window). It adds -// the ShelfItem when the window is added to the default container and maintains -// it until the window is closed, even if the window is transiently reparented -// (e.g. during a drag). -class ShelfWindowWatcher : public aura::client::ActivationChangeObserver, - public display::DisplayObserver { - public: - explicit ShelfWindowWatcher(ShelfModel* model); - ~ShelfWindowWatcher() override; - - private: - // Observes for windows being added to a root window's default container. - class ContainerWindowObserver : public aura::WindowObserver { - public: - explicit ContainerWindowObserver(ShelfWindowWatcher* window_watcher); - ~ContainerWindowObserver() override; - - private: - // aura::WindowObserver: - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; - void OnWindowDestroying(aura::Window* window) override; - - ShelfWindowWatcher* window_watcher_; - - DISALLOW_COPY_AND_ASSIGN(ContainerWindowObserver); - }; - - // Observes individual user windows to detect when they are closed or when - // their shelf item properties have changed. - class UserWindowObserver : public aura::WindowObserver { - public: - explicit UserWindowObserver(ShelfWindowWatcher* window_watcher); - ~UserWindowObserver() override; - - private: - // aura::WindowObserver: - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; - void OnWindowDestroying(aura::Window* window) override; - void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; - void OnWindowTitleChanged(aura::Window* window) override; - - ShelfWindowWatcher* window_watcher_; - - DISALLOW_COPY_AND_ASSIGN(UserWindowObserver); - }; - - // Creates a ShelfItem for |window|. - void AddShelfItem(aura::Window* window); - - // Removes a ShelfItem for |window|. - void RemoveShelfItem(aura::Window* window); - - // Returns the index of ShelfItem associated with |window|, or -1 if none. - int GetShelfItemIndexForWindow(aura::Window* window) const; - - // Cleans up observers on |container|. - void OnContainerWindowDestroying(aura::Window* container); - - // Adds a shelf item for new windows added to the default container that have - // a valid ShelfItemType property value. - void OnUserWindowAdded(aura::Window* window); - - // Adds, updates or removes the shelf item based on a property change. - void OnUserWindowPropertyChanged(aura::Window* window); - - // Removes the shelf item when a window closes. - void OnUserWindowDestroying(aura::Window* window); - - // aura::client::ActivationChangeObserver: - void OnWindowActivated(ActivationReason reason, - aura::Window* gained_active, - aura::Window* lost_active) override; - - // display::DisplayObserver overrides: - void OnDisplayAdded(const display::Display& display) override; - void OnDisplayRemoved(const display::Display& old_display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t metrics) override; - - ShelfModel* model_; - - ContainerWindowObserver container_window_observer_; - UserWindowObserver user_window_observer_; - - ScopedObserver<aura::Window, ContainerWindowObserver> - observed_container_windows_; - ScopedObserver<aura::Window, UserWindowObserver> observed_user_windows_; - - // The set of windows with shelf items managed by this ShelfWindowWatcher. - std::set<aura::Window*> user_windows_with_items_; - - DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcher); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_WINDOW_WATCHER_H_
diff --git a/ash/shelf/shelf_window_watcher_item_delegate.cc b/ash/shelf/shelf_window_watcher_item_delegate.cc deleted file mode 100644 index fbd905b..0000000 --- a/ash/shelf/shelf_window_watcher_item_delegate.cc +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_window_watcher_item_delegate.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_model.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_util.h" -#include "ui/aura/window.h" -#include "ui/events/event_constants.h" - -namespace ash { - -namespace { - -ShelfItemType GetShelfItemType(ShelfID id) { - ShelfModel* model = WmShell::Get()->shelf_controller()->model(); - ShelfItems::const_iterator item = model->ItemByID(id); - return item == model->items().end() ? TYPE_UNDEFINED : item->type; -} - -} // namespace - -ShelfWindowWatcherItemDelegate::ShelfWindowWatcherItemDelegate(ShelfID id, - WmWindow* window) - : id_(id), window_(window) { - DCHECK_NE(kInvalidShelfID, id_); - DCHECK(window_); -} - -ShelfWindowWatcherItemDelegate::~ShelfWindowWatcherItemDelegate() {} - -ShelfAction ShelfWindowWatcherItemDelegate::ItemSelected( - ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) { - // Move panels attached on another display to the current display. - if (GetShelfItemType(id_) == TYPE_APP_PANEL && - window_->aura_window()->GetProperty(kPanelAttachedKey) && - wm::MoveWindowToDisplay(window_->aura_window(), display_id)) { - window_->Activate(); - return SHELF_ACTION_WINDOW_ACTIVATED; - } - - if (window_->IsActive()) { - if (event_type == ui::ET_KEY_RELEASED) { - window_->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); - return SHELF_ACTION_NONE; - } - window_->Minimize(); - return SHELF_ACTION_WINDOW_MINIMIZED; - } - window_->Activate(); - return SHELF_ACTION_WINDOW_ACTIVATED; -} - -ShelfAppMenuItemList ShelfWindowWatcherItemDelegate::GetAppMenuItems( - int event_flags) { - // Return an empty item list to avoid showing an application menu. - return ShelfAppMenuItemList(); -} - -void ShelfWindowWatcherItemDelegate::ExecuteCommand(uint32_t command_id, - int event_flags) { - // This delegate does not support showing an application menu. - NOTIMPLEMENTED(); -} - -void ShelfWindowWatcherItemDelegate::Close() { - window_->CloseWidget(); -} - -} // namespace ash
diff --git a/ash/shelf/shelf_window_watcher_item_delegate.h b/ash/shelf/shelf_window_watcher_item_delegate.h deleted file mode 100644 index 4fa1d47d..0000000 --- a/ash/shelf/shelf_window_watcher_item_delegate.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_SHELF_WINDOW_WATCHER_ITEM_DELEGATE_H_ -#define ASH_SHELF_SHELF_WINDOW_WATCHER_ITEM_DELEGATE_H_ - -#include "ash/shelf/shelf_item_delegate.h" -#include "base/macros.h" - -namespace ash { - -class WmWindow; - -// ShelfItemDelegate for the items created by ShelfWindowWatcher, for example: -// The Chrome OS settings window, task manager window, and panel windows. -class ShelfWindowWatcherItemDelegate : public ShelfItemDelegate { - public: - ShelfWindowWatcherItemDelegate(ShelfID id, WmWindow* window); - ~ShelfWindowWatcherItemDelegate() override; - - private: - // ShelfItemDelegate overrides: - ShelfAction ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) override; - ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; - void ExecuteCommand(uint32_t command_id, int event_flags) override; - void Close() override; - - ShelfID id_; - // The window associated with this item. Not owned. - WmWindow* window_; - - DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcherItemDelegate); -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_WINDOW_WATCHER_ITEM_DELEGATE_H_
diff --git a/ash/shelf/shelf_window_watcher_unittest.cc b/ash/shelf/shelf_window_watcher_unittest.cc deleted file mode 100644 index 3f104c19..0000000 --- a/ash/shelf/shelf_window_watcher_unittest.cc +++ /dev/null
@@ -1,395 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/shelf_window_watcher.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_item_types.h" -#include "ash/shelf/shelf_model.h" -#include "ash/test/ash_test_base.h" -#include "ash/wm/window_resizer.h" -#include "ash/wm/window_state.h" -#include "ui/base/hit_test.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -class ShelfWindowWatcherTest : public test::AshTestBase { - public: - ShelfWindowWatcherTest() : model_(nullptr) {} - ~ShelfWindowWatcherTest() override {} - - void SetUp() override { - test::AshTestBase::SetUp(); - model_ = WmShell::Get()->shelf_model(); - } - - void TearDown() override { - model_ = nullptr; - test::AshTestBase::TearDown(); - } - - static ShelfID CreateShelfItem(WmWindow* window) { - ShelfID id = WmShell::Get()->shelf_model()->next_id(); - window->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_DIALOG)); - return id; - } - - protected: - ShelfModel* model_; - - private: - DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcherTest); -}; - -// Ensure shelf items are added and removed as windows are opened and closed. -TEST_F(ShelfWindowWatcherTest, OpenAndClose) { - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - // Adding windows with valid ShelfItemType properties adds shelf items. - std::unique_ptr<views::Widget> widget1 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - CreateShelfItem(WmWindow::Get(widget1->GetNativeWindow())); - EXPECT_EQ(2, model_->item_count()); - std::unique_ptr<views::Widget> widget2 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - CreateShelfItem(WmWindow::Get(widget2->GetNativeWindow())); - EXPECT_EQ(3, model_->item_count()); - - // Each ShelfItem is removed when the associated window is destroyed. - widget1.reset(); - EXPECT_EQ(2, model_->item_count()); - widget2.reset(); - EXPECT_EQ(1, model_->item_count()); -} - -TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItemProperties) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - // Creating windows without a valid ShelfItemType does not add items. - std::unique_ptr<views::Widget> widget1 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); - std::unique_ptr<views::Widget> widget2 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); - EXPECT_EQ(1, model_->item_count()); - - // Create a ShelfItem for the first window. - ShelfID id_w1 = CreateShelfItem(window1); - EXPECT_EQ(2, model_->item_count()); - - int index_w1 = model_->ItemIndexByID(id_w1); - EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); - - // Create a ShelfItem for the second window. - ShelfID id_w2 = CreateShelfItem(window2); - EXPECT_EQ(3, model_->item_count()); - - int index_w2 = model_->ItemIndexByID(id_w2); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); - - // ShelfItem is removed when the item type window property is cleared. - window1->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_UNDEFINED)); - EXPECT_EQ(2, model_->item_count()); - window2->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_UNDEFINED)); - EXPECT_EQ(1, model_->item_count()); - // Clearing twice doesn't do anything. - window2->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_UNDEFINED)); - EXPECT_EQ(1, model_->item_count()); -} - -TEST_F(ShelfWindowWatcherTest, ActivateWindow) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only have APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - std::unique_ptr<views::Widget> widget1 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); - std::unique_ptr<views::Widget> widget2 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); - - // Create a ShelfItem for the first window. - ShelfID id_w1 = CreateShelfItem(window1); - EXPECT_EQ(2, model_->item_count()); - int index_w1 = model_->ItemIndexByID(id_w1); - EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); - - // Create a ShelfItem for the second window. - ShelfID id_w2 = CreateShelfItem(window2); - EXPECT_EQ(3, model_->item_count()); - int index_w2 = model_->ItemIndexByID(id_w2); - EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); - - // The ShelfItem for the first window is active when the window is activated. - widget1->Activate(); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w1].status); - EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status); - - // The ShelfItem for the second window is active when the window is activated. - widget2->Activate(); - EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); -} - -TEST_F(ShelfWindowWatcherTest, UpdateWindowProperty) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - std::unique_ptr<views::Widget> widget = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - - // Create a ShelfItem for |window|. - ShelfID id = CreateShelfItem(window); - EXPECT_EQ(2, model_->item_count()); - - int index = model_->ItemIndexByID(id); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); - - // Update the ShelfItemType for |window|. - window->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_APP)); - // No new item is created after updating a launcher item. - EXPECT_EQ(2, model_->item_count()); - // index and id are not changed after updating a launcher item. - EXPECT_EQ(index, model_->ItemIndexByID(id)); - EXPECT_EQ(id, model_->items()[index].id); -} - -TEST_F(ShelfWindowWatcherTest, MaximizeAndRestoreWindow) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - std::unique_ptr<views::Widget> widget = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - wm::WindowState* window_state = window->GetWindowState(); - - // Create a ShelfItem for |window|. - ShelfID id = CreateShelfItem(window); - EXPECT_EQ(2, model_->item_count()); - - int index = model_->ItemIndexByID(id); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); - - // Maximize window |window|. - EXPECT_FALSE(window_state->IsMaximized()); - window_state->Maximize(); - EXPECT_TRUE(window_state->IsMaximized()); - // No new item is created after maximizing a window |window|. - EXPECT_EQ(2, model_->item_count()); - // index and id are not changed after maximizing a window |window|. - EXPECT_EQ(index, model_->ItemIndexByID(id)); - EXPECT_EQ(id, model_->items()[index].id); - - // Restore window |window|. - window_state->Restore(); - EXPECT_FALSE(window_state->IsMaximized()); - // No new item is created after restoring a window |window|. - EXPECT_EQ(2, model_->item_count()); - // Index and id are not changed after maximizing a window |window|. - EXPECT_EQ(index, model_->ItemIndexByID(id)); - EXPECT_EQ(id, model_->items()[index].id); -} - -// Check that an item is maintained when its associated Window is docked. -TEST_F(ShelfWindowWatcherTest, DockWindow) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - std::unique_ptr<views::Widget> widget = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - - // Create a ShelfItem for |window|. - ShelfID id = CreateShelfItem(window); - EXPECT_EQ(2, model_->item_count()); - - int index = model_->ItemIndexByID(id); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); - - WmWindow* root_window = window->GetRootWindow(); - WmWindow* default_container = - root_window->GetChildByShellWindowId(kShellWindowId_DefaultContainer); - EXPECT_EQ(default_container, window->GetParent()); - - WmWindow* docked_container = - root_window->GetChildByShellWindowId(kShellWindowId_DockedContainer); - - // Check |window|'s item is not removed when it is re-parented to the dock. - docked_container->AddChild(window); - EXPECT_EQ(docked_container, window->GetParent()); - EXPECT_EQ(2, model_->item_count()); - - // The shelf item is removed when the window is closed, even if it is in the - // docked container at the time. - widget.reset(); - EXPECT_EQ(1, model_->item_count()); -} - -// Check |window|'s item is not changed during the dragging. -// TODO(simonhong): Add a test for removing a Window during the dragging. -TEST_F(ShelfWindowWatcherTest, DragWindow) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - std::unique_ptr<views::Widget> widget = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - - // Create a ShelfItem for |window|. - ShelfID id = CreateShelfItem(window); - EXPECT_EQ(2, model_->item_count()); - - int index = model_->ItemIndexByID(id); - EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); - - // Simulate dragging of |window| and check its item is not changed. - std::unique_ptr<WindowResizer> resizer(CreateWindowResizer( - window, gfx::Point(), HTCAPTION, aura::client::WINDOW_MOVE_SOURCE_MOUSE)); - ASSERT_TRUE(resizer.get()); - resizer->Drag(gfx::Point(50, 50), 0); - resizer->CompleteDrag(); - - // Index and id are not changed after dragging a |window|. - EXPECT_EQ(index, model_->ItemIndexByID(id)); - EXPECT_EQ(id, model_->items()[index].id); -} - -// Ensure shelf items are added and removed as panels are opened and closed. -TEST_F(ShelfWindowWatcherTest, PanelWindow) { - // TODO: investigate failure in mash. http://crbug.com/695562. - if (WmShell::Get()->IsRunningInMash()) - return; - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model_->item_count()); - - // Adding windows with valid ShelfItemType properties adds shelf items. - std::unique_ptr<views::Widget> widget1 = - CreateTestWidget(nullptr, kShellWindowId_PanelContainer, gfx::Rect()); - WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); - window1->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_APP_PANEL)); - EXPECT_EQ(2, model_->item_count()); - std::unique_ptr<views::Widget> widget2 = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); - window2->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_APP_PANEL)); - EXPECT_EQ(3, model_->item_count()); - - // Create a panel-type widget to mimic Chrome's app panel windows. - views::Widget panel_widget; - views::Widget::InitParams panel_params(views::Widget::InitParams::TYPE_PANEL); - panel_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - WmShell::Get() - ->GetPrimaryRootWindow() - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - &panel_widget, kShellWindowId_PanelContainer, &panel_params); - panel_widget.Init(panel_params); - panel_widget.Show(); - WmWindow* panel_window = WmWindow::Get(panel_widget.GetNativeWindow()); - panel_window->aura_window()->SetProperty( - kShelfItemTypeKey, static_cast<int32_t>(TYPE_APP_PANEL)); - EXPECT_EQ(4, model_->item_count()); - - // Each ShelfItem is removed when the associated window is destroyed. - panel_widget.CloseNow(); - EXPECT_EQ(3, model_->item_count()); - widget2.reset(); - EXPECT_EQ(2, model_->item_count()); - widget1.reset(); - EXPECT_EQ(1, model_->item_count()); -} - -TEST_F(ShelfWindowWatcherTest, DontCreateShelfEntriesForChildWindows) { - const int initial_item_count = model_->item_count(); - - WmWindow* window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, - ui::LAYER_NOT_DRAWN); - window->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_APP)); - WmShell::Get() - ->GetPrimaryRootWindow() - ->GetChildByShellWindowId(kShellWindowId_DefaultContainer) - ->AddChild(window); - window->Show(); - EXPECT_EQ(initial_item_count + 1, model_->item_count()); - - WmWindow* child_window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, - ui::LAYER_NOT_DRAWN); - child_window->aura_window()->SetProperty(kShelfItemTypeKey, - static_cast<int32_t>(TYPE_APP)); - window->AddChild(child_window); - child_window->Show(); - // |child_window| should not result in adding a new entry. - EXPECT_EQ(initial_item_count + 1, model_->item_count()); - - child_window->Destroy(); - window->Destroy(); - EXPECT_EQ(initial_item_count, model_->item_count()); -} - -// Ensures ShelfWindowWatcher supports windows opened prior to session start. -using ShelfWindowWatcherSessionStartTest = test::NoSessionAshTestBase; -TEST_F(ShelfWindowWatcherSessionStartTest, PreExistingWindow) { - ShelfModel* model = WmShell::Get()->shelf_model(); - ASSERT_FALSE( - WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()); - - // ShelfModel only has an APP_LIST item. - EXPECT_EQ(1, model->item_count()); - - // Construct a window that should get a shelf item once the session starts. - std::unique_ptr<views::Widget> widget = - CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - ShelfWindowWatcherTest::CreateShelfItem(window); - EXPECT_EQ(1, model->item_count()); - - // Start the test user session; ShelfWindowWatcher will find the open window. - SetSessionStarted(true); - EXPECT_EQ(2, model->item_count()); -} - -} // namespace ash
diff --git a/ash/shelf/wm_shelf.cc b/ash/shelf/wm_shelf.cc deleted file mode 100644 index fdd2aeb..0000000 --- a/ash/shelf/wm_shelf.cc +++ /dev/null
@@ -1,375 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/wm_shelf.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_bezel_event_handler.h" -#include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_locking_manager.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf_observer.h" -#include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "ui/aura/env.h" -#include "ui/display/types/display_constants.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { - -// WmShelf::AutoHideEventHandler ----------------------------------------------- - -// Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. -// TODO(mash): Add similar event handling support for mash. -class WmShelf::AutoHideEventHandler : public ui::EventHandler { - public: - explicit AutoHideEventHandler(ShelfLayoutManager* shelf_layout_manager) - : shelf_layout_manager_(shelf_layout_manager) { - Shell::GetInstance()->AddPreTargetHandler(this); - } - ~AutoHideEventHandler() override { - Shell::GetInstance()->RemovePreTargetHandler(this); - } - - // Overridden from ui::EventHandler: - void OnMouseEvent(ui::MouseEvent* event) override { - shelf_layout_manager_->UpdateAutoHideForMouseEvent( - event, WmWindow::Get(static_cast<aura::Window*>(event->target()))); - } - void OnGestureEvent(ui::GestureEvent* event) override { - shelf_layout_manager_->UpdateAutoHideForGestureEvent( - event, WmWindow::Get(static_cast<aura::Window*>(event->target()))); - } - - private: - ShelfLayoutManager* shelf_layout_manager_; - DISALLOW_COPY_AND_ASSIGN(AutoHideEventHandler); -}; - -// WmShelf --------------------------------------------------------------------- - -WmShelf::WmShelf() {} - -WmShelf::~WmShelf() {} - -// static -WmShelf* WmShelf::ForWindow(WmWindow* window) { - return window->GetRootWindowController()->GetShelf(); -} - -// static -bool WmShelf::CanChangeShelfAlignment() { - if (WmShell::Get()->system_tray_delegate()->IsUserSupervised()) - return false; - - LoginStatus login_status = - WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); - - switch (login_status) { - case LoginStatus::LOCKED: - // Shelf alignment changes can be requested while being locked, but will - // be applied upon unlock. - case LoginStatus::USER: - case LoginStatus::OWNER: - return true; - case LoginStatus::PUBLIC: - case LoginStatus::SUPERVISED: - case LoginStatus::GUEST: - case LoginStatus::KIOSK_APP: - case LoginStatus::ARC_KIOSK_APP: - case LoginStatus::NOT_LOGGED_IN: - return false; - } - - NOTREACHED(); - return false; -} - -void WmShelf::CreateShelfWidget(WmWindow* root) { - DCHECK(!shelf_widget_); - WmWindow* shelf_container = - root->GetChildByShellWindowId(kShellWindowId_ShelfContainer); - shelf_widget_.reset(new ShelfWidget(shelf_container, this)); - - DCHECK(!shelf_layout_manager_); - shelf_layout_manager_ = shelf_widget_->shelf_layout_manager(); - shelf_layout_manager_->AddObserver(this); - - // Must occur after |shelf_widget_| is constructed because the system tray - // constructors call back into WmShelf::shelf_widget(). - DCHECK(!shelf_widget_->status_area_widget()); - WmWindow* status_container = - root->GetChildByShellWindowId(kShellWindowId_StatusContainer); - shelf_widget_->CreateStatusAreaWidget(status_container); - - // TODO: ShelfBezelEventHandler needs to work with mus too. - // http://crbug.com/636647 - if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL) - bezel_event_handler_ = base::MakeUnique<ShelfBezelEventHandler>(this); -} - -void WmShelf::ShutdownShelfWidget() { - if (shelf_widget_) - shelf_widget_->Shutdown(); -} - -void WmShelf::DestroyShelfWidget() { - shelf_widget_.reset(); -} - -void WmShelf::CreateShelfView() { - DCHECK(shelf_layout_manager_); - DCHECK(shelf_widget_); - DCHECK(!shelf_view_); - shelf_view_ = shelf_widget_->CreateShelfView(); - shelf_locking_manager_.reset(new ShelfLockingManager(this)); - WmShell::Get()->shelf_controller()->NotifyShelfCreated(this); -} - -void WmShelf::ShutdownShelf() { - DCHECK(shelf_view_); - shelf_locking_manager_.reset(); - shelf_view_ = nullptr; -} - -bool WmShelf::IsShelfInitialized() const { - return !!shelf_view_; -} - -WmWindow* WmShelf::GetWindow() { - return WmWindow::Get(shelf_widget_->GetNativeWindow()); -} - -void WmShelf::SetAlignment(ShelfAlignment alignment) { - DCHECK(shelf_layout_manager_); - DCHECK(shelf_locking_manager_); - - if (alignment_ == alignment) - return; - - if (shelf_locking_manager_->is_locked() && - alignment != SHELF_ALIGNMENT_BOTTOM_LOCKED) { - shelf_locking_manager_->set_stored_alignment(alignment); - return; - } - - alignment_ = alignment; - // The ShelfWidget notifies the ShelfView of the alignment change. - shelf_widget_->OnShelfAlignmentChanged(); - shelf_layout_manager_->LayoutShelf(); - WmShell::Get()->shelf_controller()->NotifyShelfAlignmentChanged(this); - WmShell::Get()->NotifyShelfAlignmentChanged(GetWindow()->GetRootWindow()); -} - -bool WmShelf::IsHorizontalAlignment() const { - switch (alignment_) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - return true; - case SHELF_ALIGNMENT_LEFT: - case SHELF_ALIGNMENT_RIGHT: - return false; - } - NOTREACHED(); - return true; -} - -int WmShelf::SelectValueForShelfAlignment(int bottom, - int left, - int right) const { - switch (alignment_) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - return bottom; - case SHELF_ALIGNMENT_LEFT: - return left; - case SHELF_ALIGNMENT_RIGHT: - return right; - } - NOTREACHED(); - return bottom; -} - -int WmShelf::PrimaryAxisValue(int horizontal, int vertical) const { - return IsHorizontalAlignment() ? horizontal : vertical; -} - -void WmShelf::SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide_behavior) { - DCHECK(shelf_layout_manager_); - - if (auto_hide_behavior_ == auto_hide_behavior) - return; - - auto_hide_behavior_ = auto_hide_behavior; - WmShell::Get()->shelf_controller()->NotifyShelfAutoHideBehaviorChanged(this); - WmShell::Get()->NotifyShelfAutoHideBehaviorChanged( - GetWindow()->GetRootWindow()); -} - -ShelfAutoHideState WmShelf::GetAutoHideState() const { - return shelf_layout_manager_->auto_hide_state(); -} - -void WmShelf::UpdateAutoHideState() { - shelf_layout_manager_->UpdateAutoHideState(); -} - -ShelfBackgroundType WmShelf::GetBackgroundType() const { - return shelf_widget_->GetBackgroundType(); -} - -bool WmShelf::IsVisible() const { - return shelf_widget_->IsShelfVisible(); -} - -void WmShelf::UpdateVisibilityState() { - if (shelf_layout_manager_) - shelf_layout_manager_->UpdateVisibilityState(); -} - -ShelfVisibilityState WmShelf::GetVisibilityState() const { - return shelf_layout_manager_ ? shelf_layout_manager_->visibility_state() - : SHELF_HIDDEN; -} - -gfx::Rect WmShelf::GetIdealBounds() { - return shelf_layout_manager_->GetIdealBounds(); -} - -gfx::Rect WmShelf::GetUserWorkAreaBounds() const { - return shelf_layout_manager_ ? shelf_layout_manager_->user_work_area_bounds() - : gfx::Rect(); -} - -void WmShelf::UpdateIconPositionForPanel(WmWindow* panel) { - shelf_widget_->UpdateIconPositionForPanel(panel); -} - -gfx::Rect WmShelf::GetScreenBoundsOfItemIconForWindow(WmWindow* window) { - if (!shelf_widget_) - return gfx::Rect(); - return shelf_widget_->GetScreenBoundsOfItemIconForWindow(window); -} - -// static -void WmShelf::LaunchShelfItem(int item_index) { - ShelfModel* shelf_model = WmShell::Get()->shelf_model(); - const ShelfItems& items = shelf_model->items(); - int item_count = shelf_model->item_count(); - int indexes_left = item_index >= 0 ? item_index : item_count; - int found_index = -1; - - // Iterating until we have hit the index we are interested in which - // is true once indexes_left becomes negative. - for (int i = 0; i < item_count && indexes_left >= 0; i++) { - if (items[i].type != TYPE_APP_LIST) { - found_index = i; - indexes_left--; - } - } - - // There are two ways how found_index can be valid: a.) the nth item was - // found (which is true when indexes_left is -1) or b.) the last item was - // requested (which is true when index was passed in as a negative number). - if (found_index >= 0 && (indexes_left == -1 || item_index < 0)) { - // Then set this one as active (or advance to the next item of its kind). - ActivateShelfItem(found_index); - } -} - -// static -void WmShelf::ActivateShelfItem(int item_index) { - ShelfModel* shelf_model = WmShell::Get()->shelf_model(); - const ShelfItem& item = shelf_model->items()[item_index]; - ShelfItemDelegate* item_delegate = shelf_model->GetShelfItemDelegate(item.id); - item_delegate->ItemSelected(ui::ET_KEY_RELEASED, ui::EF_NONE, - display::kInvalidDisplayId, LAUNCH_FROM_UNKNOWN); -} - -bool WmShelf::ProcessGestureEvent(const ui::GestureEvent& event) { - // Can be called at login screen. - if (!shelf_layout_manager_) - return false; - return shelf_layout_manager_->ProcessGestureEvent(event); -} - -void WmShelf::AddObserver(WmShelfObserver* observer) { - observers_.AddObserver(observer); -} - -void WmShelf::RemoveObserver(WmShelfObserver* observer) { - observers_.RemoveObserver(observer); -} - -void WmShelf::NotifyShelfIconPositionsChanged() { - for (auto& observer : observers_) - observer.OnShelfIconPositionsChanged(); -} - -StatusAreaWidget* WmShelf::GetStatusAreaWidget() const { - return shelf_widget_->status_area_widget(); -} - -void WmShelf::SetVirtualKeyboardBoundsForTesting(const gfx::Rect& bounds) { - shelf_layout_manager_->OnKeyboardBoundsChanging(bounds); -} - -ShelfLockingManager* WmShelf::GetShelfLockingManagerForTesting() { - return shelf_locking_manager_.get(); -} - -ShelfView* WmShelf::GetShelfViewForTesting() { - return shelf_view_; -} - -void WmShelf::WillDeleteShelfLayoutManager() { - if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS) { - // TODO(sky): this should be removed once Shell is used everywhere. - ShutdownShelfWidget(); - } - - // Clear event handlers that might forward events to the destroyed instance. - auto_hide_event_handler_.reset(); - bezel_event_handler_.reset(); - - DCHECK(shelf_layout_manager_); - shelf_layout_manager_->RemoveObserver(this); - shelf_layout_manager_ = nullptr; -} - -void WmShelf::WillChangeVisibilityState(ShelfVisibilityState new_state) { - for (auto& observer : observers_) - observer.WillChangeVisibilityState(new_state); - if (new_state != SHELF_AUTO_HIDE) { - auto_hide_event_handler_.reset(); - } else if (!auto_hide_event_handler_ && - aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL) { - auto_hide_event_handler_ = - base::MakeUnique<AutoHideEventHandler>(shelf_layout_manager()); - } -} - -void WmShelf::OnAutoHideStateChanged(ShelfAutoHideState new_state) { - for (auto& observer : observers_) - observer.OnAutoHideStateChanged(new_state); -} - -void WmShelf::OnBackgroundUpdated(ShelfBackgroundType background_type, - AnimationChangeType change_type) { - if (background_type == GetBackgroundType()) - return; - for (auto& observer : observers_) - observer.OnBackgroundTypeChanged(background_type, change_type); -} - -} // namespace ash
diff --git a/ash/shelf/wm_shelf.h b/ash/shelf/wm_shelf.h deleted file mode 100644 index 491f35e..0000000 --- a/ash/shelf/wm_shelf.h +++ /dev/null
@@ -1,188 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_WM_SHELF_H_ -#define ASH_SHELF_WM_SHELF_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_layout_manager_observer.h" -#include "base/observer_list.h" - -namespace gfx { -class Rect; -} - -namespace ui { -class GestureEvent; -} - -namespace ash { - -enum class AnimationChangeType; -class ShelfBezelEventHandler; -class ShelfLayoutManager; -class ShelfLayoutManagerTest; -class ShelfLockingManager; -class ShelfView; -class ShelfWidget; -class StatusAreaWidget; -class WmShelfObserver; -class WmWindow; - -// Controller for the shelf state. Exists for the lifetime of each root window -// controller. Note that the shelf widget may not be created until after login. -class ASH_EXPORT WmShelf : public ShelfLayoutManagerObserver { - public: - WmShelf(); - ~WmShelf() override; - - // Returns the shelf for the display that |window| is on. Note that the shelf - // widget may not exist, or the shelf may not be visible. - static WmShelf* ForWindow(WmWindow* window); - - // Returns if shelf alignment options are enabled, and the user is able to - // adjust the alignment (eg. not allowed in guest and supervised user modes). - static bool CanChangeShelfAlignment(); - - void CreateShelfWidget(WmWindow* root); - void ShutdownShelfWidget(); - void DestroyShelfWidget(); - - ShelfLayoutManager* shelf_layout_manager() const { - return shelf_layout_manager_; - } - - ShelfWidget* shelf_widget() { return shelf_widget_.get(); } - - // Creates the shelf view. - void CreateShelfView(); - - // TODO(jamescook): Eliminate this method. - void ShutdownShelf(); - - // True after the ShelfView has been created (e.g. after login). - bool IsShelfInitialized() const; - - // Returns the window showing the shelf. - WmWindow* GetWindow(); - - ShelfAlignment alignment() const { return alignment_; } - // TODO(jamescook): Replace with alignment(). - ShelfAlignment GetAlignment() const { return alignment_; } - void SetAlignment(ShelfAlignment alignment); - - // Returns true if the shelf alignment is horizontal (i.e. at the bottom). - bool IsHorizontalAlignment() const; - - // Returns a value based on shelf alignment. - int SelectValueForShelfAlignment(int bottom, int left, int right) const; - - // Returns |horizontal| is shelf is horizontal, otherwise |vertical|. - int PrimaryAxisValue(int horizontal, int vertical) const; - - ShelfAutoHideBehavior auto_hide_behavior() const { - return auto_hide_behavior_; - } - void SetAutoHideBehavior(ShelfAutoHideBehavior behavior); - - ShelfAutoHideState GetAutoHideState() const; - - // Invoke when the auto-hide state may have changed (for example, when the - // system tray bubble opens it should force the shelf to be visible). - void UpdateAutoHideState(); - - ShelfBackgroundType GetBackgroundType() const; - - // Whether the shelf view is visible. - // TODO(jamescook): Consolidate this with GetVisibilityState(). - bool IsVisible() const; - - void UpdateVisibilityState(); - - ShelfVisibilityState GetVisibilityState() const; - - // Returns the ideal bounds of the shelf assuming it is visible. - gfx::Rect GetIdealBounds(); - - gfx::Rect GetUserWorkAreaBounds() const; - - // Updates the icon position given the current window bounds. This is used - // when dragging panels to reposition them with respect to the other panels. - void UpdateIconPositionForPanel(WmWindow* window); - - // Returns the screen bounds of the item for the specified window. If there is - // no item for the specified window an empty rect is returned. - gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window); - - // Launch a 0-indexed shelf item in the shelf. A negative index launches the - // last shelf item in the shelf. - static void LaunchShelfItem(int item_index); - - // Activates the shelf item specified by the index in the list of shelf items. - static void ActivateShelfItem(int item_index); - - // Handles a gesture |event| coming from a source outside the shelf widget - // (e.g. the status area widget). Allows support for behaviors like toggling - // auto-hide with a swipe, even if that gesture event hits another window. - // Returns true if the event was handled. - bool ProcessGestureEvent(const ui::GestureEvent& event); - - void AddObserver(WmShelfObserver* observer); - void RemoveObserver(WmShelfObserver* observer); - - void NotifyShelfIconPositionsChanged(); - StatusAreaWidget* GetStatusAreaWidget() const; - - void SetVirtualKeyboardBoundsForTesting(const gfx::Rect& bounds); - ShelfLockingManager* GetShelfLockingManagerForTesting(); - ShelfView* GetShelfViewForTesting(); - - protected: - // ShelfLayoutManagerObserver: - void WillDeleteShelfLayoutManager() override; - void WillChangeVisibilityState(ShelfVisibilityState new_state) override; - void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; - void OnBackgroundUpdated(ShelfBackgroundType background_type, - AnimationChangeType change_type) override; - - private: - class AutoHideEventHandler; - friend class ShelfLayoutManagerTest; - - // Layout manager for the shelf container window. Instances are constructed by - // ShelfWidget and lifetimes are managed by the container windows themselves. - ShelfLayoutManager* shelf_layout_manager_ = nullptr; - - std::unique_ptr<ShelfWidget> shelf_widget_; - - // Internal implementation detail. Do not expose externally. Owned by views - // hierarchy. Null before login and in secondary display init. - ShelfView* shelf_view_ = nullptr; - - // These initial values hide the shelf until user preferences are available. - ShelfAlignment alignment_ = SHELF_ALIGNMENT_BOTTOM_LOCKED; - ShelfAutoHideBehavior auto_hide_behavior_ = SHELF_AUTO_HIDE_ALWAYS_HIDDEN; - - // Sets shelf alignment to bottom during login and screen lock. - std::unique_ptr<ShelfLockingManager> shelf_locking_manager_; - - base::ObserverList<WmShelfObserver> observers_; - - // Forwards mouse and gesture events to ShelfLayoutManager for auto-hide. - // TODO(mash): Facilitate simliar functionality in mash: crbug.com/631216 - std::unique_ptr<AutoHideEventHandler> auto_hide_event_handler_; - - // Forwards touch gestures on a bezel sensor to the shelf. - // TODO(mash): Facilitate simliar functionality in mash: crbug.com/636647 - std::unique_ptr<ShelfBezelEventHandler> bezel_event_handler_; - - DISALLOW_COPY_AND_ASSIGN(WmShelf); -}; - -} // namespace ash - -#endif // ASH_SHELF_WM_SHELF_H_
diff --git a/ash/shelf/wm_shelf_observer.h b/ash/shelf/wm_shelf_observer.h deleted file mode 100644 index 55033be..0000000 --- a/ash/shelf/wm_shelf_observer.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_WM_SHELF_OBSERVER_H_ -#define ASH_SHELF_WM_SHELF_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" - -namespace ash { - -enum class AnimationChangeType; - -// Used to observe changes to the shelf. -class ASH_EXPORT WmShelfObserver { - public: - virtual void OnBackgroundTypeChanged(ShelfBackgroundType background_type, - AnimationChangeType change_type) {} - virtual void WillChangeVisibilityState(ShelfVisibilityState new_state) {} - virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) {} - virtual void OnShelfIconPositionsChanged() {} - - protected: - virtual ~WmShelfObserver() {} -}; - -} // namespace ash - -#endif // ASH_SHELF_WM_SHELF_OBSERVER_H_
diff --git a/ash/shelf/wm_shelf_util.cc b/ash/shelf/wm_shelf_util.cc deleted file mode 100644 index 41934c5..0000000 --- a/ash/shelf/wm_shelf_util.cc +++ /dev/null
@@ -1,14 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/shelf/wm_shelf_util.h" - -namespace ash { - -bool IsHorizontalAlignment(ShelfAlignment alignment) { - return alignment == SHELF_ALIGNMENT_BOTTOM || - alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED; -} - -} // namespace ash
diff --git a/ash/shelf/wm_shelf_util.h b/ash/shelf/wm_shelf_util.h deleted file mode 100644 index 5176ec9..0000000 --- a/ash/shelf/wm_shelf_util.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SHELF_WM_SHELF_UTIL_H_ -#define ASH_SHELF_WM_SHELF_UTIL_H_ - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" - -namespace ash { - -// Returns true if the shelf |alignment| is horizontal. -// TODO(jamescook): Remove this in favor of WmShelf::IsHorizontalAlignment(). -ASH_EXPORT bool IsHorizontalAlignment(ShelfAlignment alignment); - -} // namespace ash - -#endif // ASH_SHELF_WM_SHELF_UTIL_H_
diff --git a/ash/shell.cc b/ash/shell.cc index 3a71803..90c62c0 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -8,7 +8,6 @@ #include <string> #include <utility> -#include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_controller_delegate_aura.h" #include "ash/accelerators/accelerator_delegate.h" #include "ash/accelerators/magnifier_key_scroller.h" @@ -16,13 +15,33 @@ #include "ash/app_list/app_list_delegate_impl.h" #include "ash/aura/wm_shell_aura.h" #include "ash/autoclick/autoclick_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/ash_constants.h" +#include "ash/common/frame/custom_frame_view_ash.h" #include "ash/common/gpu_support.h" #include "ash/common/keyboard/keyboard_ui.h" #include "ash/common/login_status.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/app_list_shelf_item_delegate.h" +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/shell_delegate.h" +#include "ash/common/system/chromeos/bluetooth/bluetooth_notification_controller.h" +#include "ash/common/system/chromeos/network/sms_observer.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/maximize_mode/maximize_mode_window_manager.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm/system_modal_container_layout_manager.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/cursor_window_controller.h" @@ -40,7 +59,6 @@ #include "ash/display/window_tree_host_manager.h" #include "ash/drag_drop/drag_drop_controller.h" #include "ash/first_run/first_run_helper_impl.h" -#include "ash/frame/custom_frame_view_ash.h" #include "ash/high_contrast/high_contrast_controller.h" #include "ash/ime/input_method_event_handler.h" #include "ash/laser/laser_pointer_controller.h" @@ -48,49 +66,31 @@ #include "ash/magnifier/partial_magnification_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/app_list_shelf_item_delegate.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell_init_params.h" #include "ash/sticky_keys/sticky_keys_controller.h" -#include "ash/system/bluetooth/bluetooth_notification_controller.h" -#include "ash/system/network/sms_observer.h" -#include "ash/system/power/power_event_observer.h" -#include "ash/system/power/power_status.h" -#include "ash/system/power/video_activity_notifier.h" -#include "ash/system/screen_layout_observer.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray_delegate.h" +#include "ash/system/chromeos/power/power_event_observer.h" +#include "ash/system/chromeos/power/video_activity_notifier.h" +#include "ash/system/chromeos/screen_layout_observer.h" #include "ash/touch/ash_touch_transform_controller.h" #include "ash/utility/screenshot_controller.h" #include "ash/virtual_keyboard_controller.h" #include "ash/wm/ash_focus_rules.h" #include "ash/wm/ash_native_cursor_manager.h" -#include "ash/wm/container_finder.h" #include "ash/wm/event_client_impl.h" #include "ash/wm/immersive_handler_factory_ash.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" -#include "ash/wm/mru_window_tracker.h" #include "ash/wm/overlay_event_filter.h" #include "ash/wm/overview/scoped_overview_animation_settings_factory_aura.h" #include "ash/wm/power_button_controller.h" #include "ash/wm/resize_shadow_controller.h" -#include "ash/wm/root_window_finder.h" #include "ash/wm/screen_pinning_controller.h" #include "ash/wm/system_gesture_event_filter.h" #include "ash/wm/system_modal_container_event_filter.h" -#include "ash/wm/system_modal_container_layout_manager.h" #include "ash/wm/toplevel_window_event_handler.h" #include "ash/wm/video_detector.h" #include "ash/wm/window_animations.h" -#include "ash/wm/window_positioner.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" -#include "ash/wm/workspace_controller.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h"
diff --git a/ash/shell/context_menu.cc b/ash/shell/context_menu.cc index 8282dac..5624b18 100644 --- a/ash/shell/context_menu.cc +++ b/ash/shell/context_menu.cc
@@ -4,8 +4,8 @@ #include "ash/shell/context_menu.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf.h" #include "ash/strings/grit/ash_strings.h" namespace ash {
diff --git a/ash/shell/context_menu.h b/ash/shell/context_menu.h index 6c25698c..3db053c 100644 --- a/ash/shell/context_menu.h +++ b/ash/shell/context_menu.h
@@ -5,7 +5,7 @@ #ifndef ASH_SHELL_CONTEXT_MENU_H_ #define ASH_SHELL_CONTEXT_MENU_H_ -#include "ash/shelf/shelf_alignment_menu.h" +#include "ash/common/shelf/shelf_alignment_menu.h" #include "base/macros.h" #include "ui/base/models/simple_menu_model.h"
diff --git a/ash/shell/panel_window.cc b/ash/shell/panel_window.cc index 1dfedf9aa..5566a024 100644 --- a/ash/shell/panel_window.cc +++ b/ash/shell/panel_window.cc
@@ -4,9 +4,9 @@ #include "ash/shell/panel_window.h" +#include "ash/common/wm/panels/panel_frame_view.h" #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" -#include "ash/wm/panels/panel_frame_view.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h" #include "ui/gfx/canvas.h"
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 0f47f6a..e77396a 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc
@@ -9,16 +9,16 @@ #include "ash/common/gpu_support_stub.h" #include "ash/common/palette_delegate.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/default_system_tray_delegate.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/window_state.h" #include "ash/default_wallpaper_delegate.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/shell/context_menu.h" #include "ash/shell/example_factory.h" #include "ash/shell/toplevel_window.h" -#include "ash/system/tray/default_system_tray_delegate.h" #include "ash/test/test_keyboard_ui.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/wm/window_state.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h"
diff --git a/ash/shell/toplevel_window.cc b/ash/shell/toplevel_window.cc index b659f489..75faae1 100644 --- a/ash/shell/toplevel_window.cc +++ b/ash/shell/toplevel_window.cc
@@ -4,9 +4,9 @@ #include "ash/shell/toplevel_window.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_state.h" #include "ash/shell.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h"
diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc index 6a959d1..a9f20f1 100644 --- a/ash/shell/window_type_launcher.cc +++ b/ash/shell/window_type_launcher.cc
@@ -7,6 +7,8 @@ #include <utility> #include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/web_notification/web_notification_tray.h" #include "ash/common/wm_shell.h" #include "ash/content/shell_content_state.h" #include "ash/public/cpp/shell_window_ids.h" @@ -15,8 +17,6 @@ #include "ash/shell/example_factory.h" #include "ash/shell/panel_window.h" #include "ash/shell/toplevel_window.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/web_notification/web_notification_tray.h" #include "ash/test/child_modal_window.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h"
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc index a789dd6..23cf1d3 100644 --- a/ash/shell/window_watcher.cc +++ b/ash/shell/window_watcher.cc
@@ -6,12 +6,12 @@ #include <utility> +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_widget.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/window_tree_host_manager.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell/window_watcher_shelf_item_delegate.h" #include "ash/wm/window_properties.h"
diff --git a/ash/shell/window_watcher.h b/ash/shell/window_watcher.h index accd0ef..757ea91 100644 --- a/ash/shell/window_watcher.h +++ b/ash/shell/window_watcher.h
@@ -10,7 +10,7 @@ #include <map> #include <memory> -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_types.h" #include "base/compiler_specific.h" #include "base/logging.h" #include "base/macros.h"
diff --git a/ash/shell/window_watcher_shelf_item_delegate.h b/ash/shell/window_watcher_shelf_item_delegate.h index 57f7aa10..73bb422 100644 --- a/ash/shell/window_watcher_shelf_item_delegate.h +++ b/ash/shell/window_watcher_shelf_item_delegate.h
@@ -5,8 +5,8 @@ #ifndef ASH_SHELL_WINDOW_WATCHER_SHELF_ITEM_DELEGATE_H_ #define ASH_SHELL_WINDOW_WATCHER_SHELF_ITEM_DELEGATE_H_ -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_item_types.h" #include "base/compiler_specific.h" #include "base/macros.h"
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc index 69877481..881b972 100644 --- a/ash/shell_unittest.cc +++ b/ash/shell_unittest.cc
@@ -8,6 +8,9 @@ #include <vector> #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wallpaper/wallpaper_widget_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" @@ -15,9 +18,6 @@ #include "ash/drag_drop/drag_drop_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/test/ash_test_base.h" #include "ash/test/shell_test_api.h" #include "ash/wm/window_util.h"
diff --git a/ash/system/DEPS b/ash/system/DEPS index 7e53afa4..9204a9c 100644 --- a/ash/system/DEPS +++ b/ash/system/DEPS
@@ -1,6 +1,7 @@ include_rules = [ + # NOTE: Use WmShelf in //ash/common/shelf for all external shelf access. + # See http://crbug.com/615502 + "-ash/shelf", "+components/prefs", "+components/signin/core/account_id", - "+grit/ui_chromeos_resources.h", - "+grit/ui_chromeos_strings.h", ]
diff --git a/ash/system/accessibility_observer.h b/ash/system/accessibility_observer.h deleted file mode 100644 index fb6b9371..0000000 --- a/ash/system/accessibility_observer.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_ACCESSIBILITY_OBSERVER_H_ -#define ASH_SYSTEM_ACCESSIBILITY_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "ash/common/accessibility_types.h" - -namespace ash { - -class ASH_EXPORT AccessibilityObserver { - public: - virtual ~AccessibilityObserver() {} - - // Notifies when accessibility mode changes. - virtual void OnAccessibilityModeChanged( - AccessibilityNotificationVisibility notify) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_ACCESSIBILITY_OBSERVER_H_
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc deleted file mode 100644 index 69b48a65..0000000 --- a/ash/system/audio/audio_detailed_view.cc +++ /dev/null
@@ -1,198 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/audio/audio_detailed_view.h" - -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/strings/utf_string_conversions.h" -#include "chromeos/audio/cras_audio_handler.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/controls/separator.h" - -namespace { - -base::string16 GetAudioDeviceName(const chromeos::AudioDevice& device) { - switch (device.type) { - case chromeos::AUDIO_TYPE_FRONT_MIC: - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_FRONT_MIC); - case chromeos::AUDIO_TYPE_HEADPHONE: - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HEADPHONE); - case chromeos::AUDIO_TYPE_INTERNAL_SPEAKER: - return l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_SPEAKER); - case chromeos::AUDIO_TYPE_INTERNAL_MIC: - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_MIC); - case chromeos::AUDIO_TYPE_REAR_MIC: - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_REAR_MIC); - case chromeos::AUDIO_TYPE_USB: - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_AUDIO_USB_DEVICE, - base::UTF8ToUTF16(device.display_name)); - case chromeos::AUDIO_TYPE_BLUETOOTH: - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_AUDIO_BLUETOOTH_DEVICE, - base::UTF8ToUTF16(device.display_name)); - case chromeos::AUDIO_TYPE_HDMI: - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HDMI_DEVICE, - base::UTF8ToUTF16(device.display_name)); - case chromeos::AUDIO_TYPE_MIC: - return l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_AUDIO_MIC_JACK_DEVICE); - default: - return base::UTF8ToUTF16(device.display_name); - } -} - -} // namespace - -using chromeos::CrasAudioHandler; - -namespace ash { -namespace tray { - -AudioDetailedView::AudioDetailedView(SystemTrayItem* owner) - : TrayDetailsView(owner) { - CreateItems(); - Update(); -} - -AudioDetailedView::~AudioDetailedView() {} - -void AudioDetailedView::Update() { - UpdateAudioDevices(); - Layout(); -} - -void AudioDetailedView::AddInputHeader() { - AddScrollListInfoItem(IDS_ASH_STATUS_TRAY_AUDIO_INPUT, - kSystemMenuAudioInputIcon); -} - -void AudioDetailedView::AddOutputHeader() { - AddScrollListInfoItem(IDS_ASH_STATUS_TRAY_AUDIO_OUTPUT, - kSystemMenuAudioOutputIcon); -} - -void AudioDetailedView::AddScrollListInfoItem(int text_id, - const gfx::VectorIcon& icon) { - TriView* header = TrayPopupUtils::CreateDefaultRowView(); - TrayPopupUtils::ConfigureAsStickyHeader(header); - views::ImageView* image_view = TrayPopupUtils::CreateMainImageView(); - image_view->SetImage(gfx::CreateVectorIcon( - icon, GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor))); - header->AddView(TriView::Container::START, image_view); - - views::Label* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(l10n_util::GetStringUTF16(text_id)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); - style.SetupLabel(label); - header->AddView(TriView::Container::CENTER, label); - - header->SetContainerVisible(TriView::Container::END, false); - scroll_content()->AddChildView(header); -} - -HoverHighlightView* AudioDetailedView::AddScrollListItem( - const base::string16& text, - bool highlight, - bool checked) { - HoverHighlightView* container = new HoverHighlightView(this); - - container->AddLabelRowMd(text); - if (checked) { - gfx::ImageSkia check_mark = gfx::CreateVectorIcon( - gfx::VectorIconId::CHECK_CIRCLE, gfx::kGoogleGreen700); - container->AddRightIcon(check_mark, check_mark.width()); - container->SetRightViewVisible(true); - container->SetAccessiblityState( - HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); - } else { - container->SetAccessiblityState( - HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); - } - - scroll_content()->AddChildView(container); - return container; -} - -void AudioDetailedView::CreateItems() { - CreateScrollableList(); - CreateTitleRow(IDS_ASH_STATUS_TRAY_AUDIO); -} - -void AudioDetailedView::UpdateAudioDevices() { - output_devices_.clear(); - input_devices_.clear(); - chromeos::AudioDeviceList devices; - CrasAudioHandler::Get()->GetAudioDevices(&devices); - for (size_t i = 0; i < devices.size(); ++i) { - // Don't display keyboard mic or aokr type. - if (!devices[i].is_for_simple_usage()) - continue; - if (devices[i].is_input) - input_devices_.push_back(devices[i]); - else - output_devices_.push_back(devices[i]); - } - UpdateScrollableList(); -} - -void AudioDetailedView::UpdateScrollableList() { - scroll_content()->RemoveAllChildViews(true); - device_map_.clear(); - - // Add audio output devices. - const bool has_output_devices = output_devices_.size() > 0; - if (has_output_devices) - AddOutputHeader(); - - for (size_t i = 0; i < output_devices_.size(); ++i) { - HoverHighlightView* container = AddScrollListItem( - GetAudioDeviceName(output_devices_[i]), false /* highlight */, - output_devices_[i].active); /* checkmark if active */ - device_map_[container] = output_devices_[i]; - } - - if (has_output_devices) { - scroll_content()->AddChildView( - TrayPopupUtils::CreateListSubHeaderSeparator()); - } - - // Add audio input devices. - const bool has_input_devices = input_devices_.size() > 0; - if (has_input_devices) - AddInputHeader(); - - for (size_t i = 0; i < input_devices_.size(); ++i) { - HoverHighlightView* container = AddScrollListItem( - GetAudioDeviceName(input_devices_[i]), false /* highlight */, - input_devices_[i].active); /* checkmark if active */ - device_map_[container] = input_devices_[i]; - } - - scroll_content()->SizeToPreferredSize(); - scroller()->Layout(); -} - -void AudioDetailedView::HandleViewClicked(views::View* view) { - AudioDeviceMap::iterator iter = device_map_.find(view); - if (iter == device_map_.end()) - return; - chromeos::AudioDevice device = iter->second; - CrasAudioHandler::Get()->SwitchToDevice(device, true, - CrasAudioHandler::ACTIVATE_BY_USER); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/audio/audio_detailed_view.h b/ash/system/audio/audio_detailed_view.h deleted file mode 100644 index 5e2d3fd..0000000 --- a/ash/system/audio/audio_detailed_view.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_AUDIO_AUDIO_DETAILED_VIEW_H_ -#define ASH_SYSTEM_AUDIO_AUDIO_DETAILED_VIEW_H_ - -#include <map> - -#include "ash/system/tray/tray_details_view.h" -#include "base/macros.h" -#include "chromeos/audio/audio_device.h" - -namespace gfx { -struct VectorIcon; -} - -namespace views { -class View; -} - -namespace ash { -class HoverHighlightView; - -namespace tray { - -class AudioDetailedView : public TrayDetailsView { - public: - explicit AudioDetailedView(SystemTrayItem* owner); - - ~AudioDetailedView() override; - - void Update(); - - private: - // Helper functions to add non-clickable header rows within the scrollable - // list. - void AddInputHeader(); - void AddOutputHeader(); - void AddScrollListInfoItem(int text_id, const gfx::VectorIcon& icon); - - HoverHighlightView* AddScrollListItem(const base::string16& text, - bool highlight, - bool checked); - - void CreateItems(); - - void UpdateScrollableList(); - void UpdateAudioDevices(); - - // TrayDetailsView: - void HandleViewClicked(views::View* view) override; - - typedef std::map<views::View*, chromeos::AudioDevice> AudioDeviceMap; - - chromeos::AudioDeviceList output_devices_; - chromeos::AudioDeviceList input_devices_; - AudioDeviceMap device_map_; - - DISALLOW_COPY_AND_ASSIGN(AudioDetailedView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_AUDIO_AUDIO_DETAILED_VIEW_H_
diff --git a/ash/system/audio/tray_audio.cc b/ash/system/audio/tray_audio.cc deleted file mode 100644 index ac4a3fb..0000000 --- a/ash/system/audio/tray_audio.cc +++ /dev/null
@@ -1,209 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/audio/tray_audio.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/system/audio/audio_detailed_view.h" -#include "ash/system/audio/tray_audio_delegate_chromeos.h" -#include "ash/system/audio/volume_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/tray_constants.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "ui/display/display.h" -#include "ui/display/manager/managed_display_info.h" -#include "ui/display/screen.h" -#include "ui/views/view.h" - -namespace ash { - -using chromeos::CrasAudioHandler; -using chromeos::DBusThreadManager; -using system::TrayAudioDelegate; -using system::TrayAudioDelegateChromeOs; - -TrayAudio::TrayAudio(SystemTray* system_tray) - : TrayImageItem(system_tray, kSystemTrayVolumeMuteIcon, UMA_AUDIO), - audio_delegate_(new TrayAudioDelegateChromeOs()), - volume_view_(nullptr), - pop_up_volume_view_(false), - audio_detail_view_(nullptr) { - if (CrasAudioHandler::IsInitialized()) - CrasAudioHandler::Get()->AddAudioObserver(this); - display::Screen::GetScreen()->AddObserver(this); - DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); -} - -TrayAudio::~TrayAudio() { - DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); - display::Screen::GetScreen()->RemoveObserver(this); - if (CrasAudioHandler::IsInitialized()) - CrasAudioHandler::Get()->RemoveAudioObserver(this); -} - -// static -void TrayAudio::ShowPopUpVolumeView() { - // Show the popup on all monitors with a system tray. - for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { - SystemTray* system_tray = root->GetRootWindowController()->GetSystemTray(); - if (!system_tray) - continue; - // Show the popup by simulating a volume change. The provided node id and - // volume value are ignored. - system_tray->GetTrayAudio()->OnOutputNodeVolumeChanged(0, 0); - } -} - -bool TrayAudio::GetInitialVisibility() { - return audio_delegate_->IsOutputAudioMuted(); -} - -views::View* TrayAudio::CreateDefaultView(LoginStatus status) { - volume_view_ = new tray::VolumeView(this, audio_delegate_.get(), true); - return volume_view_; -} - -views::View* TrayAudio::CreateDetailedView(LoginStatus status) { - if (pop_up_volume_view_) { - volume_view_ = new tray::VolumeView(this, audio_delegate_.get(), false); - return volume_view_; - } else { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DETAILED_AUDIO_VIEW); - audio_detail_view_ = new tray::AudioDetailedView(this); - return audio_detail_view_; - } -} - -void TrayAudio::DestroyDefaultView() { - volume_view_ = NULL; -} - -void TrayAudio::DestroyDetailedView() { - if (audio_detail_view_) { - audio_detail_view_ = nullptr; - } else if (volume_view_) { - volume_view_ = nullptr; - pop_up_volume_view_ = false; - } -} - -bool TrayAudio::ShouldShowShelf() const { - return !pop_up_volume_view_; -} - -void TrayAudio::OnOutputNodeVolumeChanged(uint64_t /* node_id */, - int /* volume */) { - float percent = - static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f; - if (tray_view()) - tray_view()->SetVisible(GetInitialVisibility()); - - if (volume_view_) { - volume_view_->SetVolumeLevel(percent); - SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); - return; - } - pop_up_volume_view_ = true; - PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); -} - -void TrayAudio::OnOutputMuteChanged(bool /* mute_on */, bool system_adjust) { - if (tray_view()) - tray_view()->SetVisible(GetInitialVisibility()); - - if (volume_view_) { - volume_view_->Update(); - SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); - } else if (!system_adjust) { - pop_up_volume_view_ = true; - PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); - } -} - -void TrayAudio::OnAudioNodesChanged() { - Update(); -} - -void TrayAudio::OnActiveOutputNodeChanged() { - Update(); -} - -void TrayAudio::OnActiveInputNodeChanged() { - Update(); -} - -void TrayAudio::ChangeInternalSpeakerChannelMode() { - // Swap left/right channel only if it is in Yoga mode. - system::TrayAudioDelegate::AudioChannelMode channel_mode = - system::TrayAudioDelegate::NORMAL; - if (display::Display::HasInternalDisplay()) { - const display::ManagedDisplayInfo& display_info = - WmShell::Get()->GetDisplayInfo(display::Display::InternalDisplayId()); - if (display_info.GetActiveRotation() == display::Display::ROTATE_180) - channel_mode = system::TrayAudioDelegate::LEFT_RIGHT_SWAPPED; - } - - audio_delegate_->SetInternalSpeakerChannelMode(channel_mode); -} - -void TrayAudio::OnDisplayAdded(const display::Display& new_display) { - if (!new_display.IsInternal()) - return; - ChangeInternalSpeakerChannelMode(); - - // This event will be triggered when the lid of the device is opened to exit - // the docked mode, we should always start or re-start HDMI re-discovering - // grace period right after this event. - audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(true); -} - -void TrayAudio::OnDisplayRemoved(const display::Display& old_display) { - if (!old_display.IsInternal()) - return; - ChangeInternalSpeakerChannelMode(); - - // This event will be triggered when the lid of the device is closed to enter - // the docked mode, we should always start or re-start HDMI re-discovering - // grace period right after this event. - audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(true); -} - -void TrayAudio::OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) { - if (!display.IsInternal()) - return; - - if (changed_metrics & display::DisplayObserver::DISPLAY_METRIC_ROTATION) - ChangeInternalSpeakerChannelMode(); - - // The event could be triggered multiple times during the HDMI display - // transition, we don't need to restart HDMI re-discovering grace period - // it is already started earlier. - audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(false); -} - -void TrayAudio::SuspendDone(const base::TimeDelta& sleep_duration) { - // This event is triggered when the device resumes after earlier suspension, - // we should always start or re-start HDMI re-discovering - // grace period right after this event. - audio_delegate_->SetActiveHDMIOutoutRediscoveringIfNecessary(true); -} - -void TrayAudio::Update() { - if (tray_view()) - tray_view()->SetVisible(GetInitialVisibility()); - if (volume_view_) { - volume_view_->SetVolumeLevel( - static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f); - volume_view_->Update(); - } - - if (audio_detail_view_) - audio_detail_view_->Update(); -} - -} // namespace ash
diff --git a/ash/system/audio/tray_audio.h b/ash/system/audio/tray_audio.h deleted file mode 100644 index c82fdf3..0000000 --- a/ash/system/audio/tray_audio.h +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_AUDIO_TRAY_AUDIO_H_ -#define ASH_SYSTEM_AUDIO_TRAY_AUDIO_H_ - -#include <stdint.h> - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/system/tray/tray_image_item.h" -#include "base/macros.h" -#include "chromeos/audio/cras_audio_handler.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/display/display_observer.h" - -namespace ash { - -namespace system { -class TrayAudioDelegate; -} - -namespace tray { -class AudioDetailedView; -class VolumeView; -} - -// The system tray item for audio input and output. -class ASH_EXPORT TrayAudio : public TrayImageItem, - public chromeos::CrasAudioHandler::AudioObserver, - public display::DisplayObserver, - public chromeos::PowerManagerClient::Observer { - public: - explicit TrayAudio(SystemTray* system_tray); - ~TrayAudio() override; - - // Temporarily shows the pop-up volume slider on all displays. Used by ARC - // when an Android app changes the system volume. - static void ShowPopUpVolumeView(); - - tray::VolumeView* volume_view_for_testing() { return volume_view_; } - bool pop_up_volume_view_for_testing() { return pop_up_volume_view_; } - - private: - // Overridden from display::DisplayObserver. - void OnDisplayAdded(const display::Display& new_display) override; - void OnDisplayRemoved(const display::Display& old_display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) override; - - // Overridden from TrayImageItem. - bool GetInitialVisibility() override; - - // Overridden from SystemTrayItem. - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - bool ShouldShowShelf() const override; - - // Overridden from CrasAudioHandler::AudioObserver. - void OnOutputNodeVolumeChanged(uint64_t node_id, int volume) override; - void OnOutputMuteChanged(bool mute_on, bool system_adjust) override; - void OnAudioNodesChanged() override; - void OnActiveOutputNodeChanged() override; - void OnActiveInputNodeChanged() override; - - // Overridden from chromeos::PowerManagerClient::Observer. - void SuspendDone(const base::TimeDelta& sleep_duration) override; - - // Swaps the left and right channels on yoga devices based on orientation. - void ChangeInternalSpeakerChannelMode(); - - // Updates the UI views. - void Update(); - - // TODO(jamescook): Remove this delegate and inline all the code. - std::unique_ptr<system::TrayAudioDelegate> audio_delegate_; - tray::VolumeView* volume_view_; - - // True if VolumeView should be created for accelerator pop up; - // Otherwise, it should be created for detailed view in ash tray bubble. - bool pop_up_volume_view_; - - tray::AudioDetailedView* audio_detail_view_; - - DISALLOW_COPY_AND_ASSIGN(TrayAudio); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_AUDIO_TRAY_AUDIO_H_
diff --git a/ash/system/audio/tray_audio_delegate.h b/ash/system/audio/tray_audio_delegate.h deleted file mode 100644 index 3ce10d4..0000000 --- a/ash/system/audio/tray_audio_delegate.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_H_ -#define ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_H_ - -namespace gfx { -struct VectorIcon; -} - -namespace ash { -namespace system { - -class TrayAudioDelegate { - public: - enum { kNoAudioDeviceIcon = -1 }; - enum AudioChannelMode { - NORMAL, - LEFT_RIGHT_SWAPPED, - }; - - virtual ~TrayAudioDelegate() {} - - // Sets the volume level of the output device to the minimum level which is - // deemed to be audible. - virtual void AdjustOutputVolumeToAudibleLevel() = 0; - - // Gets the default level in the range 0%-100% at which the output device - // should be muted. - virtual int GetOutputDefaultVolumeMuteLevel() = 0; - - // Gets the MD icon to use for the active output device. - virtual const gfx::VectorIcon& GetActiveOutputDeviceVectorIcon() = 0; - - // Returns the volume level of the output device in the range 0%-100%. - virtual int GetOutputVolumeLevel() = 0; - - // Returns true if the device has alternative inputs or outputs. - virtual bool HasAlternativeSources() = 0; - - // Returns whether the output volume is muted. - virtual bool IsOutputAudioMuted() = 0; - - // Sets the mute state of the output device. - virtual void SetOutputAudioIsMuted(bool is_muted) = 0; - - // Sets the volume level of the output device in the range 0%-100% - virtual void SetOutputVolumeLevel(int level) = 0; - - // Sets the internal speaker's channel mode. - virtual void SetInternalSpeakerChannelMode(AudioChannelMode mode) = 0; - - // If necessary, sets the starting point for re-discovering the active HDMI - // output device caused by device entering/exiting docking mode, HDMI display - // changing resolution, or chromeos device suspend/resume. If - // |force_rediscovering| is true, it will force to set the starting point for - // re-discovering the active HDMI output device again if it has been in the - // middle of rediscovering the HDMI active output device. - virtual void SetActiveHDMIOutoutRediscoveringIfNecessary( - bool force_rediscovering) = 0; -}; - -} // namespace system -} // namespace ash - -#endif // ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_H_
diff --git a/ash/system/audio/tray_audio_delegate_chromeos.cc b/ash/system/audio/tray_audio_delegate_chromeos.cc deleted file mode 100644 index 472b806..0000000 --- a/ash/system/audio/tray_audio_delegate_chromeos.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/audio/tray_audio_delegate_chromeos.h" - -#include "ash/resources/vector_icons/vector_icons.h" -#include "chromeos/audio/cras_audio_handler.h" -#include "ui/gfx/paint_vector_icon.h" - -using chromeos::CrasAudioHandler; - -namespace ash { -namespace system { - -void TrayAudioDelegateChromeOs::AdjustOutputVolumeToAudibleLevel() { - CrasAudioHandler::Get()->AdjustOutputVolumeToAudibleLevel(); -} - -int TrayAudioDelegateChromeOs::GetOutputDefaultVolumeMuteLevel() { - return CrasAudioHandler::Get()->GetOutputDefaultVolumeMuteThreshold(); -} - -int TrayAudioDelegateChromeOs::GetOutputVolumeLevel() { - return CrasAudioHandler::Get()->GetOutputVolumePercent(); -} - -const gfx::VectorIcon& -TrayAudioDelegateChromeOs::GetActiveOutputDeviceVectorIcon() { - chromeos::AudioDevice device; - if (CrasAudioHandler::Get()->GetPrimaryActiveOutputDevice(&device)) { - if (device.type == chromeos::AUDIO_TYPE_HEADPHONE) - return kSystemMenuHeadsetIcon; - if (device.type == chromeos::AUDIO_TYPE_USB) - return kSystemMenuUsbIcon; - if (device.type == chromeos::AUDIO_TYPE_BLUETOOTH) - return kSystemMenuBluetoothIcon; - if (device.type == chromeos::AUDIO_TYPE_HDMI) - return kSystemMenuHdmiIcon; - } - return gfx::kNoneIcon; -} - -bool TrayAudioDelegateChromeOs::HasAlternativeSources() { - CrasAudioHandler* audio_handler = CrasAudioHandler::Get(); - return (audio_handler->has_alternative_output() || - audio_handler->has_alternative_input()); -} - -bool TrayAudioDelegateChromeOs::IsOutputAudioMuted() { - return CrasAudioHandler::Get()->IsOutputMuted(); -} - -void TrayAudioDelegateChromeOs::SetOutputAudioIsMuted(bool is_muted) { - CrasAudioHandler::Get()->SetOutputMute(is_muted); -} - -void TrayAudioDelegateChromeOs::SetOutputVolumeLevel(int level) { - CrasAudioHandler::Get()->SetOutputVolumePercent(level); -} - -void TrayAudioDelegateChromeOs::SetInternalSpeakerChannelMode( - AudioChannelMode mode) { - CrasAudioHandler::Get()->SwapInternalSpeakerLeftRightChannel( - mode == LEFT_RIGHT_SWAPPED); -} - -void TrayAudioDelegateChromeOs::SetActiveHDMIOutoutRediscoveringIfNecessary( - bool force_rediscovering) { - CrasAudioHandler::Get()->SetActiveHDMIOutoutRediscoveringIfNecessary( - force_rediscovering); -} - -} // namespace system -} // namespace ash
diff --git a/ash/system/audio/tray_audio_delegate_chromeos.h b/ash/system/audio/tray_audio_delegate_chromeos.h deleted file mode 100644 index a3fc065e..0000000 --- a/ash/system/audio/tray_audio_delegate_chromeos.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_ -#define ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_ - -#include "ash/ash_export.h" -#include "ash/system/audio/tray_audio_delegate.h" - -namespace ash { -namespace system { - -class ASH_EXPORT TrayAudioDelegateChromeOs : public TrayAudioDelegate { - public: - ~TrayAudioDelegateChromeOs() override {} - - // Overridden from TrayAudioDelegate. - void AdjustOutputVolumeToAudibleLevel() override; - int GetOutputDefaultVolumeMuteLevel() override; - int GetOutputVolumeLevel() override; - const gfx::VectorIcon& GetActiveOutputDeviceVectorIcon() override; - bool HasAlternativeSources() override; - bool IsOutputAudioMuted() override; - void SetOutputAudioIsMuted(bool is_muted) override; - void SetOutputVolumeLevel(int level) override; - void SetInternalSpeakerChannelMode(AudioChannelMode mode) override; - void SetActiveHDMIOutoutRediscoveringIfNecessary( - bool force_rediscovering) override; -}; - -} // namespace system -} // namespace ash - -#endif // ASH_SYSTEM_AUDIO_TRAY_AUDIO_DELEGATE_CHROMEOS_H_
diff --git a/ash/system/audio/tray_audio_unittest.cc b/ash/system/audio/tray_audio_unittest.cc deleted file mode 100644 index 16d7e89..0000000 --- a/ash/system/audio/tray_audio_unittest.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/audio/tray_audio.h" - -#include "ash/system/tray/system_tray.h" -#include "ash/test/ash_test.h" - -namespace ash { - -using TrayAudioTest = AshTest; - -// Tests that the volume popup view can be explicitly shown. -TEST_F(TrayAudioTest, ShowPopUpVolumeView) { - TrayAudio* tray_audio = GetPrimarySystemTray()->GetTrayAudio(); - ASSERT_TRUE(tray_audio); - - // The volume popup is not visible initially. - EXPECT_FALSE(tray_audio->volume_view_for_testing()); - EXPECT_FALSE(tray_audio->pop_up_volume_view_for_testing()); - - // Simulate ARC asking to show the volume view. - TrayAudio::ShowPopUpVolumeView(); - - // Volume view is now visible. - EXPECT_TRUE(tray_audio->volume_view_for_testing()); - EXPECT_TRUE(tray_audio->pop_up_volume_view_for_testing()); -} - -} // namespace ash
diff --git a/ash/system/audio/volume_view.cc b/ash/system/audio/volume_view.cc deleted file mode 100644 index dd755925..0000000 --- a/ash/system/audio/volume_view.cc +++ /dev/null
@@ -1,248 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/audio/volume_view.h" - -#include <algorithm> - -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/audio/tray_audio_delegate.h" -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_container.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icon_types.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/custom_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/slider.h" -#include "ui/views/layout/fill_layout.h" - -namespace { - -const gfx::VectorIcon* const kVolumeLevelIcons[] = { - &ash::kSystemMenuVolumeMuteIcon, // Muted. - &ash::kSystemMenuVolumeLowIcon, // Low volume. - &ash::kSystemMenuVolumeMediumIcon, // Medium volume. - &ash::kSystemMenuVolumeHighIcon, // High volume. - &ash::kSystemMenuVolumeHighIcon, // Full volume. -}; - -} // namespace - -namespace ash { -namespace tray { - -class VolumeButton : public ButtonListenerActionableView { - public: - VolumeButton(SystemTrayItem* owner, - views::ButtonListener* listener, - system::TrayAudioDelegate* audio_delegate) - : ButtonListenerActionableView(owner, - TrayPopupInkDropStyle::HOST_CENTERED, - listener), - audio_delegate_(audio_delegate), - image_(TrayPopupUtils::CreateMainImageView()), - image_index_(-1) { - TrayPopupUtils::ConfigureContainer(TriView::Container::START, this); - AddChildView(image_); - SetInkDropMode(InkDropMode::ON); - Update(); - - set_notify_enter_exit_on_child(true); - } - - ~VolumeButton() override {} - - void Update() { - float level = - static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f; - int volume_levels = arraysize(kVolumeLevelIcons) - 1; - int image_index = - audio_delegate_->IsOutputAudioMuted() - ? 0 - : (level == 1.0 ? volume_levels - : std::max(1, static_cast<int>(std::ceil( - level * (volume_levels - 1))))); - gfx::ImageSkia image_skia = - gfx::CreateVectorIcon(*kVolumeLevelIcons[image_index], kMenuIconColor); - image_->SetImage(&image_skia); - image_index_ = image_index; - } - - private: - // views::View: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->SetName( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VOLUME_MUTE)); - node_data->role = ui::AX_ROLE_TOGGLE_BUTTON; - if (audio_delegate_->IsOutputAudioMuted()) - node_data->AddStateFlag(ui::AX_STATE_PRESSED); - } - - system::TrayAudioDelegate* audio_delegate_; - views::ImageView* image_; - int image_index_; - - DISALLOW_COPY_AND_ASSIGN(VolumeButton); -}; - -VolumeView::VolumeView(SystemTrayItem* owner, - system::TrayAudioDelegate* audio_delegate, - bool is_default_view) - : owner_(owner), - tri_view_(TrayPopupUtils::CreateMultiTargetRowView()), - audio_delegate_(audio_delegate), - more_button_(nullptr), - icon_(nullptr), - slider_(nullptr), - device_type_(nullptr), - is_default_view_(is_default_view) { - SetLayoutManager(new views::FillLayout); - AddChildView(tri_view_); - - icon_ = new VolumeButton(owner, this, audio_delegate_); - tri_view_->AddView(TriView::Container::START, icon_); - - slider_ = TrayPopupUtils::CreateSlider(this); - slider_->SetValue( - static_cast<float>(audio_delegate_->GetOutputVolumeLevel()) / 100.0f); - slider_->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VOLUME)); - tri_view_->AddView(TriView::Container::CENTER, slider_); - - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); - - if (!is_default_view_) { - tri_view_->SetContainerVisible(TriView::Container::END, false); - Update(); - return; - } - - more_button_ = new ButtonListenerActionableView( - owner_, TrayPopupInkDropStyle::INSET_BOUNDS, this); - TrayPopupUtils::ConfigureContainer(TriView::Container::END, more_button_); - - more_button_->SetInkDropMode(views::InkDropHostView::InkDropMode::ON); - more_button_->SetBorder(views::CreateEmptyBorder(gfx::Insets( - 0, kTrayPopupButtonEndMargin))); - tri_view_->AddView(TriView::Container::END, more_button_); - - device_type_ = TrayPopupUtils::CreateMoreImageView(); - device_type_->SetVisible(false); - more_button_->AddChildView(device_type_); - - more_button_->AddChildView(TrayPopupUtils::CreateMoreImageView()); - - Update(); -} - -VolumeView::~VolumeView() {} - -void VolumeView::Update() { - icon_->Update(); - slider_->UpdateState(!audio_delegate_->IsOutputAudioMuted()); - UpdateDeviceTypeAndMore(); - Layout(); -} - -void VolumeView::SetVolumeLevel(float percent) { - // Update volume level to the current audio level. - Update(); - - // Slider's value is in finer granularity than audio volume level(0.01), - // there will be a small discrepancy between slider's value and volume level - // on audio side. To avoid the jittering in slider UI, do not set change - // slider value if the change is less than 1%. - if (std::abs(percent - slider_->value()) < 0.01) - return; - slider_->SetValue(percent); - // It is possible that the volume was (un)muted, but the actual volume level - // did not change. In that case, setting the value of the slider won't - // trigger an update. So explicitly trigger an update. - Update(); - slider_->set_enable_accessibility_events(true); -} - -void VolumeView::UpdateDeviceTypeAndMore() { - bool show_more = is_default_view_ && audio_delegate_->HasAlternativeSources(); - - if (!show_more) - return; - - const gfx::VectorIcon& device_icon = - audio_delegate_->GetActiveOutputDeviceVectorIcon(); - const bool target_visibility = !device_icon.is_empty(); - if (target_visibility) - device_type_->SetImage(gfx::CreateVectorIcon(device_icon, kMenuIconColor)); - if (device_type_->visible() != target_visibility) { - device_type_->SetVisible(target_visibility); - device_type_->InvalidateLayout(); - } -} - -void VolumeView::HandleVolumeUp(int level) { - audio_delegate_->SetOutputVolumeLevel(level); - if (audio_delegate_->IsOutputAudioMuted() && - level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { - audio_delegate_->SetOutputAudioIsMuted(false); - } -} - -void VolumeView::HandleVolumeDown(int level) { - audio_delegate_->SetOutputVolumeLevel(level); - if (!audio_delegate_->IsOutputAudioMuted() && - level <= audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { - audio_delegate_->SetOutputAudioIsMuted(true); - } else if (audio_delegate_->IsOutputAudioMuted() && - level > audio_delegate_->GetOutputDefaultVolumeMuteLevel()) { - audio_delegate_->SetOutputAudioIsMuted(false); - } -} - -void VolumeView::ButtonPressed(views::Button* sender, const ui::Event& event) { - if (sender == icon_) { - bool mute_on = !audio_delegate_->IsOutputAudioMuted(); - audio_delegate_->SetOutputAudioIsMuted(mute_on); - if (!mute_on) - audio_delegate_->AdjustOutputVolumeToAudibleLevel(); - icon_->Update(); - } else if (sender == more_button_) { - owner_->TransitionDetailedView(); - } else { - NOTREACHED() << "Unexpected sender=" << sender->GetClassName() << "."; - } -} - -void VolumeView::SliderValueChanged(views::Slider* sender, - float value, - float old_value, - views::SliderChangeReason reason) { - if (reason == views::VALUE_CHANGED_BY_USER) { - int new_volume = static_cast<int>(value * 100); - int current_volume = audio_delegate_->GetOutputVolumeLevel(); - if (new_volume == current_volume) - return; - WmShell::Get()->RecordUserMetricsAction( - is_default_view_ ? UMA_STATUS_AREA_CHANGED_VOLUME_MENU - : UMA_STATUS_AREA_CHANGED_VOLUME_POPUP); - if (new_volume > current_volume) - HandleVolumeUp(new_volume); - else - HandleVolumeDown(new_volume); - } - icon_->Update(); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/audio/volume_view.h b/ash/system/audio/volume_view.h deleted file mode 100644 index 60a6013..0000000 --- a/ash/system/audio/volume_view.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_AUDIO_VOLUME_VIEW_H_ -#define ASH_SYSTEM_AUDIO_VOLUME_VIEW_H_ - -#include "base/macros.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/slider.h" -#include "ui/views/view.h" - -namespace views { -class CustomButton; -class ImageView; -} - -namespace ash { -class SystemTrayItem; -class TriView; - -namespace system { -class TrayAudioDelegate; -} - -namespace tray { -class VolumeButton; - -class VolumeView : public views::View, - public views::SliderListener, - public views::ButtonListener { - public: - VolumeView(SystemTrayItem* owner, - system::TrayAudioDelegate* audio_delegate, - bool is_default_view); - - ~VolumeView() override; - - void Update(); - - // Sets volume level on slider_, |percent| is ranged from [0.00] to [1.00]. - void SetVolumeLevel(float percent); - - private: - // Updates device_type_ icon and more_ button. - void UpdateDeviceTypeAndMore(); - void HandleVolumeUp(int percent); - void HandleVolumeDown(int percent); - - // SliderListener: - void SliderValueChanged(views::Slider* sender, - float value, - float old_value, - views::SliderChangeReason reason) override; - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - SystemTrayItem* owner_; - // The only immediate child view of |this|. All other view elements are added - // to the |tri_view_| to handle layout. - TriView* tri_view_; - system::TrayAudioDelegate* audio_delegate_; - views::CustomButton* more_button_; - VolumeButton* icon_; - views::Slider* slider_; - views::ImageView* device_type_; - bool is_default_view_; - - DISALLOW_COPY_AND_ASSIGN(VolumeView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_AUDIO_VOLUME_VIEW_H_
diff --git a/ash/system/bluetooth/bluetooth_notification_controller.cc b/ash/system/bluetooth/bluetooth_notification_controller.cc deleted file mode 100644 index 0b240e2a..0000000 --- a/ash/system/bluetooth/bluetooth_notification_controller.cc +++ /dev/null
@@ -1,334 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/bluetooth/bluetooth_notification_controller.h" - -#include <memory> -#include <utility> - -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" -#include "base/bind.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "device/bluetooth/bluetooth_adapter_factory.h" -#include "device/bluetooth/bluetooth_device.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/message_center/notification_types.h" - -using device::BluetoothAdapter; -using device::BluetoothAdapterFactory; -using device::BluetoothDevice; -using message_center::Notification; - -namespace { - -// Identifier for the discoverable notification. -const char kBluetoothDeviceDiscoverableNotificationId[] = - "chrome://settings/bluetooth/discoverable"; - -// Identifier for the pairing notification; the Bluetooth code ensures we -// only receive one pairing request at a time, so a single id is sufficient and -// means we "update" one notification if not handled rather than continually -// bugging the user. -const char kBluetoothDevicePairingNotificationId[] = - "chrome://settings/bluetooth/pairing"; - -// Identifier for the notification that a device has been paired with the -// system. -const char kBluetoothDevicePairedNotificationId[] = - "chrome://settings/bluetooth/paired"; - -// The BluetoothPairingNotificationDelegate handles user interaction with the -// pairing notification and sending the confirmation, rejection or cancellation -// back to the underlying device. -class BluetoothPairingNotificationDelegate - : public message_center::NotificationDelegate { - public: - BluetoothPairingNotificationDelegate(scoped_refptr<BluetoothAdapter> adapter, - const std::string& address); - - protected: - ~BluetoothPairingNotificationDelegate() override; - - // message_center::NotificationDelegate overrides. - void Close(bool by_user) override; - void ButtonClick(int button_index) override; - - private: - // Buttons that appear in notifications. - enum Button { BUTTON_ACCEPT, BUTTON_REJECT }; - - // Reference to the underlying Bluetooth Adapter, holding onto this - // reference ensures the adapter object doesn't go out of scope while we have - // a pending request and user interaction. - scoped_refptr<BluetoothAdapter> adapter_; - - // Address of the device being paired. - const std::string address_; - - DISALLOW_COPY_AND_ASSIGN(BluetoothPairingNotificationDelegate); -}; - -BluetoothPairingNotificationDelegate::BluetoothPairingNotificationDelegate( - scoped_refptr<BluetoothAdapter> adapter, - const std::string& address) - : adapter_(adapter), address_(address) {} - -BluetoothPairingNotificationDelegate::~BluetoothPairingNotificationDelegate() {} - -void BluetoothPairingNotificationDelegate::Close(bool by_user) { - VLOG(1) << "Pairing notification closed. by_user = " << by_user; - // Ignore notification closes generated as a result of pairing completion. - if (!by_user) - return; - - // Cancel the pairing of the device, if the object still exists. - BluetoothDevice* device = adapter_->GetDevice(address_); - if (device) - device->CancelPairing(); -} - -void BluetoothPairingNotificationDelegate::ButtonClick(int button_index) { - VLOG(1) << "Pairing notification, button click: " << button_index; - // If the device object still exists, send the appropriate response either - // confirming or rejecting the pairing. - BluetoothDevice* device = adapter_->GetDevice(address_); - if (device) { - switch (button_index) { - case BUTTON_ACCEPT: - device->ConfirmPairing(); - break; - case BUTTON_REJECT: - device->RejectPairing(); - break; - } - } - - // In any case, remove this pairing notification. - message_center::MessageCenter::Get()->RemoveNotification( - kBluetoothDevicePairingNotificationId, false /* by_user */); -} - -} // namespace - -namespace ash { - -BluetoothNotificationController::BluetoothNotificationController() - : weak_ptr_factory_(this) { - BluetoothAdapterFactory::GetAdapter( - base::Bind(&BluetoothNotificationController::OnGetAdapter, - weak_ptr_factory_.GetWeakPtr())); -} - -BluetoothNotificationController::~BluetoothNotificationController() { - if (adapter_.get()) { - adapter_->RemoveObserver(this); - adapter_->RemovePairingDelegate(this); - adapter_ = NULL; - } -} - -void BluetoothNotificationController::AdapterDiscoverableChanged( - BluetoothAdapter* adapter, - bool discoverable) { - if (discoverable) { - NotifyAdapterDiscoverable(); - } else { - // Clear any previous discoverable notification. - message_center::MessageCenter::Get()->RemoveNotification( - kBluetoothDeviceDiscoverableNotificationId, false /* by_user */); - } -} - -void BluetoothNotificationController::DeviceAdded(BluetoothAdapter* adapter, - BluetoothDevice* device) { - // Add the new device to the list of currently paired devices; it doesn't - // receive a notification since it's assumed it was previously notified. - if (device->IsPaired()) - paired_devices_.insert(device->GetAddress()); -} - -void BluetoothNotificationController::DeviceChanged(BluetoothAdapter* adapter, - BluetoothDevice* device) { - // If the device is already in the list of paired devices, then don't - // notify. - if (paired_devices_.find(device->GetAddress()) != paired_devices_.end()) - return; - - // Otherwise if it's marked as paired then it must be newly paired, so - // notify the user about that. - if (device->IsPaired()) { - paired_devices_.insert(device->GetAddress()); - NotifyPairedDevice(device); - } -} - -void BluetoothNotificationController::DeviceRemoved(BluetoothAdapter* adapter, - BluetoothDevice* device) { - paired_devices_.erase(device->GetAddress()); -} - -void BluetoothNotificationController::RequestPinCode(BluetoothDevice* device) { - // Cannot provide keyboard entry in a notification; these devices (old car - // audio systems for the most part) will need pairing to be initiated from - // the Chromebook. - device->CancelPairing(); -} - -void BluetoothNotificationController::RequestPasskey(BluetoothDevice* device) { - // Cannot provide keyboard entry in a notification; fortunately the spec - // doesn't allow for this to be an option when we're receiving the pairing - // request anyway. - device->CancelPairing(); -} - -void BluetoothNotificationController::DisplayPinCode( - BluetoothDevice* device, - const std::string& pincode) { - base::string16 message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PINCODE, - device->GetNameForDisplay(), base::UTF8ToUTF16(pincode)); - - NotifyPairing(device, message, false); -} - -void BluetoothNotificationController::DisplayPasskey(BluetoothDevice* device, - uint32_t passkey) { - base::string16 message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BLUETOOTH_DISPLAY_PASSKEY, - device->GetNameForDisplay(), - base::UTF8ToUTF16(base::StringPrintf("%06i", passkey))); - - NotifyPairing(device, message, false); -} - -void BluetoothNotificationController::KeysEntered(BluetoothDevice* device, - uint32_t entered) { - // Ignored since we don't have CSS in the notification to update. -} - -void BluetoothNotificationController::ConfirmPasskey(BluetoothDevice* device, - uint32_t passkey) { - base::string16 message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BLUETOOTH_CONFIRM_PASSKEY, - device->GetNameForDisplay(), - base::UTF8ToUTF16(base::StringPrintf("%06i", passkey))); - - NotifyPairing(device, message, true); -} - -void BluetoothNotificationController::AuthorizePairing( - BluetoothDevice* device) { - base::string16 message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BLUETOOTH_AUTHORIZE_PAIRING, - device->GetNameForDisplay()); - - NotifyPairing(device, message, true); -} - -void BluetoothNotificationController::OnGetAdapter( - scoped_refptr<BluetoothAdapter> adapter) { - DCHECK(!adapter_.get()); - adapter_ = adapter; - adapter_->AddObserver(this); - adapter_->AddPairingDelegate(this, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); - - // Notify a user if the adapter is already in the discoverable state. - if (adapter_->IsDiscoverable()) - NotifyAdapterDiscoverable(); - - // Build a list of the currently paired devices; these don't receive - // notifications since it's assumed they were previously notified. - BluetoothAdapter::DeviceList devices = adapter_->GetDevices(); - for (BluetoothAdapter::DeviceList::const_iterator iter = devices.begin(); - iter != devices.end(); ++iter) { - const BluetoothDevice* device = *iter; - if (device->IsPaired()) - paired_devices_.insert(device->GetAddress()); - } -} - -void BluetoothNotificationController::NotifyAdapterDiscoverable() { - message_center::RichNotificationData optional; - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, - kBluetoothDeviceDiscoverableNotificationId, base::string16() /* title */, - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERABLE, - base::UTF8ToUTF16(adapter_->GetName()), - base::UTF8ToUTF16(adapter_->GetAddress())), - bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), - base::string16() /* display source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierBluetooth), - optional, NULL)); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -void BluetoothNotificationController::NotifyPairing( - BluetoothDevice* device, - const base::string16& message, - bool with_buttons) { - message_center::RichNotificationData optional; - if (with_buttons) { - optional.buttons.push_back(message_center::ButtonInfo( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_ACCEPT))); - optional.buttons.push_back(message_center::ButtonInfo( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_REJECT))); - } - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, - kBluetoothDevicePairingNotificationId, base::string16() /* title */, - message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), - base::string16() /* display source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierBluetooth), - optional, new BluetoothPairingNotificationDelegate( - adapter_, device->GetAddress()))); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -void BluetoothNotificationController::NotifyPairedDevice( - BluetoothDevice* device) { - // Remove the currently presented pairing notification; since only one - // pairing request is queued at a time, this is guaranteed to be the device - // that just became paired. - message_center::MessageCenter::Get()->RemoveNotification( - kBluetoothDevicePairingNotificationId, false /* by_user */); - - message_center::RichNotificationData optional; - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, - kBluetoothDevicePairedNotificationId, base::string16() /* title */, - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED, - device->GetNameForDisplay()), - bundle.GetImageNamed(IDR_AURA_NOTIFICATION_BLUETOOTH), - base::string16() /* display source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierBluetooth), - optional, NULL)); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -} // namespace ash
diff --git a/ash/system/bluetooth/bluetooth_notification_controller.h b/ash/system/bluetooth/bluetooth_notification_controller.h deleted file mode 100644 index 63f7ef5..0000000 --- a/ash/system/bluetooth/bluetooth_notification_controller.h +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_ -#define ASH_SYSTEM_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_ - -#include <stdint.h> - -#include <set> -#include <string> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/strings/string16.h" -#include "device/bluetooth/bluetooth_adapter.h" -#include "device/bluetooth/bluetooth_device.h" - -namespace ash { - -// The BluetoothNotificationController receives incoming pairing requests from -// the BluetoothAdapter, and notifications of changes to the adapter state and -// set of paired devices. It presents incoming pairing requests in the form of -// rich notifications that the user can interact with to approve the request. -class ASH_EXPORT BluetoothNotificationController - : public device::BluetoothAdapter::Observer, - public device::BluetoothDevice::PairingDelegate { - public: - BluetoothNotificationController(); - ~BluetoothNotificationController() override; - - // device::BluetoothAdapter::Observer override. - void AdapterDiscoverableChanged(device::BluetoothAdapter* adapter, - bool discoverable) override; - void DeviceAdded(device::BluetoothAdapter* adapter, - device::BluetoothDevice* device) override; - void DeviceChanged(device::BluetoothAdapter* adapter, - device::BluetoothDevice* device) override; - void DeviceRemoved(device::BluetoothAdapter* adapter, - device::BluetoothDevice* device) override; - - // device::BluetoothDevice::PairingDelegate override. - void RequestPinCode(device::BluetoothDevice* device) override; - void RequestPasskey(device::BluetoothDevice* device) override; - void DisplayPinCode(device::BluetoothDevice* device, - const std::string& pincode) override; - void DisplayPasskey(device::BluetoothDevice* device, - uint32_t passkey) override; - void KeysEntered(device::BluetoothDevice* device, uint32_t entered) override; - void ConfirmPasskey(device::BluetoothDevice* device, - uint32_t passkey) override; - void AuthorizePairing(device::BluetoothDevice* device) override; - - private: - // Internal method called by BluetoothAdapterFactory to provide the adapter - // object. - void OnGetAdapter(scoped_refptr<device::BluetoothAdapter> adapter); - - // Presents a notification to the user when the adapter becomes discoverable - // to other nearby devices. - void NotifyAdapterDiscoverable(); - - // Presents a notification to the user that a device |device| is making a - // pairing request. The exact message to display is given in |message| and - // should include all relevant instructions, if |with_buttons| is true then - // the notification will have Accept and Reject buttons, if false only the - // usual cancel/dismiss button will be present on the notification. - void NotifyPairing(device::BluetoothDevice* device, - const base::string16& message, - bool with_buttons); - - // Clears any shown pairing notification now that the device has been paired. - void NotifyPairedDevice(device::BluetoothDevice* device); - - // Reference to the underlying BluetoothAdapter object, holding this reference - // ensures we stay around as the pairing delegate for that adapter. - scoped_refptr<device::BluetoothAdapter> adapter_; - - // Set of currently paired devices, stored by Bluetooth address, used to - // filter out property changes for devices that were previously paired. - std::set<std::string> paired_devices_; - - // Note: This should remain the last member so it'll be destroyed and - // invalidate its weak pointers before any other members are destroyed. - base::WeakPtrFactory<BluetoothNotificationController> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(BluetoothNotificationController); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_BLUETOOTH_BLUETOOTH_NOTIFICATION_CONTROLLER_H_
diff --git a/ash/system/bluetooth/bluetooth_observer.h b/ash/system/bluetooth/bluetooth_observer.h deleted file mode 100644 index 1c1bf4f..0000000 --- a/ash/system/bluetooth/bluetooth_observer.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_BLUETOOTH_BLUETOOTH_OBSERVER_H_ -#define ASH_SYSTEM_BLUETOOTH_BLUETOOTH_OBSERVER_H_ - -namespace ash { - -class BluetoothObserver { - public: - virtual ~BluetoothObserver() {} - - virtual void OnBluetoothRefresh() = 0; - virtual void OnBluetoothDiscoveringChanged() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_BLUETOOTH_BLUETOOTH_OBSERVER_H_
diff --git a/ash/system/bluetooth/tray_bluetooth.cc b/ash/system/bluetooth/tray_bluetooth.cc deleted file mode 100644 index 8d8889b..0000000 --- a/ash/system/bluetooth/tray_bluetooth.cc +++ /dev/null
@@ -1,632 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/bluetooth/tray_bluetooth.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/throbber_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_item_more.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "device/bluetooth/bluetooth_common.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/views/controls/button/toggle_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/progress_bar.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" - -namespace ash { -namespace tray { -namespace { - -// Updates bluetooth device |device| in the |list|. If it is new, append to the -// end of the |list|; otherwise, keep it at the same place, but update the data -// with new device info provided by |device|. -void UpdateBluetoothDeviceListHelper(BluetoothDeviceList* list, - const BluetoothDeviceInfo& device) { - for (BluetoothDeviceList::iterator it = list->begin(); it != list->end(); - ++it) { - if ((*it).address == device.address) { - *it = device; - return; - } - } - - list->push_back(device); -} - -// Removes the obsolete BluetoothDevices from |list|, if they are not in the -// |new_list|. -void RemoveObsoleteBluetoothDevicesFromList( - BluetoothDeviceList* list, - const std::set<std::string>& new_list) { - for (BluetoothDeviceList::iterator it = list->begin(); it != list->end(); - ++it) { - if (new_list.find((*it).address) == new_list.end()) { - it = list->erase(it); - if (it == list->end()) - return; - } - } -} - -// Returns corresponding device type icons for given Bluetooth device types and -// connection states. -const gfx::VectorIcon& GetBluetoothDeviceIcon( - device::BluetoothDeviceType device_type, - bool connected) { - switch (device_type) { - case device::BluetoothDeviceType::COMPUTER: - return ash::kSystemMenuComputerIcon; - case device::BluetoothDeviceType::PHONE: - return ash::kSystemMenuPhoneIcon; - case device::BluetoothDeviceType::AUDIO: - case device::BluetoothDeviceType::CAR_AUDIO: - return ash::kSystemMenuHeadsetIcon; - case device::BluetoothDeviceType::VIDEO: - return ash::kSystemMenuVideocamIcon; - case device::BluetoothDeviceType::JOYSTICK: - case device::BluetoothDeviceType::GAMEPAD: - return ash::kSystemMenuGamepadIcon; - case device::BluetoothDeviceType::KEYBOARD: - case device::BluetoothDeviceType::KEYBOARD_MOUSE_COMBO: - return ash::kSystemMenuKeyboardIcon; - case device::BluetoothDeviceType::TABLET: - return ash::kSystemMenuTabletIcon; - case device::BluetoothDeviceType::MOUSE: - return ash::kSystemMenuMouseIcon; - case device::BluetoothDeviceType::MODEM: - case device::BluetoothDeviceType::PERIPHERAL: - return ash::kSystemMenuBluetoothIcon; - case device::BluetoothDeviceType::UNKNOWN: - LOG(WARNING) << "Unknown device type icon for Bluetooth was requested."; - break; - } - return connected ? ash::kSystemMenuBluetoothConnectedIcon - : ash::kSystemMenuBluetoothIcon; -} - -const int kDisabledPanelLabelBaselineY = 20; - -} // namespace - -class BluetoothDefaultView : public TrayItemMore { - public: - explicit BluetoothDefaultView(SystemTrayItem* owner) : TrayItemMore(owner) {} - ~BluetoothDefaultView() override {} - - void Update() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - const bool enabled = delegate->GetBluetoothEnabled(); - if (delegate->GetBluetoothAvailable()) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const base::string16 label = rb.GetLocalizedString( - enabled ? IDS_ASH_STATUS_TRAY_BLUETOOTH_ENABLED - : IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED); - SetLabel(label); - SetAccessibleName(label); - SetVisible(true); - } else { - SetVisible(false); - } - UpdateStyle(); - } - - protected: - // TrayItemMore: - std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const override { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - std::unique_ptr<TrayPopupItemStyle> style = - TrayItemMore::HandleCreateStyle(); - style->set_color_style( - delegate->GetBluetoothEnabled() - ? TrayPopupItemStyle::ColorStyle::ACTIVE - : delegate->GetBluetoothAvailable() - ? TrayPopupItemStyle::ColorStyle::INACTIVE - : TrayPopupItemStyle::ColorStyle::DISABLED); - - return style; - } - - void UpdateStyle() override { - TrayItemMore::UpdateStyle(); - std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); - SetImage(gfx::CreateVectorIcon(GetCurrentIcon(), style->GetIconColor())); - } - - private: - const gfx::VectorIcon& GetCurrentIcon() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (!delegate->GetBluetoothEnabled()) - return kSystemMenuBluetoothDisabledIcon; - - bool has_connected_device = false; - BluetoothDeviceList list; - delegate->GetAvailableBluetoothDevices(&list); - for (size_t i = 0; i < list.size(); ++i) { - if (list[i].connected) { - has_connected_device = true; - break; - } - } - return has_connected_device ? kSystemMenuBluetoothConnectedIcon - : kSystemMenuBluetoothIcon; - } - - DISALLOW_COPY_AND_ASSIGN(BluetoothDefaultView); -}; - -class BluetoothDetailedView : public TrayDetailsView { - public: - BluetoothDetailedView(SystemTrayItem* owner, LoginStatus login) - : TrayDetailsView(owner), - login_(login), - toggle_(nullptr), - settings_(nullptr), - disabled_panel_(nullptr) { - CreateItems(); - } - - ~BluetoothDetailedView() override { - // Stop discovering bluetooth devices when exiting BT detailed view. - BluetoothStopDiscovering(); - } - - void Update() { - BluetoothStartDiscovering(); - UpdateBluetoothDeviceList(); - - // Update UI. - UpdateDeviceScrollList(); - UpdateHeaderEntry(); - Layout(); - } - - private: - void CreateItems() { - CreateScrollableList(); - CreateTitleRow(IDS_ASH_STATUS_TRAY_BLUETOOTH); - } - - void BluetoothStartDiscovering() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (delegate->GetBluetoothDiscovering()) { - ShowLoadingIndicator(); - return; - } - HideLoadingIndicator(); - if (delegate->GetBluetoothEnabled()) - delegate->BluetoothStartDiscovering(); - } - - void BluetoothStopDiscovering() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (delegate && delegate->GetBluetoothDiscovering()) { - delegate->BluetoothStopDiscovering(); - HideLoadingIndicator(); - } - } - - void UpdateBluetoothDeviceList() { - std::set<std::string> new_connecting_devices; - std::set<std::string> new_connected_devices; - std::set<std::string> new_paired_not_connected_devices; - std::set<std::string> new_discovered_not_paired_devices; - - BluetoothDeviceList list; - WmShell::Get()->system_tray_delegate()->GetAvailableBluetoothDevices(&list); - for (size_t i = 0; i < list.size(); ++i) { - if (list[i].connecting) { - new_connecting_devices.insert(list[i].address); - UpdateBluetoothDeviceListHelper(&connecting_devices_, list[i]); - } else if (list[i].connected && list[i].paired) { - new_connected_devices.insert(list[i].address); - UpdateBluetoothDeviceListHelper(&connected_devices_, list[i]); - } else if (list[i].paired) { - new_paired_not_connected_devices.insert(list[i].address); - UpdateBluetoothDeviceListHelper(&paired_not_connected_devices_, - list[i]); - } else { - new_discovered_not_paired_devices.insert(list[i].address); - UpdateBluetoothDeviceListHelper(&discovered_not_paired_devices_, - list[i]); - } - } - RemoveObsoleteBluetoothDevicesFromList(&connecting_devices_, - new_connecting_devices); - RemoveObsoleteBluetoothDevicesFromList(&connected_devices_, - new_connected_devices); - RemoveObsoleteBluetoothDevicesFromList(&paired_not_connected_devices_, - new_paired_not_connected_devices); - RemoveObsoleteBluetoothDevicesFromList(&discovered_not_paired_devices_, - new_discovered_not_paired_devices); - } - - void UpdateHeaderEntry() { - bool is_bluetooth_enabled = - WmShell::Get()->system_tray_delegate()->GetBluetoothEnabled(); - if (toggle_) - toggle_->SetIsOn(is_bluetooth_enabled, false); - } - - void UpdateDeviceScrollList() { - device_map_.clear(); - scroll_content()->RemoveAllChildViews(true); - - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - bool bluetooth_enabled = delegate->GetBluetoothEnabled(); - bool bluetooth_available = delegate->GetBluetoothAvailable(); - - // If Bluetooth is disabled, show a panel which only indicates that it is - // disabled, instead of the scroller with Bluetooth devices. - if (bluetooth_enabled) { - HideDisabledPanel(); - } else { - ShowDisabledPanel(); - return; - } - - // Add paired devices (and their section header in MD) in the list. - size_t num_paired_devices = connected_devices_.size() + - connecting_devices_.size() + - paired_not_connected_devices_.size(); - if (num_paired_devices > 0) { - AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES); - AppendSameTypeDevicesToScrollList(connected_devices_, true, true, - bluetooth_enabled); - AppendSameTypeDevicesToScrollList(connecting_devices_, true, false, - bluetooth_enabled); - AppendSameTypeDevicesToScrollList(paired_not_connected_devices_, false, - false, bluetooth_enabled); - } - - // Add paired devices (and their section header in MD) in the list. - if (discovered_not_paired_devices_.size() > 0) { - if (num_paired_devices > 0) - AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES); - AppendSameTypeDevicesToScrollList(discovered_not_paired_devices_, false, - false, bluetooth_enabled); - } - - // Show user Bluetooth state if there is no bluetooth devices in list. - if (device_map_.size() == 0) { - if (bluetooth_available && bluetooth_enabled) { - HoverHighlightView* container = new HoverHighlightView(this); - container->AddLabel(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING), - gfx::ALIGN_LEFT, false); - scroll_content()->AddChildView(container); - } - } - - scroll_content()->InvalidateLayout(); - } - - void AppendSameTypeDevicesToScrollList(const BluetoothDeviceList& list, - bool highlight, - bool checked, - bool enabled) { - for (size_t i = 0; i < list.size(); ++i) { - HoverHighlightView* container = nullptr; - gfx::ImageSkia icon_image = CreateVectorIcon( - GetBluetoothDeviceIcon(list[i].device_type, list[i].connected), - kMenuIconColor); - container = AddScrollListItem(list[i].display_name, icon_image, - list[i].connected, list[i].connecting); - device_map_[container] = list[i].address; - } - } - - HoverHighlightView* AddScrollListItem(const base::string16& text, - const gfx::ImageSkia& image, - bool connected, - bool connecting) { - HoverHighlightView* container = new HoverHighlightView(this); - if (connected) { - SetupConnectedItem(container, text, image); - } else if (connecting) { - SetupConnectingItem(container, text, image); - } else { - container->AddIconAndLabel(image, text, false); - } - scroll_content()->AddChildView(container); - return container; - } - - void AddSubHeader(int message_id) { - TriView* header = TrayPopupUtils::CreateSubHeaderRowView(); - TrayPopupUtils::ConfigureAsStickyHeader(header); - - views::Label* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(l10n_util::GetStringUTF16(message_id)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); - style.SetupLabel(label); - header->AddView(TriView::Container::CENTER, label); - - scroll_content()->AddChildView(header); - } - - void SetupConnectedItem(HoverHighlightView* container, - const base::string16& text, - const gfx::ImageSkia& image) { - container->AddIconAndLabels( - image, text, l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); - style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); - style.SetupLabel(container->sub_text_label()); - } - - void SetupConnectingItem(HoverHighlightView* container, - const base::string16& text, - const gfx::ImageSkia& image) { - container->AddIconAndLabels( - image, text, l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); - ThrobberView* throbber = new ThrobberView; - throbber->Start(); - container->AddRightView(throbber); - } - - // Returns true if the device with |device_id| is found in |device_list|, - // and the display_name of the device will be returned in |display_name| if - // it's not NULL. - bool FoundDevice(const std::string& device_id, - const BluetoothDeviceList& device_list, - base::string16* display_name, - device::BluetoothDeviceType* device_type) { - for (size_t i = 0; i < device_list.size(); ++i) { - if (device_list[i].address == device_id) { - if (display_name) - *display_name = device_list[i].display_name; - if (device_type) - *device_type = device_list[i].device_type; - return true; - } - } - return false; - } - - // Updates UI of the clicked bluetooth device to show it is being connected - // or disconnected if such an operation is going to be performed underway. - void UpdateClickedDevice(const std::string& device_id, - views::View* item_container) { - base::string16 display_name; - device::BluetoothDeviceType device_type; - if (FoundDevice(device_id, paired_not_connected_devices_, &display_name, - &device_type)) { - item_container->RemoveAllChildViews(true); - HoverHighlightView* container = - static_cast<HoverHighlightView*>(item_container); - TrayPopupItemStyle style( - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - gfx::ImageSkia icon_image = CreateVectorIcon( - GetBluetoothDeviceIcon(device_type, false), style.GetIconColor()); - SetupConnectingItem(container, display_name, icon_image); - scroll_content()->SizeToPreferredSize(); - scroller()->Layout(); - } - } - - // TrayDetailsView: - void HandleViewClicked(views::View* view) override { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (!delegate->GetBluetoothEnabled()) - return; - - std::map<views::View*, std::string>::iterator find; - find = device_map_.find(view); - if (find == device_map_.end()) - return; - - const std::string device_id = find->second; - if (FoundDevice(device_id, connecting_devices_, nullptr, nullptr)) - return; - - UpdateClickedDevice(device_id, view); - delegate->ConnectToBluetoothDevice(device_id); - } - - void HandleButtonPressed(views::Button* sender, - const ui::Event& event) override { - if (sender == toggle_) { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - WmShell::Get()->RecordUserMetricsAction( - delegate->GetBluetoothEnabled() ? UMA_STATUS_AREA_BLUETOOTH_DISABLED - : UMA_STATUS_AREA_BLUETOOTH_ENABLED); - delegate->ToggleBluetooth(); - } else if (sender == settings_) { - ShowSettings(); - } else { - NOTREACHED(); - } - } - - void CreateExtraTitleRowButtons() override { - if (login_ == LoginStatus::LOCKED) - return; - - DCHECK(!toggle_); - DCHECK(!settings_); - - tri_view()->SetContainerVisible(TriView::Container::END, true); - - toggle_ = - TrayPopupUtils::CreateToggleButton(this, IDS_ASH_STATUS_TRAY_BLUETOOTH); - tri_view()->AddView(TriView::Container::END, toggle_); - - settings_ = - CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS); - tri_view()->AddView(TriView::Container::END, settings_); - } - - void ShowSettings() { - if (TrayPopupUtils::CanOpenWebUISettings(login_)) { - WmShell::Get()->system_tray_delegate()->ManageBluetoothDevices(); - owner()->system_tray()->CloseSystemBubble(); - } - } - - void ShowLoadingIndicator() { - // Setting a value of -1 gives progress_bar an infinite-loading behavior. - ShowProgress(-1, true); - } - - void HideLoadingIndicator() { ShowProgress(0, false); } - - void ShowDisabledPanel() { - DCHECK(scroller()); - if (!disabled_panel_) { - disabled_panel_ = CreateDisabledPanel(); - // Insert |disabled_panel_| before the scroller, since the scroller will - // have unnecessary bottom border when it is not the last child. - AddChildViewAt(disabled_panel_, GetIndexOf(scroller())); - // |disabled_panel_| need to fill the remaining space below the title row - // so that the inner contents of |disabled_panel_| are placed properly. - box_layout()->SetFlexForView(disabled_panel_, 1); - } - disabled_panel_->SetVisible(true); - scroller()->SetVisible(false); - } - - void HideDisabledPanel() { - DCHECK(scroller()); - if (disabled_panel_) - disabled_panel_->SetVisible(false); - scroller()->SetVisible(true); - } - - views::View* CreateDisabledPanel() { - views::View* container = new views::View; - views::BoxLayout* box_layout = - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); - box_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); - container->SetLayoutManager(box_layout); - - TrayPopupItemStyle style( - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - style.set_color_style(TrayPopupItemStyle::ColorStyle::DISABLED); - - views::ImageView* image_view = new views::ImageView; - image_view->SetImage(gfx::CreateVectorIcon(kSystemMenuBluetoothDisabledIcon, - style.GetIconColor())); - image_view->SetVerticalAlignment(views::ImageView::TRAILING); - container->AddChildView(image_view); - - views::Label* label = new views::Label( - ui::ResourceBundle::GetSharedInstance().GetLocalizedString( - IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED)); - style.SetupLabel(label); - label->SetBorder(views::CreateEmptyBorder( - kDisabledPanelLabelBaselineY - label->GetBaseline(), 0, 0, 0)); - container->AddChildView(label); - - // Make top padding of the icon equal to the height of the label so that the - // icon is vertically aligned to center of the container. - image_view->SetBorder( - views::CreateEmptyBorder(label->GetPreferredSize().height(), 0, 0, 0)); - return container; - } - - LoginStatus login_; - - std::map<views::View*, std::string> device_map_; - - BluetoothDeviceList connected_devices_; - BluetoothDeviceList connecting_devices_; - BluetoothDeviceList paired_not_connected_devices_; - BluetoothDeviceList discovered_not_paired_devices_; - - views::ToggleButton* toggle_; - views::Button* settings_; - - // The container of the message "Bluetooth is disabled" and an icon. It should - // be shown instead of Bluetooth device list when Bluetooth is disabled. - views::View* disabled_panel_; - - DISALLOW_COPY_AND_ASSIGN(BluetoothDetailedView); -}; - -} // namespace tray - -TrayBluetooth::TrayBluetooth(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_BLUETOOTH), - default_(nullptr), - detailed_(nullptr) { - WmShell::Get()->system_tray_notifier()->AddBluetoothObserver(this); -} - -TrayBluetooth::~TrayBluetooth() { - WmShell::Get()->system_tray_notifier()->RemoveBluetoothObserver(this); -} - -views::View* TrayBluetooth::CreateTrayView(LoginStatus status) { - return NULL; -} - -views::View* TrayBluetooth::CreateDefaultView(LoginStatus status) { - CHECK(default_ == NULL); - default_ = new tray::BluetoothDefaultView(this); - default_->SetEnabled(status != LoginStatus::LOCKED); - default_->Update(); - return default_; -} - -views::View* TrayBluetooth::CreateDetailedView(LoginStatus status) { - if (!WmShell::Get()->system_tray_delegate()->GetBluetoothAvailable()) - return NULL; - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DETAILED_BLUETOOTH_VIEW); - CHECK(detailed_ == NULL); - detailed_ = new tray::BluetoothDetailedView(this, status); - detailed_->Update(); - return detailed_; -} - -void TrayBluetooth::DestroyTrayView() {} - -void TrayBluetooth::DestroyDefaultView() { - default_ = NULL; -} - -void TrayBluetooth::DestroyDetailedView() { - detailed_ = NULL; -} - -void TrayBluetooth::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayBluetooth::OnBluetoothRefresh() { - if (default_) - default_->Update(); - else if (detailed_) - detailed_->Update(); -} - -void TrayBluetooth::OnBluetoothDiscoveringChanged() { - if (!detailed_) - return; - detailed_->Update(); -} - -} // namespace ash
diff --git a/ash/system/bluetooth/tray_bluetooth.h b/ash/system/bluetooth/tray_bluetooth.h deleted file mode 100644 index 223c794..0000000 --- a/ash/system/bluetooth/tray_bluetooth.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_BLUETOOTH_TRAY_BLUETOOTH_H_ -#define ASH_SYSTEM_BLUETOOTH_TRAY_BLUETOOTH_H_ - -#include "ash/system/bluetooth/bluetooth_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { -namespace tray { -class BluetoothDefaultView; -class BluetoothDetailedView; -} - -class TrayBluetooth : public SystemTrayItem, public BluetoothObserver { - public: - explicit TrayBluetooth(SystemTray* system_tray); - ~TrayBluetooth() override; - - private: - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - - // Overridden from BluetoothObserver. - void OnBluetoothRefresh() override; - void OnBluetoothDiscoveringChanged() override; - - tray::BluetoothDefaultView* default_; - tray::BluetoothDetailedView* detailed_; - - DISALLOW_COPY_AND_ASSIGN(TrayBluetooth); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_BLUETOOTH_TRAY_BLUETOOTH_H_
diff --git a/ash/system/brightness/brightness_controller_chromeos.cc b/ash/system/brightness/brightness_controller_chromeos.cc deleted file mode 100644 index 9e3a473..0000000 --- a/ash/system/brightness/brightness_controller_chromeos.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/brightness/brightness_controller_chromeos.h" - -#include "base/metrics/user_metrics.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/base/accelerators/accelerator.h" - -namespace ash { -namespace system { - -void BrightnessControllerChromeos::HandleBrightnessDown( - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_DOWN) - base::RecordAction(base::UserMetricsAction("Accel_BrightnessDown_F6")); - - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->DecreaseScreenBrightness(true); -} - -void BrightnessControllerChromeos::HandleBrightnessUp( - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_UP) - base::RecordAction(base::UserMetricsAction("Accel_BrightnessUp_F7")); - - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->IncreaseScreenBrightness(); -} - -void BrightnessControllerChromeos::SetBrightnessPercent(double percent, - bool gradual) { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->SetScreenBrightnessPercent(percent, gradual); -} - -void BrightnessControllerChromeos::GetBrightnessPercent( - const base::Callback<void(double)>& callback) { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->GetScreenBrightnessPercent(callback); -} - -} // namespace system -} // namespace ash
diff --git a/ash/system/brightness/brightness_controller_chromeos.h b/ash/system/brightness/brightness_controller_chromeos.h deleted file mode 100644 index f6e7a027..0000000 --- a/ash/system/brightness/brightness_controller_chromeos.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_BRIGHTNESS_BRIGHTNESS_CONTROLLER_CHROMEOS_H_ -#define ASH_SYSTEM_BRIGHTNESS_BRIGHTNESS_CONTROLLER_CHROMEOS_H_ - -#include "ash/ash_export.h" -#include "ash/system/brightness_control_delegate.h" -#include "base/compiler_specific.h" -#include "base/macros.h" - -namespace ash { -namespace system { - -// A class which controls brightness when F6, F7 or a multimedia key for -// brightness is pressed. -class ASH_EXPORT BrightnessControllerChromeos - : public ash::BrightnessControlDelegate { - public: - BrightnessControllerChromeos() {} - ~BrightnessControllerChromeos() override {} - - // Overridden from ash::BrightnessControlDelegate: - void HandleBrightnessDown(const ui::Accelerator& accelerator) override; - void HandleBrightnessUp(const ui::Accelerator& accelerator) override; - void SetBrightnessPercent(double percent, bool gradual) override; - void GetBrightnessPercent( - const base::Callback<void(double)>& callback) override; - - private: - DISALLOW_COPY_AND_ASSIGN(BrightnessControllerChromeos); -}; - -} // namespace system -} // namespace ash - -#endif // ASH_SYSTEM_BRIGHTNESS_BRIGHTNESS_CONTROLLER_CHROMEOS_H_
diff --git a/ash/system/brightness/tray_brightness.cc b/ash/system/brightness/tray_brightness.cc deleted file mode 100644 index 79ae2c4e..0000000 --- a/ash/system/brightness/tray_brightness.cc +++ /dev/null
@@ -1,283 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/brightness/tray_brightness.h" - -#include <algorithm> - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/brightness_control_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "base/bind.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/display/display.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/slider.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/view.h" - -namespace ash { -namespace tray { -namespace { - -// We don't let the screen brightness go lower than this when it's being -// adjusted via the slider. Otherwise, if the user doesn't know about the -// brightness keys, they may turn the backlight off and not know how to turn it -// back on. -const double kMinBrightnessPercent = 5.0; - -} // namespace - -class BrightnessView : public ShellObserver, - public views::View, - public views::SliderListener { - public: - BrightnessView(bool default_view, double initial_percent); - ~BrightnessView() override; - - bool is_default_view() const { return is_default_view_; } - - // |percent| is in the range [0.0, 100.0]. - void SetBrightnessPercent(double percent); - - // ShellObserver: - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - - private: - // views::View: - void OnBoundsChanged(const gfx::Rect& old_bounds) override; - - // views:SliderListener: - void SliderValueChanged(views::Slider* sender, - float value, - float old_value, - views::SliderChangeReason reason) override; - - // views:SliderListener: - void SliderDragStarted(views::Slider* slider) override; - void SliderDragEnded(views::Slider* slider) override; - - views::Slider* slider_; - - // Is |slider_| currently being dragged? - bool dragging_; - - // True if this view is for the default tray view. Used to control hide/show - // behaviour of the default view when entering or leaving Maximize Mode. - bool is_default_view_; - - // Last brightness level that we observed, in the range [0.0, 100.0]. - double last_percent_; - - DISALLOW_COPY_AND_ASSIGN(BrightnessView); -}; - -BrightnessView::BrightnessView(bool default_view, double initial_percent) - : dragging_(false), - is_default_view_(default_view), - last_percent_(initial_percent) { - SetLayoutManager(new views::FillLayout); - // Use CreateMultiTargetRowView() instead of CreateDefaultRowView() because - // that's what the audio row uses and we want the two rows to layout with the - // same insets. - TriView* tri_view = TrayPopupUtils::CreateMultiTargetRowView(); - AddChildView(tri_view); - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - views::ImageView* icon = TrayPopupUtils::CreateMainImageView(); - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - icon->SetImage( - gfx::CreateVectorIcon(kSystemMenuBrightnessIcon, kMenuIconColor)); - } else { - icon->SetImage( - rb.GetImageNamed(IDR_AURA_UBER_TRAY_BRIGHTNESS).ToImageSkia()); - } - tri_view->AddView(TriView::Container::START, icon); - - slider_ = TrayPopupUtils::CreateSlider(this); - slider_->SetValue(static_cast<float>(initial_percent / 100.0)); - slider_->SetAccessibleName( - rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_BRIGHTNESS)); - tri_view->AddView(TriView::Container::CENTER, slider_); - - if (is_default_view_) { - WmShell::Get()->AddShellObserver(this); - SetVisible(WmShell::Get() - ->maximize_mode_controller() - ->IsMaximizeModeWindowManagerEnabled()); - } else { - tri_view->SetContainerVisible(TriView::Container::END, false); - } -} - -BrightnessView::~BrightnessView() { - if (is_default_view_) - WmShell::Get()->RemoveShellObserver(this); -} - -void BrightnessView::SetBrightnessPercent(double percent) { - last_percent_ = percent; - if (!dragging_) - slider_->SetValue(static_cast<float>(percent / 100.0)); -} - -void BrightnessView::OnMaximizeModeStarted() { - SetVisible(true); -} - -void BrightnessView::OnMaximizeModeEnded() { - SetVisible(false); -} - -void BrightnessView::OnBoundsChanged(const gfx::Rect& old_bounds) { - int w = width() - slider_->x(); - slider_->SetSize(gfx::Size(w, slider_->height())); -} - -void BrightnessView::SliderValueChanged(views::Slider* sender, - float value, - float old_value, - views::SliderChangeReason reason) { - DCHECK_EQ(sender, slider_); - if (reason != views::VALUE_CHANGED_BY_USER) - return; - BrightnessControlDelegate* brightness_control_delegate = - WmShell::Get()->brightness_control_delegate(); - if (brightness_control_delegate) { - double percent = std::max(value * 100.0, kMinBrightnessPercent); - brightness_control_delegate->SetBrightnessPercent(percent, true); - } -} - -void BrightnessView::SliderDragStarted(views::Slider* slider) { - DCHECK_EQ(slider, slider_); - dragging_ = true; -} - -void BrightnessView::SliderDragEnded(views::Slider* slider) { - DCHECK_EQ(slider, slider_); - dragging_ = false; - slider_->SetValue(static_cast<float>(last_percent_ / 100.0)); -} - -} // namespace tray - -TrayBrightness::TrayBrightness(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_DISPLAY_BRIGHTNESS), - brightness_view_(NULL), - current_percent_(100.0), - got_current_percent_(false), - weak_ptr_factory_(this) { - // Post a task to get the initial brightness; the BrightnessControlDelegate - // isn't created yet. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&TrayBrightness::GetInitialBrightness, - weak_ptr_factory_.GetWeakPtr())); - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( - this); -} - -TrayBrightness::~TrayBrightness() { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( - this); -} - -void TrayBrightness::GetInitialBrightness() { - BrightnessControlDelegate* brightness_control_delegate = - WmShell::Get()->brightness_control_delegate(); - // Worrisome, but happens in unit tests, so don't log anything. - if (!brightness_control_delegate) - return; - brightness_control_delegate->GetBrightnessPercent( - base::Bind(&TrayBrightness::HandleInitialBrightness, - weak_ptr_factory_.GetWeakPtr())); -} - -void TrayBrightness::HandleInitialBrightness(double percent) { - if (!got_current_percent_) - HandleBrightnessChanged(percent, false); -} - -views::View* TrayBrightness::CreateTrayView(LoginStatus status) { - return NULL; -} - -views::View* TrayBrightness::CreateDefaultView(LoginStatus status) { - CHECK(brightness_view_ == NULL); - brightness_view_ = new tray::BrightnessView(true, current_percent_); - return brightness_view_; -} - -views::View* TrayBrightness::CreateDetailedView(LoginStatus status) { - CHECK(brightness_view_ == NULL); - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DETAILED_BRIGHTNESS_VIEW); - brightness_view_ = new tray::BrightnessView(false, current_percent_); - return brightness_view_; -} - -void TrayBrightness::DestroyTrayView() {} - -void TrayBrightness::DestroyDefaultView() { - if (brightness_view_ && brightness_view_->is_default_view()) - brightness_view_ = NULL; -} - -void TrayBrightness::DestroyDetailedView() { - if (brightness_view_ && !brightness_view_->is_default_view()) - brightness_view_ = NULL; -} - -void TrayBrightness::UpdateAfterLoginStatusChange(LoginStatus status) {} - -bool TrayBrightness::ShouldShowShelf() const { - return false; -} - -void TrayBrightness::BrightnessChanged(int level, bool user_initiated) { - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_BRIGHTNESS_CHANGED); - double percent = static_cast<double>(level); - HandleBrightnessChanged(percent, user_initiated); -} - -void TrayBrightness::HandleBrightnessChanged(double percent, - bool user_initiated) { - current_percent_ = percent; - got_current_percent_ = true; - - if (brightness_view_) - brightness_view_->SetBrightnessPercent(percent); - - if (!user_initiated) - return; - - // Never show the bubble on systems that lack internal displays: if an - // external display's brightness is changed, it may already display the new - // level via an on-screen display. - if (!display::Display::HasInternalDisplay()) - return; - - if (brightness_view_ && brightness_view_->visible()) - SetDetailedViewCloseDelay(kTrayPopupAutoCloseDelayInSeconds); - else - PopupDetailedView(kTrayPopupAutoCloseDelayInSeconds, false); -} - -} // namespace ash
diff --git a/ash/system/brightness/tray_brightness.h b/ash/system/brightness/tray_brightness.h deleted file mode 100644 index c443f6f..0000000 --- a/ash/system/brightness/tray_brightness.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_BRIGHTNESS_TRAY_BRIGHTNESS_H_ -#define ASH_SYSTEM_BRIGHTNESS_TRAY_BRIGHTNESS_H_ - -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "chromeos/dbus/power_manager_client.h" - -namespace ash { -namespace tray { -class BrightnessView; -} - -class ASH_EXPORT TrayBrightness - : public SystemTrayItem, - public chromeos::PowerManagerClient::Observer { - public: - explicit TrayBrightness(SystemTray* system_tray); - ~TrayBrightness() override; - - private: - friend class TrayBrightnessTest; - - // Sends a request to get the current screen brightness so |current_percent_| - // can be initialized. - void GetInitialBrightness(); - - // Updates |current_percent_| with the initial brightness requested by - // GetInitialBrightness(), if we haven't seen the brightness already in the - // meantime. - void HandleInitialBrightness(double percent); - - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - bool ShouldShowShelf() const override; - - // Overriden from PowerManagerClient::Observer. - void BrightnessChanged(int level, bool user_initiated) override; - - void HandleBrightnessChanged(double percent, bool user_initiated); - - tray::BrightnessView* brightness_view_; - - // Brightness level in the range [0.0, 100.0] that we've heard about most - // recently. - double current_percent_; - - // Has |current_percent_| been initialized? - bool got_current_percent_; - - base::WeakPtrFactory<TrayBrightness> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(TrayBrightness); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_BRIGHTNESS_TRAY_BRIGHTNESS_H_
diff --git a/ash/system/brightness/tray_brightness_unittest.cc b/ash/system/brightness/tray_brightness_unittest.cc deleted file mode 100644 index 31e470f..0000000 --- a/ash/system/brightness/tray_brightness_unittest.cc +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/brightness/tray_brightness.h" - -#include <memory> - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/test/ash_test.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ui/views/view.h" - -namespace ash { - -class TrayBrightnessTest : public AshTest { - public: - TrayBrightnessTest() {} - ~TrayBrightnessTest() override {} - - protected: - views::View* CreateDefaultView() { - TrayBrightness tray(NULL); - // The login status doesn't matter here; supply any random value. - return tray.CreateDefaultView(LoginStatus::USER); - } - - views::View* CreateDetailedView() { - TrayBrightness tray(NULL); - // The login status doesn't matter here; supply any random value. - return tray.CreateDetailedView(LoginStatus::USER); - } - - private: - DISALLOW_COPY_AND_ASSIGN(TrayBrightnessTest); -}; - -// Tests that when the default view is initially created, that its -// BrightnessView is created not visible. -TEST_F(TrayBrightnessTest, CreateDefaultView) { - std::unique_ptr<views::View> tray(CreateDefaultView()); - EXPECT_FALSE(tray->visible()); -} - -// Tests the construction of the default view while MaximizeMode is active. -// The BrightnessView should be visible. -TEST_F(TrayBrightnessTest, CreateDefaultViewDuringMaximizeMode) { - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - std::unique_ptr<views::View> tray(CreateDefaultView()); - EXPECT_TRUE(tray->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); -} - -// Tests that the enabling of MaximizeMode affects a previously created -// BrightnessView, changing the visibility. -TEST_F(TrayBrightnessTest, DefaultViewVisibilityChangesDuringMaximizeMode) { - std::unique_ptr<views::View> tray(CreateDefaultView()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - EXPECT_TRUE(tray->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - EXPECT_FALSE(tray->visible()); -} - -// Tests that when the detailed view is initially created that its -// BrightnessView is created as visible for both MD and non MD modes. -TEST_F(TrayBrightnessTest, CreateDetailedView) { - std::unique_ptr<views::View> tray(CreateDetailedView()); - EXPECT_TRUE(tray->visible()); -} - -// Tests that when the detailed view is created during MaximizeMode that its -// BrightnessView is visible. -TEST_F(TrayBrightnessTest, CreateDetailedViewDuringMaximizeMode) { - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - std::unique_ptr<views::View> tray(CreateDetailedView()); - EXPECT_TRUE(tray->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); -} - -// Tests that the enabling of MaximizeMode has no affect on the visibility of a -// previously created BrightnessView that belongs to a detailed view. -TEST_F(TrayBrightnessTest, DetailedViewVisibilityChangesDuringMaximizeMode) { - std::unique_ptr<views::View> tray(CreateDetailedView()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - EXPECT_TRUE(tray->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - EXPECT_TRUE(tray->visible()); -} - -} // namespace ash
diff --git a/ash/system/brightness_control_delegate.h b/ash/system/brightness_control_delegate.h deleted file mode 100644 index 153cc92..0000000 --- a/ash/system/brightness_control_delegate.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_BRIGHTNESS_CONTROL_DELEGATE_H_ -#define ASH_SYSTEM_BRIGHTNESS_CONTROL_DELEGATE_H_ - -#include "base/callback.h" - -namespace ui { -class Accelerator; -} // namespace ui - -namespace ash { - -// Delegate for controlling the brightness. -class BrightnessControlDelegate { - public: - virtual ~BrightnessControlDelegate() {} - - // Handles an accelerator-driven request to decrease or increase the screen - // brightness. - virtual void HandleBrightnessDown(const ui::Accelerator& accelerator) = 0; - virtual void HandleBrightnessUp(const ui::Accelerator& accelerator) = 0; - - // Requests that the brightness be set to |percent|, in the range - // [0.0, 100.0]. |gradual| specifies whether the transition to the new - // brightness should be animated or instantaneous. - virtual void SetBrightnessPercent(double percent, bool gradual) = 0; - - // Asynchronously invokes |callback| with the current brightness, in the range - // [0.0, 100.0]. - virtual void GetBrightnessPercent( - const base::Callback<void(double)>& callback) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_BRIGHTNESS_CONTROL_DELEGATE_H_
diff --git a/ash/system/cast/tray_cast.cc b/ash/system/cast/tray_cast.cc deleted file mode 100644 index 9765818..0000000 --- a/ash/system/cast/tray_cast.cc +++ /dev/null
@@ -1,572 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/cast/tray_cast.h" - -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include "ash/common/cast_config_controller.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/public/interfaces/cast_config.mojom.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/screen_security/screen_tray_item.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/throbber_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_item_more.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_utils.h" -#include "base/bind.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/text_elider.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -namespace { - -const size_t kMaximumStatusStringLength = 100; - -// Helper method to elide the given string to the maximum length. If a string is -// contains user-input and is displayed, we should elide it. -// TODO(jdufault): This does not properly trim unicode characters. We should -// implement this properly by using views::Label::SetElideBehavior(...). See -// crbug.com/532496. -base::string16 ElideString(const base::string16& text) { - base::string16 elided; - gfx::ElideString(text, kMaximumStatusStringLength, &elided); - return elided; -} - -// Returns a vectorized version of the Cast icon. The icon's interior region is -// filled in if |is_casting| is true. -gfx::ImageSkia GetCastIconForSystemMenu(bool is_casting) { - return gfx::CreateVectorIcon( - kSystemMenuCastIcon, is_casting ? kMenuIconColor : SK_ColorTRANSPARENT); -} - -} // namespace - -namespace tray { - -// This view is displayed in the system tray when the cast extension is active. -// It asks the user if they want to cast the desktop. If they click on the -// chevron, then a detail view will replace this view where the user will -// actually pick the cast receiver. -class CastSelectDefaultView : public TrayItemMore { - public: - explicit CastSelectDefaultView(SystemTrayItem* owner); - ~CastSelectDefaultView() override; - - private: - DISALLOW_COPY_AND_ASSIGN(CastSelectDefaultView); -}; - -CastSelectDefaultView::CastSelectDefaultView(SystemTrayItem* owner) - : TrayItemMore(owner) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - - // Update the image and label. - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - SetImage(GetCastIconForSystemMenu(false)); - else - SetImage(*rb.GetImageNamed(IDR_AURA_UBER_TRAY_CAST).ToImageSkia()); - - base::string16 label = - rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_CAST_DESKTOP); - SetLabel(label); - SetAccessibleName(label); -} - -CastSelectDefaultView::~CastSelectDefaultView() {} - -// This view is displayed when the screen is actively being casted; it allows -// the user to easily stop casting. It fully replaces the -// |CastSelectDefaultView| view inside of the |CastDuplexView|. -class CastCastView : public ScreenStatusView { - public: - CastCastView(); - ~CastCastView() override; - - void StopCasting(); - - const std::string& displayed_route_id() const { return displayed_route_->id; } - - // Updates the label for the stop view to include information about the - // current device that is being casted. - void UpdateLabel(const std::vector<mojom::SinkAndRoutePtr>& sinks_routes); - - private: - // Overridden from views::ButtonListener. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // The cast activity id that we are displaying. If the user stops a cast, we - // send this value to the config delegate so that we stop the right cast. - mojom::CastRoutePtr displayed_route_; - - DISALLOW_COPY_AND_ASSIGN(CastCastView); -}; - -CastCastView::CastCastView() - : ScreenStatusView( - nullptr, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN), - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_STOP)) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - icon()->SetImage(GetCastIconForSystemMenu(true)); - } else { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - icon()->SetImage( - bundle.GetImageNamed(IDR_AURA_UBER_TRAY_CAST_ENABLED).ToImageSkia()); - } -} - -CastCastView::~CastCastView() {} - -void CastCastView::StopCasting() { - WmShell::Get()->cast_config()->StopCasting(displayed_route_.Clone()); - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_CAST_STOP_CAST); -} - -void CastCastView::UpdateLabel( - const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) { - for (auto& i : sinks_routes) { - const mojom::CastSinkPtr& sink = i->sink; - const mojom::CastRoutePtr& route = i->route; - - // We only want to display casts that came from this machine, since on a - // busy network many other people could be casting. - if (!route->id.empty() && route->is_local_source) { - displayed_route_ = route.Clone(); - - // We want to display different labels inside of the title depending on - // what we are actually casting - either the desktop, a tab, or a fallback - // that catches everything else (ie, an extension tab). - switch (route->content_source) { - case ash::mojom::ContentSource::UNKNOWN: - label()->SetText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN)); - stop_button()->SetAccessibleName(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_CAST_CAST_UNKNOWN_ACCESSIBILITY_STOP)); - break; - case ash::mojom::ContentSource::TAB: - label()->SetText(ElideString(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_CAST_CAST_TAB, - base::UTF8ToUTF16(route->title), base::UTF8ToUTF16(sink->name)))); - stop_button()->SetAccessibleName( - ElideString(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_CAST_CAST_TAB_ACCESSIBILITY_STOP, - base::UTF8ToUTF16(route->title), - base::UTF8ToUTF16(sink->name)))); - break; - case ash::mojom::ContentSource::DESKTOP: - label()->SetText(ElideString( - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP, - base::UTF8ToUTF16(sink->name)))); - stop_button()->SetAccessibleName( - ElideString(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_CAST_CAST_DESKTOP_ACCESSIBILITY_STOP, - base::UTF8ToUTF16(sink->name)))); - break; - } - - PreferredSizeChanged(); - Layout(); - // Only need to update labels once. - break; - } - } -} - -void CastCastView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - StopCasting(); -} - -// This view by itself does very little. It acts as a front-end for managing -// which of the two child views (|CastSelectDefaultView| and |CastCastView|) -// is active. -class CastDuplexView : public views::View { - public: - CastDuplexView(SystemTrayItem* owner, - bool enabled, - const std::vector<mojom::SinkAndRoutePtr>& sinks_routes); - ~CastDuplexView() override; - - // Activate either the casting or select view. - void ActivateCastView(); - void ActivateSelectView(); - - CastSelectDefaultView* select_view() { return select_view_; } - CastCastView* cast_view() { return cast_view_; } - - private: - // Overridden from views::View. - void ChildPreferredSizeChanged(views::View* child) override; - void Layout() override; - - // Only one of |select_view_| or |cast_view_| will be displayed at any given - // time. This will return the view is being displayed. - views::View* ActiveChildView(); - - CastSelectDefaultView* select_view_; - CastCastView* cast_view_; - - DISALLOW_COPY_AND_ASSIGN(CastDuplexView); -}; - -CastDuplexView::CastDuplexView( - SystemTrayItem* owner, - bool enabled, - const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) { - select_view_ = new CastSelectDefaultView(owner); - select_view_->SetEnabled(enabled); - cast_view_ = new CastCastView(); - cast_view_->UpdateLabel(sinks_routes); - SetLayoutManager(new views::FillLayout()); - - ActivateSelectView(); -} - -CastDuplexView::~CastDuplexView() { - RemoveChildView(ActiveChildView()); - delete select_view_; - delete cast_view_; -} - -void CastDuplexView::ActivateCastView() { - if (ActiveChildView() == cast_view_) - return; - - RemoveChildView(select_view_); - AddChildView(cast_view_); - InvalidateLayout(); -} - -void CastDuplexView::ActivateSelectView() { - if (ActiveChildView() == select_view_) - return; - - RemoveChildView(cast_view_); - AddChildView(select_view_); - InvalidateLayout(); -} - -void CastDuplexView::ChildPreferredSizeChanged(views::View* child) { - PreferredSizeChanged(); -} - -void CastDuplexView::Layout() { - views::View::Layout(); - - select_view_->SetBoundsRect(GetContentsBounds()); - cast_view_->SetBoundsRect(GetContentsBounds()); -} - -views::View* CastDuplexView::ActiveChildView() { - if (cast_view_->parent() == this) - return cast_view_; - if (select_view_->parent() == this) - return select_view_; - return nullptr; -} - -// Exposes an icon in the tray. |TrayCast| manages the visiblity of this. -class CastTrayView : public TrayItemView { - public: - explicit CastTrayView(SystemTrayItem* tray_item); - ~CastTrayView() override; - - private: - DISALLOW_COPY_AND_ASSIGN(CastTrayView); -}; - -CastTrayView::CastTrayView(SystemTrayItem* tray_item) - : TrayItemView(tray_item) { - CreateImageView(); - if (MaterialDesignController::UseMaterialDesignSystemIcons()) { - image_view()->SetImage( - gfx::CreateVectorIcon(kSystemTrayCastIcon, kTrayIconColor)); - } else { - image_view()->SetImage(ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE) - .ToImageSkia()); - } -} - -CastTrayView::~CastTrayView() {} - -// This view displays a list of cast receivers that can be clicked on and casted -// to. It is activated by clicking on the chevron inside of -// |CastSelectDefaultView|. -class CastDetailedView : public TrayDetailsView { - public: - CastDetailedView(SystemTrayItem* owner, - const std::vector<mojom::SinkAndRoutePtr>& sinks_and_routes); - ~CastDetailedView() override; - - // Makes the detail view think the view associated with the given receiver_id - // was clicked. This will start a cast. - void SimulateViewClickedForTest(const std::string& receiver_id); - - // Updates the list of available receivers. - void UpdateReceiverList( - const std::vector<mojom::SinkAndRoutePtr>& sinks_routes); - - private: - void CreateItems(); - - void UpdateReceiverListFromCachedData(); - views::View* AddToReceiverList(const mojom::SinkAndRoutePtr& sink_route); - - // TrayDetailsView: - void HandleViewClicked(views::View* view) override; - - // A mapping from the receiver id to the receiver/activity data. - std::map<std::string, ash::mojom::SinkAndRoutePtr> sinks_and_routes_; - // A mapping from the view pointer to the associated activity id. - std::map<views::View*, ash::mojom::CastSinkPtr> view_to_sink_map_; - - DISALLOW_COPY_AND_ASSIGN(CastDetailedView); -}; - -CastDetailedView::CastDetailedView( - SystemTrayItem* owner, - const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) - : TrayDetailsView(owner) { - CreateItems(); - UpdateReceiverList(sinks_routes); -} - -CastDetailedView::~CastDetailedView() {} - -void CastDetailedView::SimulateViewClickedForTest( - const std::string& receiver_id) { - for (const auto& it : view_to_sink_map_) { - if (it.second->id == receiver_id) { - HandleViewClicked(it.first); - break; - } - } -} - -void CastDetailedView::CreateItems() { - CreateScrollableList(); - CreateTitleRow(IDS_ASH_STATUS_TRAY_CAST); -} - -void CastDetailedView::UpdateReceiverList( - const std::vector<mojom::SinkAndRoutePtr>& sinks_routes) { - // Add/update existing. - for (const auto& it : sinks_routes) - sinks_and_routes_[it->sink->id] = it->Clone(); - - // Remove non-existent sinks. Removing an element invalidates all existing - // iterators. - auto i = sinks_and_routes_.begin(); - while (i != sinks_and_routes_.end()) { - bool has_receiver = false; - for (auto& receiver : sinks_routes) { - if (i->first == receiver->sink->id) - has_receiver = true; - } - - if (has_receiver) - ++i; - else - i = sinks_and_routes_.erase(i); - } - - // Update UI. - UpdateReceiverListFromCachedData(); - Layout(); -} - -void CastDetailedView::UpdateReceiverListFromCachedData() { - // Remove all of the existing views. - view_to_sink_map_.clear(); - scroll_content()->RemoveAllChildViews(true); - - // Add a view for each receiver. - for (auto& it : sinks_and_routes_) { - const ash::mojom::SinkAndRoutePtr& sink_route = it.second; - views::View* container = AddToReceiverList(sink_route); - view_to_sink_map_[container] = sink_route->sink.Clone(); - } - - scroll_content()->SizeToPreferredSize(); - scroller()->Layout(); -} - -views::View* CastDetailedView::AddToReceiverList( - const ash::mojom::SinkAndRoutePtr& sink_route) { - const gfx::ImageSkia image = - MaterialDesignController::IsSystemTrayMenuMaterial() - ? gfx::CreateVectorIcon(kSystemMenuCastDeviceIcon, kMenuIconColor) - : *ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_AURA_UBER_TRAY_CAST_DEVICE_ICON) - .ToImageSkia(); - - HoverHighlightView* container = new HoverHighlightView(this); - container->AddIconAndLabelCustomSize( - image, base::UTF8ToUTF16(sink_route->sink->name), false, - kTrayPopupDetailsIconWidth, kTrayPopupPaddingHorizontal, - kTrayPopupPaddingBetweenItems); - - scroll_content()->AddChildView(container); - return container; -} - -void CastDetailedView::HandleViewClicked(views::View* view) { - // Find the receiver we are going to cast to. - auto it = view_to_sink_map_.find(view); - if (it != view_to_sink_map_.end()) { - WmShell::Get()->cast_config()->CastToSink(it->second.Clone()); - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DETAILED_CAST_VIEW_LAUNCH_CAST); - } -} - -} // namespace tray - -TrayCast::TrayCast(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_CAST) { - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->cast_config()->AddObserver(this); - WmShell::Get()->cast_config()->RequestDeviceRefresh(); -} - -TrayCast::~TrayCast() { - WmShell::Get()->cast_config()->RemoveObserver(this); - WmShell::Get()->RemoveShellObserver(this); -} - -void TrayCast::StartCastForTest(const std::string& receiver_id) { - if (detailed_ != nullptr) - detailed_->SimulateViewClickedForTest(receiver_id); -} - -void TrayCast::StopCastForTest() { - default_->cast_view()->StopCasting(); -} - -const std::string& TrayCast::GetDisplayedCastId() { - return default_->cast_view()->displayed_route_id(); -} - -const views::View* TrayCast::GetDefaultView() const { - return default_; -} - -views::View* TrayCast::CreateTrayView(LoginStatus status) { - CHECK(tray_ == nullptr); - tray_ = new tray::CastTrayView(this); - tray_->SetVisible(HasActiveRoute()); - return tray_; -} - -views::View* TrayCast::CreateDefaultView(LoginStatus status) { - CHECK(default_ == nullptr); - - default_ = new tray::CastDuplexView(this, status != LoginStatus::LOCKED, - sinks_and_routes_); - default_->set_id(TRAY_VIEW); - default_->select_view()->set_id(SELECT_VIEW); - default_->cast_view()->set_id(CAST_VIEW); - - UpdatePrimaryView(); - return default_; -} - -views::View* TrayCast::CreateDetailedView(LoginStatus status) { - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_DETAILED_CAST_VIEW); - CHECK(detailed_ == nullptr); - detailed_ = new tray::CastDetailedView(this, sinks_and_routes_); - return detailed_; -} - -void TrayCast::DestroyTrayView() { - tray_ = nullptr; -} - -void TrayCast::DestroyDefaultView() { - default_ = nullptr; -} - -void TrayCast::DestroyDetailedView() { - detailed_ = nullptr; -} - -void TrayCast::OnDevicesUpdated(std::vector<mojom::SinkAndRoutePtr> devices) { - sinks_and_routes_ = std::move(devices); - UpdatePrimaryView(); - - if (default_) { - bool has_receivers = !sinks_and_routes_.empty(); - default_->SetVisible(has_receivers); - default_->cast_view()->UpdateLabel(sinks_and_routes_); - } - if (detailed_) - detailed_->UpdateReceiverList(sinks_and_routes_); -} - -void TrayCast::UpdatePrimaryView() { - if (WmShell::Get()->cast_config()->Connected() && - !sinks_and_routes_.empty()) { - if (default_) { - if (HasActiveRoute()) - default_->ActivateCastView(); - else - default_->ActivateSelectView(); - } - - if (tray_) - tray_->SetVisible(is_mirror_casting_); - } else { - if (default_) - default_->SetVisible(false); - if (tray_) - tray_->SetVisible(false); - } -} - -bool TrayCast::HasActiveRoute() { - for (const auto& sr : sinks_and_routes_) { - if (!sr->route->title.empty() && sr->route->is_local_source) - return true; - } - - return false; -} - -void TrayCast::OnCastingSessionStartedOrStopped(bool started) { - is_mirror_casting_ = started; - UpdatePrimaryView(); -} - -} // namespace ash
diff --git a/ash/system/cast/tray_cast.h b/ash/system/cast/tray_cast.h deleted file mode 100644 index 3935250d..0000000 --- a/ash/system/cast/tray_cast.h +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_CAST_TRAY_CAST_H_ -#define ASH_SYSTEM_CAST_TRAY_CAST_H_ - -#include <string> -#include <vector> - -#include "ash/common/cast_config_controller.h" -#include "ash/common/shell_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { -namespace tray { -class CastTrayView; -class CastDetailedView; -class CastDuplexView; -} // namespace tray - -class ASH_EXPORT TrayCast : public SystemTrayItem, - public ShellObserver, - public CastConfigControllerObserver { - public: - explicit TrayCast(SystemTray* system_tray); - ~TrayCast() override; - - private: - // Helper/utility methods for testing. - friend class TrayCastTestAPI; - void StartCastForTest(const std::string& sink_id); - void StopCastForTest(); - // Returns the id of the item we are currently displaying in the cast view. - // This assumes that the cast view is active. - const std::string& GetDisplayedCastId(); - const views::View* GetDefaultView() const; - enum ChildViewId { TRAY_VIEW = 1, SELECT_VIEW, CAST_VIEW }; - - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - - // Overridden from ShellObserver. - void OnCastingSessionStartedOrStopped(bool started) override; - - // Overridden from CastConfigObserver. - void OnDevicesUpdated(std::vector<mojom::SinkAndRoutePtr> devices) override; - - // This makes sure that the current view displayed in the tray is the correct - // one, depending on if we are currently casting. If we're casting, then a - // view with a stop button is displayed; otherwise, a view that links to a - // detail view is displayed instead that allows the user to easily begin a - // casting session. - void UpdatePrimaryView(); - - // Returns true if there is an active cast route. The route may be DIAL based, - // such as casting YouTube where the cast sink directly streams content from - // another server. In that case, is_mirror_casting_ will be false since this - // device is not actively transmitting information to the cast sink. - bool HasActiveRoute(); - - std::vector<mojom::SinkAndRoutePtr> sinks_and_routes_; - - // True if there is a mirror-based cast session and the active-cast tray icon - // should be shown. - bool is_mirror_casting_ = false; - - // Not owned. - tray::CastTrayView* tray_ = nullptr; - tray::CastDuplexView* default_ = nullptr; - tray::CastDetailedView* detailed_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(TrayCast); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_CAST_TRAY_CAST_H_
diff --git a/ash/system/chromeos/DEPS b/ash/system/chromeos/DEPS new file mode 100644 index 0000000..8b78505 --- /dev/null +++ b/ash/system/chromeos/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+grit/ui_chromeos_resources.h", + "+grit/ui_chromeos_strings.h", +]
diff --git a/ash/system/chromeos/power/power_event_observer.cc b/ash/system/chromeos/power/power_event_observer.cc new file mode 100644 index 0000000..a59d96f --- /dev/null +++ b/ash/system/chromeos/power/power_event_observer.cc
@@ -0,0 +1,165 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/power/power_event_observer.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm_shell.h" +#include "ash/shell.h" +#include "ash/wm/power_button_controller.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" +#include "ui/base/user_activity/user_activity_detector.h" +#include "ui/compositor/compositor.h" +#include "ui/display/manager/chromeos/display_configurator.h" + +namespace ash { + +namespace { + +// Tells the compositor for each of the displays to finish all pending +// rendering requests and block any new ones. +void StopRenderingRequests() { + for (aura::Window* window : Shell::GetAllRootWindows()) { + ui::Compositor* compositor = window->GetHost()->compositor(); + compositor->SetVisible(false); + } +} + +// Tells the compositor for each of the displays to resume sending rendering +// requests to the GPU. +void ResumeRenderingRequests() { + for (aura::Window* window : Shell::GetAllRootWindows()) + window->GetHost()->compositor()->SetVisible(true); +} + +void OnSuspendDisplaysCompleted(const base::Closure& suspend_callback, + bool status) { + suspend_callback.Run(); +} + +} // namespace + +PowerEventObserver::PowerEventObserver() + : screen_locked_(false), waiting_for_lock_screen_animations_(false) { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( + this); + chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver( + this); +} + +PowerEventObserver::~PowerEventObserver() { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( + this); + chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver( + this); +} + +void PowerEventObserver::OnLockAnimationsComplete() { + VLOG(1) << "Screen locker animations have completed."; + waiting_for_lock_screen_animations_ = false; + + if (!screen_lock_callback_.is_null()) { + StopRenderingRequests(); + + screen_lock_callback_.Run(); + screen_lock_callback_.Reset(); + } +} + +void PowerEventObserver::BrightnessChanged(int level, bool user_initiated) { + Shell::GetInstance()->power_button_controller()->OnScreenBrightnessChanged( + static_cast<double>(level)); +} + +void PowerEventObserver::SuspendImminent() { + SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); + + // This class is responsible for disabling all rendering requests at suspend + // time and then enabling them at resume time. When the + // auto-screen-lock pref is not set this is easy to do since + // StopRenderingRequests() is just called directly from this function. If the + // auto-screen-lock pref _is_ set, then the suspend needs to be delayed + // until the lock screen is fully visible. While it is sufficient from a + // security perspective to block only until the lock screen is ready, which + // guarantees that the contents of the user's screen are no longer visible, + // this leads to poor UX on the first resume since neither the user pod nor + // the header bar will be visible for a few hundred milliseconds until the GPU + // process starts rendering again. To deal with this, the suspend is delayed + // until all the lock screen animations have completed and the suspend request + // is unblocked from OnLockAnimationsComplete(). + if (!screen_locked_ && delegate->ShouldLockScreenAutomatically() && + delegate->CanLockScreen()) { + screen_lock_callback_ = chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->GetSuspendReadinessCallback(); + VLOG(1) << "Requesting screen lock from PowerEventObserver"; + chromeos::DBusThreadManager::Get() + ->GetSessionManagerClient() + ->RequestLockScreen(); + } else if (waiting_for_lock_screen_animations_) { + // The lock-before-suspending pref has been set and the lock screen is ready + // but the animations have not completed yet. This can happen if a suspend + // request is canceled after the lock screen is ready but before the + // animations have completed and then another suspend request is immediately + // started. In practice, it is highly unlikely that this will ever happen + // but it's better to be safe since the cost of not dealing with it properly + // is a memory leak in the GPU and weird artifacts on the screen. + screen_lock_callback_ = chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->GetSuspendReadinessCallback(); + } else { + // The lock-before-suspending pref is not set or the screen has already been + // locked and the animations have completed. Rendering can be stopped now. + StopRenderingRequests(); + } + + ui::UserActivityDetector::Get()->OnDisplayPowerChanging(); + + // TODO(derat): After mus exposes a method for suspending displays, call it + // here: http://crbug.com/692193 + if (!WmShell::Get()->IsRunningInMash()) { + Shell::GetInstance()->display_configurator()->SuspendDisplays(base::Bind( + &OnSuspendDisplaysCompleted, chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->GetSuspendReadinessCallback())); + } +} + +void PowerEventObserver::SuspendDone(const base::TimeDelta& sleep_duration) { + // TODO(derat): After mus exposes a method for resuming displays, call it + // here: http://crbug.com/692193 + if (!WmShell::Get()->IsRunningInMash()) + Shell::GetInstance()->display_configurator()->ResumeDisplays(); + WmShell::Get()->system_tray_notifier()->NotifyRefreshClock(); + + // If the suspend request was being blocked while waiting for the lock + // animation to complete, clear the blocker since the suspend has already + // completed. This prevents rendering requests from being blocked after a + // resume if the lock screen took too long to show. + screen_lock_callback_.Reset(); + + ResumeRenderingRequests(); +} + +void PowerEventObserver::ScreenIsLocked() { + screen_locked_ = true; + waiting_for_lock_screen_animations_ = true; + + // The screen is now locked but the pending suspend, if any, will be blocked + // until all the animations have completed. + if (!screen_lock_callback_.is_null()) { + VLOG(1) << "Screen locked due to suspend"; + } else { + VLOG(1) << "Screen locked without suspend"; + } +} + +void PowerEventObserver::ScreenIsUnlocked() { + screen_locked_ = false; +} + +} // namespace ash
diff --git a/ash/system/chromeos/power/power_event_observer.h b/ash/system/chromeos/power/power_event_observer.h new file mode 100644 index 0000000..eb5bc058 --- /dev/null +++ b/ash/system/chromeos/power/power_event_observer.h
@@ -0,0 +1,57 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHROMEOS_POWER_POWER_EVENT_OBSERVER_H_ +#define ASH_SYSTEM_CHROMEOS_POWER_POWER_EVENT_OBSERVER_H_ + +#include "ash/ash_export.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "chromeos/dbus/power_manager_client.h" +#include "chromeos/dbus/session_manager_client.h" + +namespace ash { + +// A class that observes power-management-related events. +class ASH_EXPORT PowerEventObserver + : public chromeos::PowerManagerClient::Observer, + public chromeos::SessionManagerClient::Observer { + public: + // This class registers/unregisters itself as an observer in ctor/dtor. + PowerEventObserver(); + ~PowerEventObserver() override; + + // Called by the WebUIScreenLocker when all the lock screen animations have + // completed. This really should be implemented via an observer but since + // ash/ isn't allowed to depend on chrome/ we need to have the + // WebUIScreenLocker reach into ash::Shell to make this call. + void OnLockAnimationsComplete(); + + // chromeos::PowerManagerClient::Observer overrides: + void BrightnessChanged(int level, bool user_initiated) override; + void SuspendImminent() override; + void SuspendDone(const base::TimeDelta& sleep_duration) override; + + // chromeos::SessionManagerClient::Observer overrides. + void ScreenIsLocked() override; + void ScreenIsUnlocked() override; + + // Is the screen currently locked? + bool screen_locked_; + + // Have the lock screen animations completed? + bool waiting_for_lock_screen_animations_; + + // If set, called when the lock screen animations have completed to confirm + // that the system is ready to be suspended. + base::Closure screen_lock_callback_; + + private: + DISALLOW_COPY_AND_ASSIGN(PowerEventObserver); +}; + +} // namespace chromeos + +#endif // ASH_SYSTEM_CHROMEOS_POWER_POWER_EVENT_OBSERVER_H_
diff --git a/ash/system/chromeos/power/power_event_observer_unittest.cc b/ash/system/chromeos/power/power_event_observer_unittest.cc new file mode 100644 index 0000000..5d0b79f --- /dev/null +++ b/ash/system/chromeos/power/power_event_observer_unittest.cc
@@ -0,0 +1,163 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/power/power_event_observer.h" + +#include <memory> + +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "base/time/time.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" +#include "ui/compositor/compositor.h" + +namespace ash { + +class PowerEventObserverTest : public test::AshTestBase { + public: + PowerEventObserverTest() {} + ~PowerEventObserverTest() override {} + + // test::AshTestBase::SetUp() overrides: + void SetUp() override { + test::AshTestBase::SetUp(); + observer_.reset(new PowerEventObserver()); + } + + void TearDown() override { + observer_.reset(); + test::AshTestBase::TearDown(); + } + + protected: + int GetNumVisibleCompositors() { + int result = 0; + for (auto* window : Shell::GetAllRootWindows()) { + if (window->GetHost()->compositor()->IsVisible()) + ++result; + } + + return result; + } + + std::unique_ptr<PowerEventObserver> observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(PowerEventObserverTest); +}; + +TEST_F(PowerEventObserverTest, LockBeforeSuspend) { + chromeos::PowerManagerClient* client = + chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); + ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); + + // Check that the observer requests a suspend-readiness callback when it hears + // that the system is about to suspend. + test::TestSessionStateDelegate::SetCanLockScreen(true); + SetShouldLockScreenAutomatically(true); + observer_->SuspendImminent(); + EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks()); + + // It should run the callback when it hears that the screen is locked and the + // lock screen animations have completed. + observer_->ScreenIsLocked(); + observer_->OnLockAnimationsComplete(); + EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); + + // If the system is already locked, no callback should be requested. + observer_->SuspendDone(base::TimeDelta()); + observer_->ScreenIsUnlocked(); + observer_->ScreenIsLocked(); + observer_->OnLockAnimationsComplete(); + observer_->SuspendImminent(); + EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); + + // It also shouldn't request a callback if it isn't instructed to lock the + // screen. + observer_->SuspendDone(base::TimeDelta()); + SetShouldLockScreenAutomatically(false); + observer_->SuspendImminent(); + EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); +} + +TEST_F(PowerEventObserverTest, SetInvisibleBeforeSuspend) { + // Tests that all the Compositors are marked invisible before a suspend + // request when the screen is not supposed to be locked before a suspend. + EXPECT_EQ(1, GetNumVisibleCompositors()); + + observer_->SuspendImminent(); + EXPECT_EQ(0, GetNumVisibleCompositors()); + observer_->SuspendDone(base::TimeDelta()); + + // Tests that all the Compositors are marked invisible _after_ the screen lock + // animations have completed. + test::TestSessionStateDelegate::SetCanLockScreen(true); + SetShouldLockScreenAutomatically(true); + + observer_->SuspendImminent(); + EXPECT_EQ(1, GetNumVisibleCompositors()); + + observer_->ScreenIsLocked(); + EXPECT_EQ(1, GetNumVisibleCompositors()); + + observer_->OnLockAnimationsComplete(); + EXPECT_EQ(0, GetNumVisibleCompositors()); + + observer_->SuspendDone(base::TimeDelta()); + EXPECT_EQ(1, GetNumVisibleCompositors()); +} + +TEST_F(PowerEventObserverTest, CanceledSuspend) { + // Tests that the Compositors are not marked invisible if a suspend is + // canceled or the system resumes before the lock screen is ready. + test::TestSessionStateDelegate::SetCanLockScreen(true); + SetShouldLockScreenAutomatically(true); + observer_->SuspendImminent(); + EXPECT_EQ(1, GetNumVisibleCompositors()); + + observer_->SuspendDone(base::TimeDelta()); + observer_->ScreenIsLocked(); + observer_->OnLockAnimationsComplete(); + EXPECT_EQ(1, GetNumVisibleCompositors()); +} + +TEST_F(PowerEventObserverTest, DelayResuspendForLockAnimations) { + // Tests that the following order of events is handled correctly: + // + // - A suspend request is started. + // - The screen is locked. + // - The suspend request is canceled. + // - Another suspend request is started. + // - The screen lock animations complete. + // + // In this case, the observer should block the second suspend request until + // the animations have completed. + test::TestSessionStateDelegate::SetCanLockScreen(true); + SetShouldLockScreenAutomatically(true); + + chromeos::PowerManagerClient* client = + chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); + observer_->SuspendImminent(); + EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks()); + + observer_->ScreenIsLocked(); + observer_->SuspendDone(base::TimeDelta()); + observer_->SuspendImminent(); + + // The expected number of suspend readiness callbacks is 2 because the + // observer has not run the callback that it got from the first suspend + // request. The real PowerManagerClient would reset its internal counter in + // this situation but the stub client is not that smart. + EXPECT_EQ(2, client->GetNumPendingSuspendReadinessCallbacks()); + + observer_->OnLockAnimationsComplete(); + EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks()); + EXPECT_EQ(0, GetNumVisibleCompositors()); +} + +} // namespace ash
diff --git a/ash/system/chromeos/power/tablet_power_button_controller.cc b/ash/system/chromeos/power/tablet_power_button_controller.cc new file mode 100644 index 0000000..672e54c --- /dev/null +++ b/ash/system/chromeos/power/tablet_power_button_controller.cc
@@ -0,0 +1,265 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/power/tablet_power_button_controller.h" + +#include "ash/common/accessibility_delegate.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/shell_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/shell.h" +#include "ash/wm/lock_state_controller.h" +#include "base/time/default_tick_clock.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "ui/events/devices/input_device_manager.h" +#include "ui/events/devices/stylus_state.h" +#include "ui/events/event.h" + +namespace ash { + +namespace { + +// Amount of time the power button must be held to start the pre-shutdown +// animation when in tablet mode. This differs depending on whether the screen +// is on or off when the power button is initially pressed. +constexpr int kShutdownWhenScreenOnTimeoutMs = 500; +// TODO(derat): This is currently set to a high value to work around delays in +// powerd's reports of button-up events when the preceding button-down event +// turns the display on. Set it to a lower value once powerd no longer blocks on +// asking Chrome to turn the display on: http://crbug.com/685734 +constexpr int kShutdownWhenScreenOffTimeoutMs = 2000; + +// Amount of time since last SuspendDone() that power button event needs to be +// ignored. +constexpr int kIgnorePowerButtonAfterResumeMs = 2000; + +// Ignore button-up events occurring within this many milliseconds of the +// previous button-up event. This prevents us from falling behind if the power +// button is pressed repeatedly. +constexpr int kIgnoreRepeatedButtonUpMs = 500; + +// Returns true if device is a convertible/tablet device, otherwise false. +bool IsTabletModeSupported() { + MaximizeModeController* maximize_mode_controller = + WmShell::Get()->maximize_mode_controller(); + return maximize_mode_controller && + maximize_mode_controller->CanEnterMaximizeMode(); +} + +// Returns true if device is currently in tablet/maximize mode, otherwise false. +bool IsTabletModeActive() { + MaximizeModeController* maximize_mode_controller = + WmShell::Get()->maximize_mode_controller(); + return maximize_mode_controller && + maximize_mode_controller->IsMaximizeModeWindowManagerEnabled(); +} + +} // namespace + +TabletPowerButtonController::TestApi::TestApi( + TabletPowerButtonController* controller) + : controller_(controller) {} + +TabletPowerButtonController::TestApi::~TestApi() {} + +bool TabletPowerButtonController::TestApi::ShutdownTimerIsRunning() const { + return controller_->shutdown_timer_.IsRunning(); +} + +void TabletPowerButtonController::TestApi::TriggerShutdownTimeout() { + DCHECK(ShutdownTimerIsRunning()); + controller_->OnShutdownTimeout(); + controller_->shutdown_timer_.Stop(); +} + +TabletPowerButtonController::TabletPowerButtonController( + LockStateController* controller) + : tick_clock_(new base::DefaultTickClock()), + force_off_on_button_up_(true), + controller_(controller), + weak_ptr_factory_(this) { + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( + this); + WmShell::Get()->AddShellObserver(this); + // TODO(mash): Provide a way for this class to observe stylus events: + // http://crbug.com/682460 + if (ui::InputDeviceManager::HasInstance()) + ui::InputDeviceManager::GetInstance()->AddObserver(this); + Shell::GetInstance()->PrependPreTargetHandler(this); + + GetInitialBacklightsForcedOff(); +} + +TabletPowerButtonController::~TabletPowerButtonController() { + Shell::GetInstance()->RemovePreTargetHandler(this); + if (ui::InputDeviceManager::HasInstance()) + ui::InputDeviceManager::GetInstance()->RemoveObserver(this); + WmShell::Get()->RemoveShellObserver(this); + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( + this); +} + +bool TabletPowerButtonController::ShouldHandlePowerButtonEvents() const { + return IsTabletModeSupported(); +} + +void TabletPowerButtonController::OnPowerButtonEvent( + bool down, + const base::TimeTicks& timestamp) { + if (down) { + force_off_on_button_up_ = true; + // When the system resumes in response to the power button being pressed, + // Chrome receives powerd's SuspendDone signal and notification that the + // backlight has been turned back on before seeing the power button events + // that woke the system. Avoid forcing off display just after resuming to + // ensure that we don't turn the display off in response to the events. + if (timestamp - last_resume_time_ <= + base::TimeDelta::FromMilliseconds(kIgnorePowerButtonAfterResumeMs)) { + force_off_on_button_up_ = false; + } + screen_off_when_power_button_down_ = brightness_level_is_zero_; + SetDisplayForcedOff(false); + StartShutdownTimer(); + } else { + // When power button is released, cancel shutdown animation whenever it is + // still cancellable. + if (controller_->CanCancelShutdownAnimation()) + controller_->CancelShutdownAnimation(); + + const base::TimeTicks previous_up_time = last_button_up_time_; + last_button_up_time_ = tick_clock_->NowTicks(); + // Ignore the event if it comes too soon after the last one. + if (timestamp - previous_up_time <= + base::TimeDelta::FromMilliseconds(kIgnoreRepeatedButtonUpMs)) { + shutdown_timer_.Stop(); + return; + } + + if (shutdown_timer_.IsRunning()) { + shutdown_timer_.Stop(); + if (!screen_off_when_power_button_down_ && force_off_on_button_up_) { + SetDisplayForcedOff(true); + LockScreenIfRequired(); + } + } + } +} + +void TabletPowerButtonController::PowerManagerRestarted() { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->SetBacklightsForcedOff(backlights_forced_off_); +} + +void TabletPowerButtonController::BrightnessChanged(int level, + bool user_initiated) { + brightness_level_is_zero_ = level == 0; +} + +void TabletPowerButtonController::SuspendDone( + const base::TimeDelta& sleep_duration) { + last_resume_time_ = tick_clock_->NowTicks(); +} + +void TabletPowerButtonController::OnMaximizeModeStarted() { + shutdown_timer_.Stop(); + if (controller_->CanCancelShutdownAnimation()) + controller_->CancelShutdownAnimation(); +} + +void TabletPowerButtonController::OnMaximizeModeEnded() { + shutdown_timer_.Stop(); + if (controller_->CanCancelShutdownAnimation()) + controller_->CancelShutdownAnimation(); +} + +void TabletPowerButtonController::OnKeyEvent(ui::KeyEvent* event) { + // Ignore key events generated by the power button since power button activity + // is already handled by OnPowerButtonEvent(). + if (event->key_code() == ui::VKEY_POWER) + return; + + if (!IsTabletModeActive() && backlights_forced_off_) + SetDisplayForcedOff(false); +} + +void TabletPowerButtonController::OnMouseEvent(ui::MouseEvent* event) { + if (event->flags() & ui::EF_IS_SYNTHESIZED) + return; + + if (!IsTabletModeActive() && backlights_forced_off_) + SetDisplayForcedOff(false); +} + +void TabletPowerButtonController::OnStylusStateChanged(ui::StylusState state) { + if (IsTabletModeSupported() && state == ui::StylusState::REMOVED && + backlights_forced_off_) { + SetDisplayForcedOff(false); + } +} + +void TabletPowerButtonController::SetTickClockForTesting( + std::unique_ptr<base::TickClock> tick_clock) { + DCHECK(tick_clock); + tick_clock_ = std::move(tick_clock); +} + +void TabletPowerButtonController::SetDisplayForcedOff(bool forced_off) { + if (backlights_forced_off_ == forced_off) + return; + + // Set the display and keyboard backlights (if present) to |forced_off|. + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->SetBacklightsForcedOff(forced_off); + backlights_forced_off_ = forced_off; + + ShellDelegate* delegate = WmShell::Get()->delegate(); + delegate->SetTouchscreenEnabledInPrefs(!forced_off, + true /* use_local_state */); + delegate->UpdateTouchscreenStatusFromPrefs(); + + // Send an a11y alert. + WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert( + forced_off ? A11Y_ALERT_SCREEN_OFF : A11Y_ALERT_SCREEN_ON); +} + +void TabletPowerButtonController::GetInitialBacklightsForcedOff() { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->GetBacklightsForcedOff(base::Bind( + &TabletPowerButtonController::OnGotInitialBacklightsForcedOff, + weak_ptr_factory_.GetWeakPtr())); +} + +void TabletPowerButtonController::OnGotInitialBacklightsForcedOff( + bool is_forced_off) { + backlights_forced_off_ = is_forced_off; +} + +void TabletPowerButtonController::StartShutdownTimer() { + base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( + screen_off_when_power_button_down_ ? kShutdownWhenScreenOffTimeoutMs + : kShutdownWhenScreenOnTimeoutMs); + shutdown_timer_.Start(FROM_HERE, timeout, this, + &TabletPowerButtonController::OnShutdownTimeout); +} + +void TabletPowerButtonController::OnShutdownTimeout() { + controller_->StartShutdownAnimation(); +} + +void TabletPowerButtonController::LockScreenIfRequired() { + SessionStateDelegate* session_state_delegate = + WmShell::Get()->GetSessionStateDelegate(); + if (session_state_delegate->ShouldLockScreenAutomatically() && + session_state_delegate->CanLockScreen() && + !session_state_delegate->IsUserSessionBlocked() && + !controller_->LockRequested()) { + session_state_delegate->LockScreen(); + } +} + +} // namespace ash
diff --git a/ash/system/chromeos/power/tablet_power_button_controller.h b/ash/system/chromeos/power/tablet_power_button_controller.h new file mode 100644 index 0000000..2a90377 --- /dev/null +++ b/ash/system/chromeos/power/tablet_power_button_controller.h
@@ -0,0 +1,139 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHROMEOS_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_ +#define ASH_SYSTEM_CHROMEOS_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_ + +#include <memory> + +#include "ash/ash_export.h" +#include "ash/common/shell_observer.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/time/tick_clock.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "chromeos/dbus/power_manager_client.h" +#include "ui/events/devices/input_device_event_observer.h" +#include "ui/events/event_handler.h" + +namespace ash { + +class LockStateController; + +// Handles power button events on convertible/tablet device. This class is +// instantiated and used in PowerButtonController. +class ASH_EXPORT TabletPowerButtonController + : public chromeos::PowerManagerClient::Observer, + public ShellObserver, + public ui::EventHandler, + public ui::InputDeviceEventObserver { + public: + // Helper class used by tablet power button tests to access internal state. + class ASH_EXPORT TestApi { + public: + explicit TestApi(TabletPowerButtonController* controller); + ~TestApi(); + + // Returns true when |shutdown_timer_| is running. + bool ShutdownTimerIsRunning() const; + + // Emulates |shutdown_timer_| timeout. + void TriggerShutdownTimeout(); + + private: + TabletPowerButtonController* controller_; // Not owned. + + DISALLOW_COPY_AND_ASSIGN(TestApi); + }; + + explicit TabletPowerButtonController(LockStateController* controller); + ~TabletPowerButtonController() override; + + // Returns true if power button events should be handled by this class instead + // of PowerButtonController. + bool ShouldHandlePowerButtonEvents() const; + + // Handles a power button event. + void OnPowerButtonEvent(bool down, const base::TimeTicks& timestamp); + + // Overridden from chromeos::PowerManagerClient::Observer: + void PowerManagerRestarted() override; + void BrightnessChanged(int level, bool user_initiated) override; + void SuspendDone(const base::TimeDelta& sleep_duration) override; + + // Overridden from ShellObserver: + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + + // Overridden from ui::EventHandler: + void OnKeyEvent(ui::KeyEvent* event) override; + void OnMouseEvent(ui::MouseEvent* event) override; + + // Overridden from ui::InputDeviceObserver: + void OnStylusStateChanged(ui::StylusState state) override; + + // Overrides the tick clock used by |this| for testing. + void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); + + private: + // Updates the power manager's backlights-forced-off state and enables or + // disables the touchscreen. No-op if |backlights_forced_off_| already equals + // |forced_off|. + void SetDisplayForcedOff(bool forced_off); + + // Sends a request to powerd to get the backlights forced off state so that + // |backlights_forced_off_| can be initialized. + void GetInitialBacklightsForcedOff(); + + // Initializes |backlights_forced_off_|. + void OnGotInitialBacklightsForcedOff(bool is_forced_off); + + // Starts |shutdown_timer_| when the power button is pressed while in + // tablet mode. + void StartShutdownTimer(); + + // Called by |shutdown_timer_| to start the pre-shutdown animation. + void OnShutdownTimeout(); + + // Locks the screen if the "require password to wake from sleep" pref is set + // and locking is possible. + void LockScreenIfRequired(); + + // True if the brightness level is currently set to off. + bool brightness_level_is_zero_ = false; + + // Current forced-off state of backlights. + bool backlights_forced_off_ = false; + + // True if the screen was off when the power button was pressed. + bool screen_off_when_power_button_down_ = false; + + // Time source for performed action times. + std::unique_ptr<base::TickClock> tick_clock_; + + // Saves the most recent timestamp that powerd is resuming from suspend, + // updated in SuspendDone(). + base::TimeTicks last_resume_time_; + + // Saves the most recent timestamp that power button is released. + base::TimeTicks last_button_up_time_; + + // True if power button released should force off display. + bool force_off_on_button_up_; + + // Started when the tablet power button is pressed and stopped when it's + // released. Runs OnShutdownTimeout() to start shutdown. + base::OneShotTimer shutdown_timer_; + + LockStateController* controller_; // Not owned. + + base::WeakPtrFactory<TabletPowerButtonController> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonController); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_
diff --git a/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc b/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc new file mode 100644 index 0000000..8a2df30 --- /dev/null +++ b/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
@@ -0,0 +1,481 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/power/tablet_power_button_controller.h" + +#include <memory> + +#include "ash/common/ash_switches.h" +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/lock_state_controller_test_api.h" +#include "ash/test/test_shell_delegate.h" +#include "ash/wm/lock_state_controller.h" +#include "ash/wm/power_button_controller.h" +#include "base/command_line.h" +#include "base/compiler_specific.h" +#include "base/memory/ptr_util.h" +#include "base/run_loop.h" +#include "base/test/simple_test_tick_clock.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_power_manager_client.h" +#include "ui/events/event.h" +#include "ui/events/test/event_generator.h" + +namespace ash { +namespace test { + +namespace { + +// A non-zero brightness used for test. +constexpr int kNonZeroBrightness = 10; + +void CopyResult(bool* dest, bool src) { + *dest = src; +} + +} // namespace + +class TabletPowerButtonControllerTest : public AshTestBase { + public: + TabletPowerButtonControllerTest() {} + ~TabletPowerButtonControllerTest() override {} + + void SetUp() override { + // This also initializes DBusThreadManager. + std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter = + chromeos::DBusThreadManager::GetSetterForTesting(); + power_manager_client_ = new chromeos::FakePowerManagerClient(); + dbus_setter->SetPowerManagerClient(base::WrapUnique(power_manager_client_)); + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kAshEnableTouchView); + AshTestBase::SetUp(); + + lock_state_controller_ = Shell::GetInstance()->lock_state_controller(); + tablet_controller_ = Shell::GetInstance() + ->power_button_controller() + ->tablet_power_button_controller_for_test(); + test_api_ = base::MakeUnique<TabletPowerButtonController::TestApi>( + tablet_controller_); + lock_state_test_api_ = + base::MakeUnique<LockStateControllerTestApi>(lock_state_controller_); + tick_clock_ = new base::SimpleTestTickClock; + tablet_controller_->SetTickClockForTesting( + std::unique_ptr<base::TickClock>(tick_clock_)); + shell_delegate_ = + static_cast<TestShellDelegate*>(WmShell::Get()->delegate()); + generator_ = &AshTestBase::GetEventGenerator(); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_FALSE(GetBacklightsForcedOff()); + } + + void TearDown() override { + generator_ = nullptr; + const bool is_mash = WmShell::Get()->IsRunningInMash(); + AshTestBase::TearDown(); + // Mash shuts down dbus after each test. + if (!is_mash) + chromeos::DBusThreadManager::Shutdown(); + } + + protected: + void PressPowerButton() { + tablet_controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); + } + + void ReleasePowerButton() { + tablet_controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); + } + + void UnlockScreen() { + lock_state_controller_->OnLockStateChanged(false); + WmShell::Get()->GetSessionStateDelegate()->UnlockScreen(); + } + + void Initialize(LoginStatus status) { + lock_state_controller_->OnLoginStateChanged(status); + SetUserLoggedIn(status != LoginStatus::NOT_LOGGED_IN); + lock_state_controller_->OnLockStateChanged(false); + } + + void EnableMaximizeMode(bool enabled) { + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + enabled); + } + + bool GetLockedState() { + return WmShell::Get()->GetSessionStateDelegate()->IsScreenLocked(); + } + + bool GetBacklightsForcedOff() WARN_UNUSED_RESULT { + bool forced_off = false; + power_manager_client_->GetBacklightsForcedOff( + base::Bind(&CopyResult, base::Unretained(&forced_off))); + base::RunLoop().RunUntilIdle(); + return forced_off; + } + + // Ownership is passed on to chromeos::DBusThreadManager. + chromeos::FakePowerManagerClient* power_manager_client_; + + LockStateController* lock_state_controller_; // Not owned. + TabletPowerButtonController* tablet_controller_; // Not owned. + std::unique_ptr<TabletPowerButtonController::TestApi> test_api_; + std::unique_ptr<LockStateControllerTestApi> lock_state_test_api_; + base::SimpleTestTickClock* tick_clock_; // Not owned. + TestShellDelegate* shell_delegate_; // Not owned. + ui::test::EventGenerator* generator_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonControllerTest); +}; + +TEST_F(TabletPowerButtonControllerTest, LockScreenIfRequired) { + Initialize(LoginStatus::USER); + SetShouldLockScreenAutomatically(true); + EXPECT_FALSE(GetLockedState()); + + // On User logged in status, power-button-press-release should lock screen if + // automatic screen-locking was requested. + PressPowerButton(); + ReleasePowerButton(); + EXPECT_TRUE(GetLockedState()); + + // On locked state, power-button-press-release should do nothing. + PressPowerButton(); + ReleasePowerButton(); + EXPECT_TRUE(GetLockedState()); + + // Unlock the sceen. + UnlockScreen(); + ASSERT_FALSE(GetLockedState()); + + // power-button-press-release should not lock the screen if automatic + // screen-locking wasn't requested. + SetShouldLockScreenAutomatically(false); + PressPowerButton(); + ReleasePowerButton(); + EXPECT_FALSE(GetLockedState()); +} + +// Tests that shutdown animation is not started if the power button is released +// quickly. +TEST_F(TabletPowerButtonControllerTest, + ReleasePowerButtonBeforeStartingShutdownAnimation) { + PressPowerButton(); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + EXPECT_FALSE(GetBacklightsForcedOff()); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + EXPECT_TRUE(GetBacklightsForcedOff()); + + PressPowerButton(); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + EXPECT_FALSE(GetBacklightsForcedOff()); + ReleasePowerButton(); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + EXPECT_FALSE(GetBacklightsForcedOff()); +} + +// Tests that the shutdown animation is started when the power button is +// released after the timer fires. +TEST_F(TabletPowerButtonControllerTest, + ReleasePowerButtonDuringShutdownAnimation) { + PressPowerButton(); + test_api_->TriggerShutdownTimeout(); + EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); + ReleasePowerButton(); + EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Test again when backlights is forced off. + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + + PressPowerButton(); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_FALSE(GetBacklightsForcedOff()); + test_api_->TriggerShutdownTimeout(); + EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); + ReleasePowerButton(); + EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); + EXPECT_FALSE(GetBacklightsForcedOff()); +} + +// Tests tapping power button when screen is idle off. +TEST_F(TabletPowerButtonControllerTest, TappingPowerButtonWhenScreenIsIdleOff) { + power_manager_client_->SendBrightnessChanged(0, false); + PressPowerButton(); + EXPECT_FALSE(GetBacklightsForcedOff()); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + ReleasePowerButton(); + EXPECT_FALSE(GetBacklightsForcedOff()); +} + +// Tests tapping power button when device is suspended without backlights forced +// off. +TEST_F(TabletPowerButtonControllerTest, + TappingPowerButtonWhenSuspendedWithoutBacklightsForcedOff) { + power_manager_client_->SendSuspendImminent(); + power_manager_client_->SendBrightnessChanged(0, false); + // There is a power button pressed here, but PowerButtonEvent is sent later. + power_manager_client_->SendSuspendDone(); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + + // Send the power button event after a short delay and check that backlights + // are not forced off. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(500)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Send the power button event after a longer delay and check that backlights + // are forced off. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1600)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + EXPECT_TRUE(GetBacklightsForcedOff()); +} + +// Tests tapping power button when device is suspended with backlights forced +// off. +TEST_F(TabletPowerButtonControllerTest, + TappingPowerButtonWhenSuspendedWithBacklightsForcedOff) { + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + power_manager_client_->SendSuspendImminent(); + // There is a power button pressed here, but PowerButtonEvent is sent later. + // Because of backlights forced off, resuming system will not restore + // brightness. + power_manager_client_->SendSuspendDone(); + + // Send the power button event after a short delay and check that backlights + // are not forced off. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(500)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Send the power button event after a longer delay and check that backlights + // are forced off. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1600)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + EXPECT_TRUE(GetBacklightsForcedOff()); +} + +// For convertible device working on laptop mode, tests keyboard/mouse event +// when screen is off. +TEST_F(TabletPowerButtonControllerTest, ConvertibleOnLaptopMode) { + EnableMaximizeMode(false); + + // KeyEvent should SetBacklightsForcedOff(false). + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + generator_->PressKey(ui::VKEY_L, ui::EF_NONE); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Regular mouse event should SetBacklightsForcedOff(false). + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + generator_->MoveMouseBy(1, 1); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Synthesized mouse event should not SetBacklightsForcedOff(false). + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + generator_->set_flags(ui::EF_IS_SYNTHESIZED); + generator_->MoveMouseBy(1, 1); + generator_->set_flags(ui::EF_NONE); + EXPECT_TRUE(GetBacklightsForcedOff()); +} + +// For convertible device working on tablet mode, keyboard/mouse event should +// not SetBacklightsForcedOff(false) when screen is off. +TEST_F(TabletPowerButtonControllerTest, ConvertibleOnMaximizeMode) { + EnableMaximizeMode(true); + + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + generator_->PressKey(ui::VKEY_L, ui::EF_NONE); + EXPECT_TRUE(GetBacklightsForcedOff()); + + generator_->MoveMouseBy(1, 1); + EXPECT_TRUE(GetBacklightsForcedOff()); +} + +// Tests that a single set of power button pressed-and-released operation should +// cause only one SetBacklightsForcedOff call. +TEST_F(TabletPowerButtonControllerTest, IgnorePowerOnKeyEvent) { + ui::KeyEvent power_key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_POWER, + ui::EF_NONE); + ui::KeyEvent power_key_released(ui::ET_KEY_RELEASED, ui::VKEY_POWER, + ui::EF_NONE); + + // There are two |power_key_pressed| events and |power_key_released| events + // generated for each pressing and releasing, and multiple repeating pressed + // events depending on holding. + tablet_controller_->OnKeyEvent(&power_key_pressed); + tablet_controller_->OnKeyEvent(&power_key_pressed); + PressPowerButton(); + tablet_controller_->OnKeyEvent(&power_key_pressed); + tablet_controller_->OnKeyEvent(&power_key_pressed); + tablet_controller_->OnKeyEvent(&power_key_pressed); + ReleasePowerButton(); + tablet_controller_->OnKeyEvent(&power_key_released); + tablet_controller_->OnKeyEvent(&power_key_released); + EXPECT_EQ(1, power_manager_client_->num_set_backlights_forced_off_calls()); +} + +// Tests that under (1) tablet power button pressed/released, (2) keyboard/mouse +// events on laptop mode when screen is off, requesting/stopping backlights +// forced off should also set corresponding touch screen state in local pref. +TEST_F(TabletPowerButtonControllerTest, TouchScreenState) { + // Tests tablet power button. + EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_FALSE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); + + PressPowerButton(); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + ReleasePowerButton(); + EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); + + EnableMaximizeMode(false); + // KeyEvent on laptop mode when screen is off. + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + EXPECT_FALSE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); + generator_->PressKey(ui::VKEY_L, ui::EF_NONE); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); + + // MouseEvent on laptop mode when screen is off. + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + EXPECT_FALSE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); + generator_->MoveMouseBy(1, 1); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); +} + +// When user switches convertible device between laptop mode and tablet mode, +// power button may be pressed and held, which may cause unwanted shutdown. +TEST_F(TabletPowerButtonControllerTest, + EnterOrLeaveMaximizeModeWhilePressingPowerButton) { + Initialize(LoginStatus::USER); + SetShouldLockScreenAutomatically(true); + EXPECT_FALSE(GetLockedState()); + + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + tablet_controller_->OnMaximizeModeStarted(); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1500)); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(GetLockedState()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + test_api_->TriggerShutdownTimeout(); + EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); + tablet_controller_->OnMaximizeModeStarted(); + EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(2500)); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(GetLockedState()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); + tablet_controller_->OnMaximizeModeEnded(); + EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(3500)); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(GetLockedState()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + test_api_->TriggerShutdownTimeout(); + EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); + tablet_controller_->OnMaximizeModeEnded(); + EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(4500)); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(GetLockedState()); + EXPECT_FALSE(GetBacklightsForcedOff()); +} + +// Tests that repeated power button releases are ignored (crbug.com/675291). +TEST_F(TabletPowerButtonControllerTest, IgnoreRepeatedPowerButtonReleases) { + // Advance a long duration from initialized last resume time in + // |tablet_controller_| to avoid cross interference. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(2000)); + + // Set backlights forced off for starting point. + PressPowerButton(); + ReleasePowerButton(); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); + + // Test that a pressing-releasing operation after a short duration, backlights + // forced off is stopped since we don't drop request for power button pressed. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Test that after another short duration, backlights will not be forced off + // since this immediately following forcing off request needs to be dropped. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + EXPECT_FALSE(GetBacklightsForcedOff()); + + // Test that after another long duration, backlights should be forced off. + tick_clock_->Advance(base::TimeDelta::FromMilliseconds(800)); + power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); + power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); + power_manager_client_->SendBrightnessChanged(0, false); + EXPECT_TRUE(GetBacklightsForcedOff()); +} + +} // namespace test +} // namespace ash
diff --git a/ash/system/chromeos/power/video_activity_notifier.cc b/ash/system/chromeos/power/video_activity_notifier.cc new file mode 100644 index 0000000..3c19426 --- /dev/null +++ b/ash/system/chromeos/power/video_activity_notifier.cc
@@ -0,0 +1,83 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/power/video_activity_notifier.h" + +#include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm_shell.h" +#include "ash/shell.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" + +namespace ash { +namespace { + +// Minimum number of seconds between repeated notifications of the same state. +// This should be less than powerd's timeout for determining whether video is +// still active for the purposes of controlling the keyboard backlight. +const int kNotifyIntervalSec = 5; + +} // namespace + +VideoActivityNotifier::VideoActivityNotifier(VideoDetector* detector) + : detector_(detector), + video_state_(detector->state()), + screen_is_locked_( + Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) { + detector_->AddObserver(this); + WmShell::Get()->AddShellObserver(this); + + MaybeNotifyPowerManager(); + UpdateTimer(); +} + +VideoActivityNotifier::~VideoActivityNotifier() { + WmShell::Get()->RemoveShellObserver(this); + detector_->RemoveObserver(this); +} + +void VideoActivityNotifier::OnVideoStateChanged(VideoDetector::State state) { + if (video_state_ != state) { + video_state_ = state; + MaybeNotifyPowerManager(); + UpdateTimer(); + } +} + +void VideoActivityNotifier::OnLockStateChanged(bool locked) { + if (screen_is_locked_ != locked) { + screen_is_locked_ = locked; + MaybeNotifyPowerManager(); + UpdateTimer(); + } +} + +bool VideoActivityNotifier::TriggerTimeoutForTest() { + if (!notify_timer_.IsRunning()) + return false; + + MaybeNotifyPowerManager(); + return true; +} + +void VideoActivityNotifier::UpdateTimer() { + if (!should_notify_power_manager()) { + notify_timer_.Stop(); + } else { + notify_timer_.Start(FROM_HERE, + base::TimeDelta::FromSeconds(kNotifyIntervalSec), this, + &VideoActivityNotifier::MaybeNotifyPowerManager); + } +} + +void VideoActivityNotifier::MaybeNotifyPowerManager() { + if (should_notify_power_manager()) { + chromeos::DBusThreadManager::Get() + ->GetPowerManagerClient() + ->NotifyVideoActivity(video_state_ == + VideoDetector::State::PLAYING_FULLSCREEN); + } +} + +} // namespace ash
diff --git a/ash/system/chromeos/power/video_activity_notifier.h b/ash/system/chromeos/power/video_activity_notifier.h new file mode 100644 index 0000000..bf941fd --- /dev/null +++ b/ash/system/chromeos/power/video_activity_notifier.h
@@ -0,0 +1,63 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHROMEOS_POWER_VIDEO_ACTIVITY_NOTIFIER_H_ +#define ASH_SYSTEM_CHROMEOS_POWER_VIDEO_ACTIVITY_NOTIFIER_H_ + +#include "ash/ash_export.h" +#include "ash/wm/video_detector.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/time/time.h" + +namespace ash { + +// Notifies the power manager when a video is playing. +class ASH_EXPORT VideoActivityNotifier : public VideoDetector::Observer, + public ShellObserver { + public: + explicit VideoActivityNotifier(VideoDetector* detector); + ~VideoActivityNotifier() override; + + // VideoDetector::Observer implementation. + void OnVideoStateChanged(VideoDetector::State state) override; + + // ShellObserver implementation. + void OnLockStateChanged(bool locked) override; + + // If |notify_timer_| is running, calls MaybeNotifyPowerManager() and returns + // true. Returns false otherwise. + bool TriggerTimeoutForTest() WARN_UNUSED_RESULT; + + private: + bool should_notify_power_manager() { + return video_state_ != VideoDetector::State::NOT_PLAYING && + !screen_is_locked_; + } + + // Starts or stops |notify_timer_| as needed. + void UpdateTimer(); + + // Notifies powerd about video activity if should_notify_power_manager() is + // true. + void MaybeNotifyPowerManager(); + + VideoDetector* detector_; // not owned + + // Most-recently-observed video state. + VideoDetector::State video_state_; + + // True if the screen is currently locked. + bool screen_is_locked_; + + // Periodically calls MaybeNotifyPowerManager() while + // should_notify_power_manager() is true. + base::RepeatingTimer notify_timer_; + + DISALLOW_COPY_AND_ASSIGN(VideoActivityNotifier); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_POWER_VIDEO_ACTIVITY_NOTIFIER_H_
diff --git a/ash/system/chromeos/power/video_activity_notifier_unittest.cc b/ash/system/chromeos/power/video_activity_notifier_unittest.cc new file mode 100644 index 0000000..eaf9fc8 --- /dev/null +++ b/ash/system/chromeos/power/video_activity_notifier_unittest.cc
@@ -0,0 +1,113 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/power/video_activity_notifier.h" + +#include <memory> + +#include "ash/test/ash_test_base.h" +#include "ash/wm/video_detector.h" +#include "base/macros.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_power_manager_client.h" + +namespace ash { + +class VideoActivityNotifierTest : public test::AshTestBase { + public: + VideoActivityNotifierTest() {} + ~VideoActivityNotifierTest() override {} + + void SetUp() override { + test::AshTestBase::SetUp(); + power_client_ = static_cast<chromeos::FakePowerManagerClient*>( + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()); + detector_.reset(new VideoDetector()); + notifier_.reset(new VideoActivityNotifier(detector_.get())); + } + + void TearDown() override { + notifier_.reset(); + detector_.reset(); + test::AshTestBase::TearDown(); + } + + protected: + chromeos::FakePowerManagerClient* power_client_; // Not owned. + + std::unique_ptr<VideoDetector> detector_; + std::unique_ptr<VideoActivityNotifier> notifier_; + + DISALLOW_COPY_AND_ASSIGN(VideoActivityNotifierTest); +}; + +// Test that powerd is notified immediately when video changes to a new playing +// state or the screen is unlocked. +TEST_F(VideoActivityNotifierTest, NotifyImmediatelyOnStateChange) { + EXPECT_FALSE(power_client_->have_video_activity_report()); + + notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); + EXPECT_FALSE(power_client_->PopVideoActivityReport()); + + notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_FULLSCREEN); + EXPECT_TRUE(power_client_->PopVideoActivityReport()); + + notifier_->OnLockStateChanged(true); + EXPECT_FALSE(power_client_->have_video_activity_report()); + + notifier_->OnLockStateChanged(false); + EXPECT_TRUE(power_client_->PopVideoActivityReport()); + + notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); + EXPECT_FALSE(power_client_->PopVideoActivityReport()); + + notifier_->OnVideoStateChanged(VideoDetector::State::NOT_PLAYING); + EXPECT_FALSE(power_client_->have_video_activity_report()); + + notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); + EXPECT_FALSE(power_client_->PopVideoActivityReport()); +} + +// Test that powerd is notified periodically while video is ongoing. +TEST_F(VideoActivityNotifierTest, NotifyPeriodically) { + // The timer shouldn't be running initially. + EXPECT_FALSE(notifier_->TriggerTimeoutForTest()); + + // The timer should start in response to windowed video. + notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); + EXPECT_FALSE(power_client_->PopVideoActivityReport()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + EXPECT_TRUE(notifier_->TriggerTimeoutForTest()); + EXPECT_FALSE(power_client_->PopVideoActivityReport()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + + // After fullscreen video starts, the timer should start reporting that + // instead. + notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_FULLSCREEN); + EXPECT_TRUE(power_client_->PopVideoActivityReport()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + EXPECT_TRUE(notifier_->TriggerTimeoutForTest()); + EXPECT_TRUE(power_client_->PopVideoActivityReport()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + + // Locking the screen should stop the timer. + notifier_->OnLockStateChanged(true); + EXPECT_FALSE(notifier_->TriggerTimeoutForTest()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + + // Unlocking it should restart the timer. + notifier_->OnLockStateChanged(false); + EXPECT_TRUE(power_client_->PopVideoActivityReport()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + EXPECT_TRUE(notifier_->TriggerTimeoutForTest()); + EXPECT_TRUE(power_client_->PopVideoActivityReport()); + EXPECT_FALSE(power_client_->have_video_activity_report()); + + // The timer should stop when video video. + notifier_->OnVideoStateChanged(VideoDetector::State::NOT_PLAYING); + EXPECT_FALSE(notifier_->TriggerTimeoutForTest()); + EXPECT_FALSE(power_client_->have_video_activity_report()); +} + +} // namespace ash
diff --git a/ash/system/chromeos/rotation/tray_rotation_lock.cc b/ash/system/chromeos/rotation/tray_rotation_lock.cc new file mode 100644 index 0000000..2a10c6ddb --- /dev/null +++ b/ash/system/chromeos/rotation/tray_rotation_lock.cc
@@ -0,0 +1,219 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/rotation/tray_rotation_lock.h" + +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/system/tray/tray_popup_item_style.h" +#include "ash/common/system/tray/tray_popup_utils.h" +#include "ash/common/system/tray/tri_view.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/display/screen_orientation_controller_chromeos.h" +#include "ash/resources/vector_icons/vector_icons.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/display/display.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" + +namespace ash { + +namespace { + +bool IsMaximizeModeWindowManagerEnabled() { + return WmShell::Get() + ->maximize_mode_controller() + ->IsMaximizeModeWindowManagerEnabled(); +} + +bool IsRotationLocked() { + return Shell::GetInstance() + ->screen_orientation_controller() + ->rotation_locked(); +} + +} // namespace + +namespace tray { + +class RotationLockDefaultView : public ActionableView, + public ShellObserver, + public ScreenOrientationController::Observer { + public: + explicit RotationLockDefaultView(SystemTrayItem* owner); + ~RotationLockDefaultView() override; + + private: + // Updates icon and label according to current rotation lock status. + void Update(); + + // Stop observing rotation lock status. + void StopObservingRotation(); + + // ActionableView: + void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + bool PerformAction(const ui::Event& event) override; + + // ShellObserver: + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + + // ScreenOrientationController::Obsever: + void OnRotationLockChanged(bool rotation_locked) override; + + views::ImageView* icon_; + views::Label* label_; + + DISALLOW_COPY_AND_ASSIGN(RotationLockDefaultView); +}; + +RotationLockDefaultView::RotationLockDefaultView(SystemTrayItem* owner) + : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), + icon_(TrayPopupUtils::CreateMainImageView()), + label_(TrayPopupUtils::CreateDefaultLabel()) { + SetLayoutManager(new views::FillLayout); + + TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); + AddChildView(tri_view); + + tri_view->AddView(TriView::Container::START, icon_); + tri_view->AddView(TriView::Container::CENTER, label_); + tri_view->SetContainerVisible(TriView::Container::END, false); + + Update(); + + SetInkDropMode(InkDropHostView::InkDropMode::ON); + + SetVisible(IsMaximizeModeWindowManagerEnabled()); + WmShell::Get()->AddShellObserver(this); + if (IsMaximizeModeWindowManagerEnabled()) + Shell::GetInstance()->screen_orientation_controller()->AddObserver(this); +} + +RotationLockDefaultView::~RotationLockDefaultView() { + StopObservingRotation(); + WmShell::Get()->RemoveShellObserver(this); +} + +void RotationLockDefaultView::Update() { + TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); + icon_->SetImage(gfx::CreateVectorIcon(IsRotationLocked() + ? kSystemMenuRotationLockLockedIcon + : kSystemMenuRotationLockAutoIcon, + kMenuIconSize, style.GetIconColor())); + + base::string16 label = l10n_util::GetStringUTF16( + IsRotationLocked() ? IDS_ASH_STATUS_TRAY_ROTATION_LOCK_LOCKED + : IDS_ASH_STATUS_TRAY_ROTATION_LOCK_AUTO); + label_->SetText(label); + style.SetupLabel(label_); + + Layout(); + SchedulePaint(); +} + +void RotationLockDefaultView::StopObservingRotation() { + ScreenOrientationController* controller = + Shell::GetInstance()->screen_orientation_controller(); + if (controller) + controller->RemoveObserver(this); +} + +void RotationLockDefaultView::GetAccessibleNodeData(ui::AXNodeData* node_data) { + ActionableView::GetAccessibleNodeData(node_data); + if (!label_->text().empty()) + node_data->SetName(label_->text()); +} + +bool RotationLockDefaultView::PerformAction(const ui::Event& event) { + Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( + !IsRotationLocked()); + return true; +} + +void RotationLockDefaultView::OnMaximizeModeStarted() { + Update(); + SetVisible(true); + Shell::GetInstance()->screen_orientation_controller()->AddObserver(this); +} + +void RotationLockDefaultView::OnMaximizeModeEnded() { + SetVisible(false); + StopObservingRotation(); +} + +void RotationLockDefaultView::OnRotationLockChanged(bool rotation_locked) { + Update(); +} + +} // namespace tray + +TrayRotationLock::TrayRotationLock(SystemTray* system_tray) + : TrayImageItem(system_tray, + kSystemTrayRotationLockLockedIcon, + UMA_ROTATION_LOCK) { + WmShell::Get()->AddShellObserver(this); +} + +TrayRotationLock::~TrayRotationLock() { + WmShell::Get()->RemoveShellObserver(this); +} + +void TrayRotationLock::OnRotationLockChanged(bool rotation_locked) { + tray_view()->SetVisible(ShouldBeVisible()); +} + +views::View* TrayRotationLock::CreateDefaultView(LoginStatus status) { + if (OnPrimaryDisplay()) + return new tray::RotationLockDefaultView(this); + return nullptr; +} + +void TrayRotationLock::OnMaximizeModeStarted() { + tray_view()->SetVisible(IsRotationLocked()); + Shell::GetInstance()->screen_orientation_controller()->AddObserver(this); +} + +void TrayRotationLock::OnMaximizeModeEnded() { + tray_view()->SetVisible(false); + StopObservingRotation(); +} + +void TrayRotationLock::DestroyTrayView() { + StopObservingRotation(); + WmShell::Get()->RemoveShellObserver(this); + TrayImageItem::DestroyTrayView(); +} + +bool TrayRotationLock::GetInitialVisibility() { + return ShouldBeVisible(); +} + +bool TrayRotationLock::ShouldBeVisible() { + return OnPrimaryDisplay() && IsMaximizeModeWindowManagerEnabled() && + IsRotationLocked(); +} + +bool TrayRotationLock::OnPrimaryDisplay() const { + gfx::NativeView native_view = system_tray()->GetWidget()->GetNativeView(); + display::Display parent_display = + display::Screen::GetScreen()->GetDisplayNearestWindow(native_view); + return parent_display.IsInternal(); +} + +void TrayRotationLock::StopObservingRotation() { + ScreenOrientationController* controller = + Shell::GetInstance()->screen_orientation_controller(); + if (controller) + controller->RemoveObserver(this); +} + +} // namespace ash
diff --git a/ash/system/chromeos/rotation/tray_rotation_lock.h b/ash/system/chromeos/rotation/tray_rotation_lock.h new file mode 100644 index 0000000..109376c --- /dev/null +++ b/ash/system/chromeos/rotation/tray_rotation_lock.h
@@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHROMEOS_ROTATION_TRAY_ROTATION_LOCK_H_ +#define ASH_SYSTEM_CHROMEOS_ROTATION_TRAY_ROTATION_LOCK_H_ + +#include "ash/common/shell_observer.h" +#include "ash/common/system/tray/tray_image_item.h" +#include "ash/display/screen_orientation_controller_chromeos.h" +#include "base/macros.h" + +namespace ash { + +// TrayRotationLock is a provider of views for the SystemTray. Both a tray view +// and a default view are provided. Each view indicates the current state of +// the rotation lock for the display which it appears on. The default view can +// be interacted with, it toggles the state of the rotation lock. +// TrayRotationLock is only available on the primary display. +class ASH_EXPORT TrayRotationLock + : public TrayImageItem, + public ScreenOrientationController::Observer, + public ShellObserver { + public: + explicit TrayRotationLock(SystemTray* system_tray); + ~TrayRotationLock() override; + + // ScreenOrientationController::Observer: + void OnRotationLockChanged(bool rotation_locked) override; + + // SystemTrayItem: + views::View* CreateDefaultView(LoginStatus status) override; + + // ShellObserver: + void OnMaximizeModeStarted() override; + void OnMaximizeModeEnded() override; + + // TrayImageItem: + void DestroyTrayView() override; + + protected: + // TrayImageItem: + bool GetInitialVisibility() override; + + private: + friend class TrayRotationLockTest; + + // True if |on_primary_display_|, maximize mode is enabled, and rotation is + // locked. + bool ShouldBeVisible(); + + // True if this is owned by a SystemTray on the primary display. + bool OnPrimaryDisplay() const; + + // Removes TrayRotationLock as a ScreenOrientationController::Observer if + // currently observing. + void StopObservingRotation(); + + DISALLOW_COPY_AND_ASSIGN(TrayRotationLock); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_ROTATION_TRAY_ROTATION_LOCK_H_
diff --git a/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc b/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc new file mode 100644 index 0000000..a902e92 --- /dev/null +++ b/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc
@@ -0,0 +1,267 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/rotation/tray_rotation_lock.h" + +#include <memory> + +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm_shell.h" +#include "ash/display/screen_orientation_controller_chromeos.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/status_area_widget_test_helper.h" +#include "base/command_line.h" +#include "base/time/time.h" +#include "ui/display/display_switches.h" +#include "ui/display/manager/display_manager.h" +#include "ui/display/types/display_constants.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" +#include "ui/views/view.h" + +namespace ash { + +class TrayRotationLockTest : public test::AshTestBase { + public: + TrayRotationLockTest() {} + ~TrayRotationLockTest() override {} + + TrayRotationLock* tray() { return tray_.get(); } + + views::View* tray_view() { return tray_view_.get(); } + + views::View* default_view() { return default_view_.get(); } + + // Creates the tray view associated to |tray_rotation_lock|. + views::View* CreateTrayView(TrayRotationLock* tray_rotation_lock); + + // Destroys only the |tray_view_|. Tests may call this to simulate destruction + // order during the deletion of the StatusAreaWidget. + void DestroyTrayView(); + + // Sets up a TrayRotationLock, its tray view, and its default view, for the + // given SystemTray and its display. On a primary display all will be + // created. On a secondary display both the tray view and default view will + // be null. + void SetUpForStatusAreaWidget(StatusAreaWidget* status_area_widget); + + // Resets |tray_| |tray_view_| and |default_view_| so that all components of + // TrayRotationLock have been cleared. Tests may then call + // SetUpForStatusAreaWidget in order to initial the components. + void TearDownViews(); + + // test::AshTestBase: + void SetUp() override; + void TearDown() override; + + private: + std::unique_ptr<TrayRotationLock> tray_; + std::unique_ptr<views::View> tray_view_; + std::unique_ptr<views::View> default_view_; + + DISALLOW_COPY_AND_ASSIGN(TrayRotationLockTest); +}; + +views::View* TrayRotationLockTest::CreateTrayView( + TrayRotationLock* tray_rotation_lock) { + return tray_rotation_lock->CreateTrayView( + StatusAreaWidgetTestHelper::GetUserLoginStatus()); +} + +void TrayRotationLockTest::DestroyTrayView() { + tray_view_.reset(); + tray_->DestroyTrayView(); +} + +void TrayRotationLockTest::SetUpForStatusAreaWidget( + StatusAreaWidget* status_area_widget) { + tray_.reset(new TrayRotationLock(status_area_widget->system_tray())); + tray_view_.reset( + tray_->CreateTrayView(StatusAreaWidgetTestHelper::GetUserLoginStatus())); + default_view_.reset(tray_->CreateDefaultView( + StatusAreaWidgetTestHelper::GetUserLoginStatus())); +} + +void TrayRotationLockTest::TearDownViews() { + tray_view_.reset(); + default_view_.reset(); + tray_.reset(); +} + +void TrayRotationLockTest::SetUp() { + // The Display used for testing is not an internal display. This flag + // allows for DisplayManager to treat it as one. TrayRotationLock is only + // visible on internal primary displays. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + ::switches::kUseFirstDisplayAsInternal); + test::AshTestBase::SetUp(); + SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); +} + +void TrayRotationLockTest::TearDown() { + TearDownViews(); + test::AshTestBase::TearDown(); +} + +// Tests that when the tray view is initially created, that it is created +// not visible. +TEST_F(TrayRotationLockTest, CreateTrayView) { + EXPECT_FALSE(tray_view()->visible()); +} + +// Tests that when the tray view is created, while MaximizeMode is active, that +// it is not visible. +TEST_F(TrayRotationLockTest, CreateTrayViewDuringMaximizeMode) { + TearDownViews(); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); + EXPECT_FALSE(tray_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); +} + +// Tests that when the tray view is created, while MaximizeMode is active, and +// rotation is locked, that it is visible. +TEST_F(TrayRotationLockTest, CreateTrayViewDuringMaximizeModeAndRotationLock) { + TearDownViews(); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( + true); + SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); + EXPECT_TRUE(tray_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_FALSE(tray_view()->visible()); +} + +// Tests that the enabling of MaximizeMode affects a previously created tray +// view, changing the visibility. +TEST_F(TrayRotationLockTest, TrayViewVisibilityChangesDuringMaximizeMode) { + ASSERT_FALSE(tray_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( + true); + EXPECT_TRUE(tray_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_FALSE(tray_view()->visible()); +} + +// Tests that the when the tray view is created for a secondary display, that +// it is not visible, and that MaximizeMode does not affect visibility. +TEST_F(TrayRotationLockTest, CreateSecondaryTrayView) { + UpdateDisplay("400x400,200x200"); + + SetUpForStatusAreaWidget( + StatusAreaWidgetTestHelper::GetSecondaryStatusAreaWidget()); + EXPECT_FALSE(tray_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + EXPECT_FALSE(tray_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_FALSE(tray_view()->visible()); +} + +// Tests that when the default view is initially created, that it is created +// not visible. +TEST_F(TrayRotationLockTest, CreateDefaultView) { + EXPECT_FALSE(default_view()->visible()); +} + +// Tests that when the default view is created, while MaximizeMode is active, +// that it is visible. +TEST_F(TrayRotationLockTest, CreateDefaultViewDuringMaximizeMode) { + TearDownViews(); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); + EXPECT_TRUE(default_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); +} + +// Tests that the enabling of MaximizeMode affects a previously created default +// view, changing the visibility. +TEST_F(TrayRotationLockTest, DefaultViewVisibilityChangesDuringMaximizeMode) { + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + EXPECT_TRUE(default_view()->visible()); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); + EXPECT_FALSE(default_view()->visible()); +} + +// Tests that no default view is created when the target is a secondary +// display. +TEST_F(TrayRotationLockTest, CreateSecondaryDefaultView) { + UpdateDisplay("400x400,200x200"); + + TearDownViews(); + SetUpForStatusAreaWidget( + StatusAreaWidgetTestHelper::GetSecondaryStatusAreaWidget()); + EXPECT_EQ(NULL, default_view()); +} + +// Tests that activating the default view causes the display to have its +// rotation locked, and that the tray view becomes visible. +TEST_F(TrayRotationLockTest, PerformActionOnDefaultView) { + MaximizeModeController* maximize_mode_controller = + WmShell::Get()->maximize_mode_controller(); + ScreenOrientationController* screen_orientation_controller = + Shell::GetInstance()->screen_orientation_controller(); + ASSERT_FALSE(screen_orientation_controller->rotation_locked()); + maximize_mode_controller->EnableMaximizeModeWindowManager(true); + ASSERT_FALSE(tray_view()->visible()); + + ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), + ui::GestureEventDetails(ui::ET_GESTURE_TAP)); + default_view()->OnGestureEvent(&tap); + EXPECT_TRUE(screen_orientation_controller->rotation_locked()); + EXPECT_TRUE(tray_view()->visible()); + + maximize_mode_controller->EnableMaximizeModeWindowManager(false); +} + +// Tests that when the tray is created without the internal display being known, +// that it will still display correctly once the internal display is known. +TEST_F(TrayRotationLockTest, InternalDisplayNotAvailableAtCreation) { + int64_t internal_display_id = display::Display::InternalDisplayId(); + TearDownViews(); + display::Display::SetInternalDisplayId(display::kInvalidDisplayId); + + std::unique_ptr<TrayRotationLock> tray(new TrayRotationLock( + StatusAreaWidgetTestHelper::GetStatusAreaWidget()->system_tray())); + + display::Display::SetInternalDisplayId(internal_display_id); + std::unique_ptr<views::View> tray_view(CreateTrayView(tray.get())); + std::unique_ptr<views::View> default_view(tray->CreateDefaultView( + StatusAreaWidgetTestHelper::GetUserLoginStatus())); + EXPECT_TRUE(default_view); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + EXPECT_TRUE(default_view->visible()); +} + +// Tests that when the tray view is deleted, while TrayRotationLock has not been +// deleted, that updates to the rotation lock state do not crash. +TEST_F(TrayRotationLockTest, LockUpdatedDuringDesctruction) { + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + true); + DestroyTrayView(); + Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( + true); + WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( + false); +} + +} // namespace ash
diff --git a/ash/system/chromeos/screen_layout_observer.cc b/ash/system/chromeos/screen_layout_observer.cc new file mode 100644 index 0000000..1110c76 --- /dev/null +++ b/ash/system/chromeos/screen_layout_observer.cc
@@ -0,0 +1,424 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/screen_layout_observer.h" + +#include <memory> +#include <utility> +#include <vector> + +#include "ash/common/metrics/user_metrics_action.h" +#include "ash/common/system/chromeos/devicetype_utils.h" +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/fixed_sized_image_view.h" +#include "ash/common/system/tray/system_tray_controller.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/system/tray/tray_constants.h" +#include "ash/common/wm_shell.h" +#include "ash/display/screen_orientation_controller_chromeos.h" +#include "ash/resources/grit/ash_resources.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "base/bind.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/display/display.h" +#include "ui/display/manager/display_manager.h" +#include "ui/display/types/display_constants.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_delegate.h" +#include "ui/strings/grit/ui_strings.h" + +using message_center::Notification; + +namespace ash { +namespace { + +display::DisplayManager* GetDisplayManager() { + return Shell::GetInstance()->display_manager(); +} + +base::string16 GetDisplayName(int64_t display_id) { + return base::UTF8ToUTF16( + GetDisplayManager()->GetDisplayNameForId(display_id)); +} + +base::string16 GetDisplaySize(int64_t display_id) { + display::DisplayManager* display_manager = GetDisplayManager(); + + const display::Display* display = + &display_manager->GetDisplayForId(display_id); + + // We don't show display size for mirrored display. Fallback + // to empty string if this happens on release build. + bool mirroring = display_manager->mirroring_display_id() == display_id; + DCHECK(!mirroring); + if (mirroring) + return base::string16(); + + DCHECK(display->is_valid()); + return base::UTF8ToUTF16(display->size().ToString()); +} + +// Attempts to open the display settings, returns true if successful. +bool OpenSettings() { + // switch is intentionally introduced without default, to cause an error when + // a new type of login status is introduced. + switch (WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()) { + case LoginStatus::NOT_LOGGED_IN: + case LoginStatus::LOCKED: + return false; + + case LoginStatus::USER: + case LoginStatus::OWNER: + case LoginStatus::GUEST: + case LoginStatus::PUBLIC: + case LoginStatus::SUPERVISED: + case LoginStatus::KIOSK_APP: + case LoginStatus::ARC_KIOSK_APP: + SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); + if (delegate->ShouldShowSettings()) { + WmShell::Get()->system_tray_controller()->ShowDisplaySettings(); + return true; + } + break; + } + + return false; +} + +// Callback to handle a user selecting the notification view. +void OpenSettingsFromNotification() { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED); + if (OpenSettings()) { + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS); + } +} + +// Returns the name of the currently connected external display whose ID is +// |external_display_id|. This should not be used when the external display is +// used for mirroring. +base::string16 GetExternalDisplayName(int64_t external_display_id) { + DCHECK(!display::Display::IsInternalDisplayId(external_display_id)); + + display::DisplayManager* display_manager = GetDisplayManager(); + DCHECK(!display_manager->IsInMirrorMode()); + + if (external_display_id == display::kInvalidDisplayId) + return l10n_util::GetStringUTF16(IDS_DISPLAY_NAME_UNKNOWN); + + // The external display name may have an annotation of "(width x height)" in + // case that the display is rotated or its resolution is changed. + base::string16 name = GetDisplayName(external_display_id); + const display::ManagedDisplayInfo& display_info = + display_manager->GetDisplayInfo(external_display_id); + if (display_info.GetActiveRotation() != display::Display::ROTATE_0 || + display_info.configured_ui_scale() != 1.0f || + !display_info.overscan_insets_in_dip().IsEmpty()) { + name = + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, + name, GetDisplaySize(external_display_id)); + } else if (display_info.overscan_insets_in_dip().IsEmpty() && + display_info.has_overscan()) { + name = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, name, + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN)); + } + + return name; +} + +// Returns true if docked mode is currently enabled. +bool IsDockedModeEnabled() { + display::DisplayManager* display_manager = GetDisplayManager(); + if (!display::Display::HasInternalDisplay()) + return false; + + for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { + if (display::Display::IsInternalDisplayId( + display_manager->GetDisplayAt(i).id())) { + return false; + } + } + + // We have an internal display but it's not one of the active displays. + return true; +} + +// Returns the notification message that should be shown when mirror display +// mode is entered. +base::string16 GetEnterMirrorModeMessage() { + if (display::Display::HasInternalDisplay()) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, + GetDisplayName(GetDisplayManager()->mirroring_display_id())); + } + + return l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL); +} + +// Returns the notification message that should be shown when unified desktop +// mode is entered. +base::string16 GetEnterUnifiedModeMessage() { + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED); +} + +// Returns the notification message that should be shown when unified desktop +// mode is exited. +base::string16 GetExitUnifiedModeMessage() { + return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING); +} + +base::string16 GetDisplayRemovedMessage( + const display::ManagedDisplayInfo& removed_display_info, + base::string16* out_additional_message) { + return l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED, + base::UTF8ToUTF16(removed_display_info.name())); +} + +base::string16 GetDisplayAddedMessage(int64_t added_display_id, + base::string16* additional_message_out) { + if (!display::Display::HasInternalDisplay()) { + return l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL); + } + + return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, + GetExternalDisplayName(added_display_id)); +} + +} // namespace + +const char ScreenLayoutObserver::kNotificationId[] = + "chrome://settings/display"; + +ScreenLayoutObserver::ScreenLayoutObserver() { + WmShell::Get()->AddDisplayObserver(this); + UpdateDisplayInfo(NULL); +} + +ScreenLayoutObserver::~ScreenLayoutObserver() { + WmShell::Get()->RemoveDisplayObserver(this); +} + +void ScreenLayoutObserver::UpdateDisplayInfo( + ScreenLayoutObserver::DisplayInfoMap* old_info) { + if (old_info) + old_info->swap(display_info_); + display_info_.clear(); + + display::DisplayManager* display_manager = GetDisplayManager(); + for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { + int64_t id = display_manager->GetDisplayAt(i).id(); + display_info_[id] = display_manager->GetDisplayInfo(id); + } +} + +bool ScreenLayoutObserver::GetDisplayMessageForNotification( + const ScreenLayoutObserver::DisplayInfoMap& old_info, + base::string16* out_message, + base::string16* out_additional_message) { + if (old_display_mode_ != current_display_mode_) { + // Detect changes in the mirror mode status. + if (current_display_mode_ == DisplayMode::MIRRORING) { + *out_message = GetEnterMirrorModeMessage(); + return true; + } + if (old_display_mode_ == DisplayMode::MIRRORING && + GetExitMirrorModeMessage(out_message, out_additional_message)) { + return true; + } + + // Detect changes in the unified mode status. + if (current_display_mode_ == DisplayMode::UNIFIED) { + *out_message = GetEnterUnifiedModeMessage(); + return true; + } + if (old_display_mode_ == DisplayMode::UNIFIED) { + *out_message = GetExitUnifiedModeMessage(); + return true; + } + + if (current_display_mode_ == DisplayMode::DOCKED || + old_display_mode_ == DisplayMode::DOCKED) { + // We no longer show any notification for docked mode events. + // crbug.com/674719. + return false; + } + } + + // Displays are added or removed. + if (display_info_.size() < old_info.size()) { + // A display has been removed. + for (const auto& iter : old_info) { + if (display_info_.count(iter.first)) + continue; + + *out_message = + GetDisplayRemovedMessage(iter.second, out_additional_message); + return true; + } + } else if (display_info_.size() > old_info.size()) { + // A display has been added. + for (const auto& iter : display_info_) { + if (old_info.count(iter.first)) + continue; + + *out_message = GetDisplayAddedMessage(iter.first, out_additional_message); + return true; + } + } + + for (const auto& iter : display_info_) { + DisplayInfoMap::const_iterator old_iter = old_info.find(iter.first); + if (old_iter == old_info.end()) { + // The display's number is same but different displays. This happens + // for the transition between docked mode and mirrored display. + // This condition can never be reached here, since it is handled above. + NOTREACHED() << "A display mode transition that should have been handled" + "earlier."; + return false; + } + + if (iter.second.configured_ui_scale() != + old_iter->second.configured_ui_scale()) { + *out_additional_message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, + GetDisplayName(iter.first), GetDisplaySize(iter.first)); + return true; + } + if (iter.second.GetActiveRotation() != + old_iter->second.GetActiveRotation()) { + int rotation_text_id = 0; + switch (iter.second.GetActiveRotation()) { + case display::Display::ROTATE_0: + rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION; + break; + case display::Display::ROTATE_90: + rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90; + break; + case display::Display::ROTATE_180: + rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180; + break; + case display::Display::ROTATE_270: + rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270; + break; + } + *out_additional_message = l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetDisplayName(iter.first), + l10n_util::GetStringUTF16(rotation_text_id)); + return true; + } + } + + // Found nothing special + return false; +} + +void ScreenLayoutObserver::CreateOrUpdateNotification( + const base::string16& message, + const base::string16& additional_message) { + // Always remove the notification to make sure the notification appears + // as a popup in any situation. + message_center::MessageCenter::Get()->RemoveNotification(kNotificationId, + false /* by_user */); + + if (message.empty() && additional_message.empty()) + return; + + // Don't display notifications for accelerometer triggered screen rotations. + // See http://crbug.com/364949 + if (Shell::GetInstance() + ->screen_orientation_controller() + ->ignore_display_configuration_updates()) { + return; + } + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + std::unique_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message, + additional_message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_DISPLAY), + base::string16(), // display_source + GURL(), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + system_notifier::kNotifierDisplay), + message_center::RichNotificationData(), + new message_center::HandleNotificationClickedDelegate( + base::Bind(&OpenSettingsFromNotification)))); + + WmShell::Get()->RecordUserMetricsAction( + UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED); + message_center::MessageCenter::Get()->AddNotification( + std::move(notification)); +} + +void ScreenLayoutObserver::OnDisplayConfigurationChanged() { + DisplayInfoMap old_info; + UpdateDisplayInfo(&old_info); + + old_display_mode_ = current_display_mode_; + if (GetDisplayManager()->IsInMirrorMode()) + current_display_mode_ = DisplayMode::MIRRORING; + else if (GetDisplayManager()->IsInUnifiedMode()) + current_display_mode_ = DisplayMode::UNIFIED; + else if (IsDockedModeEnabled()) + current_display_mode_ = DisplayMode::DOCKED; + else if (GetDisplayManager()->GetNumDisplays() > 2) + current_display_mode_ = DisplayMode::EXTENDED_3_PLUS; + else if (GetDisplayManager()->GetNumDisplays() == 2) + current_display_mode_ = DisplayMode::EXTENDED_2; + else + current_display_mode_ = DisplayMode::SINGLE; + + if (!show_notifications_for_testing) + return; + + base::string16 message; + base::string16 additional_message; + if (GetDisplayMessageForNotification(old_info, &message, &additional_message)) + CreateOrUpdateNotification(message, additional_message); +} + +bool ScreenLayoutObserver::GetExitMirrorModeMessage( + base::string16* out_message, + base::string16* out_additional_message) { + switch (current_display_mode_) { + case DisplayMode::EXTENDED_3_PLUS: + // Mirror mode was turned off due to having more than two displays. + // Show a message that mirror mode for 3+ displays is not supported. + *out_message = + l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED); + return true; + + case DisplayMode::DOCKED: + // Handle disabling mirror mode as a result of going to docked mode + // when we only have a single display (this means we actually have two + // physical displays, one of which is the internal display, but they + // were in mirror mode, and hence considered as one. Closing the + // internal display disables mirror mode and we still have a single + // active display). + // Falls through. + case DisplayMode::SINGLE: + // We're exiting mirror mode because we removed one of the two + // displays. + *out_message = + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT); + return true; + + default: + // Mirror mode was turned off; other messages should be shown e.g. + // extended mode is on, ... etc. + return false; + } +} + +} // namespace ash
diff --git a/ash/system/chromeos/screen_layout_observer.h b/ash/system/chromeos/screen_layout_observer.h new file mode 100644 index 0000000..1ef8bbb --- /dev/null +++ b/ash/system/chromeos/screen_layout_observer.h
@@ -0,0 +1,87 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_SYSTEM_CHROMEOS_SCREEN_LAYOUT_OBSERVER_H_ +#define ASH_SYSTEM_CHROMEOS_SCREEN_LAYOUT_OBSERVER_H_ + +#include <stdint.h> + +#include <map> + +#include "ash/ash_export.h" +#include "ash/common/wm_display_observer.h" +#include "base/macros.h" +#include "base/strings/string16.h" +#include "ui/display/manager/managed_display_info.h" + +namespace ash { + +// ScreenLayoutObserver is responsible to send notification to users when screen +// resolution changes or screen rotation changes. +class ASH_EXPORT ScreenLayoutObserver : public WmDisplayObserver { + public: + ScreenLayoutObserver(); + ~ScreenLayoutObserver() override; + + // Overridden from WmDisplayObserver: + void OnDisplayConfigurationChanged() override; + + // Notifications are shown in production and are not shown in unit tests. + // Allow individual unit tests to show notifications. + void set_show_notifications_for_testing(bool show) { + show_notifications_for_testing = show; + } + + private: + friend class ScreenLayoutObserverTest; + + using DisplayInfoMap = std::map<int64_t, display::ManagedDisplayInfo>; + + static const char kNotificationId[]; + + // Scans the current display info and updates |display_info_|. Sets the + // previous data to |old_info| if it's not NULL. + void UpdateDisplayInfo(DisplayInfoMap* old_info); + + // Compares the current display settings with |old_info| and determine what + // message should be shown for notification. Returns true if there's a + // meaningful change. Note that it's possible to return true and set + // |message_out| to empty, which means the notification should be removed. It + // also sets |additional_message_out| which appears in the notification with + // the |message_out|. + bool GetDisplayMessageForNotification(const DisplayInfoMap& old_info, + base::string16* out_message, + base::string16* out_additional_message); + + // Creates or updates the display notification. + void CreateOrUpdateNotification(const base::string16& message, + const base::string16& additional_message); + + // Returns the notification message that should be shown when mirror display + // mode is exited. + bool GetExitMirrorModeMessage(base::string16* out_message, + base::string16* out_additional_message); + + DisplayInfoMap display_info_; + + enum class DisplayMode { + SINGLE, + EXTENDED_2, // 2 displays in extended mode. + EXTENDED_3_PLUS, // 3+ displays in extended mode. + MIRRORING, + UNIFIED, + DOCKED + }; + + DisplayMode old_display_mode_ = DisplayMode::SINGLE; + DisplayMode current_display_mode_ = DisplayMode::SINGLE; + + bool show_notifications_for_testing = true; + + DISALLOW_COPY_AND_ASSIGN(ScreenLayoutObserver); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_CHROMEOS_SCREEN_LAYOUT_OBSERVER_H_
diff --git a/ash/system/chromeos/screen_layout_observer_unittest.cc b/ash/system/chromeos/screen_layout_observer_unittest.cc new file mode 100644 index 0000000..193b254 --- /dev/null +++ b/ash/system/chromeos/screen_layout_observer_unittest.cc
@@ -0,0 +1,443 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/chromeos/screen_layout_observer.h" + +#include "ash/common/system/chromeos/devicetype_utils.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" +#include "ash/test/ash_test_base.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/display/display.h" +#include "ui/display/display_layout_builder.h" +#include "ui/display/manager/display_manager.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" +#include "ui/message_center/notification_list.h" +#include "ui/views/controls/label.h" + +namespace ash { + +class ScreenLayoutObserverTest : public test::AshTestBase { + public: + ScreenLayoutObserverTest(); + ~ScreenLayoutObserverTest() override; + + protected: + ScreenLayoutObserver* GetScreenLayoutObserver(); + void CheckUpdate(); + + void CloseNotification(); + base::string16 GetDisplayNotificationText() const; + base::string16 GetDisplayNotificationAdditionalText() const; + + base::string16 GetFirstDisplayName(); + + base::string16 GetSecondDisplayName(); + + base::string16 GetMirroringDisplayName(); + + private: + const message_center::Notification* GetDisplayNotification() const; + + DISALLOW_COPY_AND_ASSIGN(ScreenLayoutObserverTest); +}; + +ScreenLayoutObserverTest::ScreenLayoutObserverTest() {} + +ScreenLayoutObserverTest::~ScreenLayoutObserverTest() {} + +ScreenLayoutObserver* ScreenLayoutObserverTest::GetScreenLayoutObserver() { + return Shell::GetInstance()->screen_layout_observer(); +} + +void ScreenLayoutObserverTest::CloseNotification() { + message_center::MessageCenter::Get()->RemoveNotification( + ScreenLayoutObserver::kNotificationId, false); + RunAllPendingInMessageLoop(); +} + +base::string16 ScreenLayoutObserverTest::GetDisplayNotificationText() const { + const message_center::Notification* notification = GetDisplayNotification(); + return notification ? notification->title() : base::string16(); +} + +base::string16 ScreenLayoutObserverTest::GetDisplayNotificationAdditionalText() + const { + const message_center::Notification* notification = GetDisplayNotification(); + return notification ? notification->message() : base::string16(); +} + +base::string16 ScreenLayoutObserverTest::GetFirstDisplayName() { + return base::UTF8ToUTF16(display_manager()->GetDisplayNameForId( + display_manager()->first_display_id())); +} + +base::string16 ScreenLayoutObserverTest::GetSecondDisplayName() { + return base::UTF8ToUTF16(display_manager()->GetDisplayNameForId( + display_manager()->GetSecondaryDisplay().id())); +} + +base::string16 ScreenLayoutObserverTest::GetMirroringDisplayName() { + return base::UTF8ToUTF16(display_manager()->GetDisplayNameForId( + display_manager()->mirroring_display_id())); +} + +const message_center::Notification* +ScreenLayoutObserverTest::GetDisplayNotification() const { + const message_center::NotificationList::Notifications notifications = + message_center::MessageCenter::Get()->GetVisibleNotifications(); + for (const auto* notification : notifications) { + if (notification->id() == ScreenLayoutObserver::kNotificationId) + return notification; + } + + return nullptr; +} + +TEST_F(ScreenLayoutObserverTest, DisplayNotifications) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + + UpdateDisplay("400x400"); + display::Display::SetInternalDisplayId(display_manager()->first_display_id()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // rotation. + UpdateDisplay("400x400/r"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(), + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), + GetDisplayNotificationAdditionalText()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + CloseNotification(); + UpdateDisplay("400x400"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(), + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION)), + GetDisplayNotificationAdditionalText()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // UI-scale + CloseNotification(); + UpdateDisplay("400x400@1.5"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, + GetFirstDisplayName(), base::UTF8ToUTF16("600x600")), + GetDisplayNotificationAdditionalText()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // UI-scale to 1.0 + CloseNotification(); + UpdateDisplay("400x400"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, + GetFirstDisplayName(), base::UTF8ToUTF16("400x400")), + GetDisplayNotificationAdditionalText()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // No-update + CloseNotification(); + UpdateDisplay("400x400"); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); + + // Extended. + CloseNotification(); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, + GetSecondDisplayName()), + GetDisplayNotificationText()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); + + // Mirroring. + CloseNotification(); + display_manager()->SetSoftwareMirroring(true); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, + GetMirroringDisplayName()), + GetDisplayNotificationText()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); + + // Back to extended. + CloseNotification(); + display_manager()->SetSoftwareMirroring(false); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, + GetSecondDisplayName()), + GetDisplayNotificationText()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); + + // Resize the first display. + UpdateDisplay("400x400@1.5,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, + GetFirstDisplayName(), base::UTF8ToUTF16("600x600")), + GetDisplayNotificationAdditionalText()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // Rotate the second. + UpdateDisplay("400x400@1.5,200x200/r"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetSecondDisplayName(), + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), + GetDisplayNotificationAdditionalText()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // Enters closed lid mode. + UpdateDisplay("400x400@1.5,200x200"); + display::Display::SetInternalDisplayId( + display_manager()->GetSecondaryDisplay().id()); + UpdateDisplay("400x400@1.5"); + EXPECT_TRUE(GetDisplayNotificationText().empty()); +} + +// Verify that notification shows up when display is switched from dock mode to +// extend mode. +TEST_F(ScreenLayoutObserverTest, DisplayConfigurationChangedTwice) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), + GetDisplayNotificationText()); + + // OnDisplayConfigurationChanged() may be called more than once for a single + // update display in case of primary is swapped or recovered from dock mode. + // Should not remove the notification in such case. + GetScreenLayoutObserver()->OnDisplayConfigurationChanged(); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), + GetDisplayNotificationText()); + + // Back to the single display. It should show that a display was removed. + UpdateDisplay("400x400"); + EXPECT_TRUE(base::StartsWith( + GetDisplayNotificationText(), + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED, + base::UTF8ToUTF16("")), + base::CompareCase::SENSITIVE)); +} + +// Verify the notification message content when one of the 2 displays that +// connected to the device is rotated. +TEST_F(ScreenLayoutObserverTest, UpdateAfterSuppressDisplayNotification) { + UpdateDisplay("400x400,200x200"); + + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + + // Rotate the second. + UpdateDisplay("400x400,200x200/r"); + EXPECT_EQ(l10n_util::GetStringFUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetSecondDisplayName(), + l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), + GetDisplayNotificationAdditionalText()); +} + +// Verify that no notification is shown when overscan of a screen is changed. +TEST_F(ScreenLayoutObserverTest, OverscanDisplay) { + UpdateDisplay("400x400, 300x300"); + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + display::Display::SetInternalDisplayId(display_manager()->first_display_id()); + + // /o creates the default overscan. + UpdateDisplay("400x400, 300x300/o"); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); + + // Reset the overscan. + Shell::GetInstance()->display_manager()->SetOverscanInsets( + display_manager()->GetSecondaryDisplay().id(), gfx::Insets()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); +} + +// Tests that exiting mirror mode by closing the lid shows the correct "exiting +// mirror mode" message. +TEST_F(ScreenLayoutObserverTest, ExitMirrorModeBecauseOfDockedModeMessage) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400,200x200"); + display::Display::SetInternalDisplayId( + display_manager()->GetSecondaryDisplay().id()); + + // Mirroring. + display_manager()->SetSoftwareMirroring(true); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, + GetMirroringDisplayName()), + GetDisplayNotificationText()); + + // Docked. + CloseNotification(); + display_manager()->SetSoftwareMirroring(false); + display::Display::SetInternalDisplayId(display_manager()->first_display_id()); + UpdateDisplay("200x200"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT), + GetDisplayNotificationText()); +} + +// Tests that exiting mirror mode because of adding a third display shows the +// correct "3+ displays mirror mode is not supported" message. +TEST_F(ScreenLayoutObserverTest, ExitMirrorModeBecauseOfThirdDisplayMessage) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400,200x200"); + display::Display::SetInternalDisplayId( + display_manager()->GetSecondaryDisplay().id()); + + // Mirroring. + display_manager()->SetSoftwareMirroring(true); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, + GetMirroringDisplayName()), + GetDisplayNotificationText()); + + // Adding a third display. Mirror mode for 3+ displays is not supported. + CloseNotification(); + display_manager()->SetSoftwareMirroring(false); + UpdateDisplay("400x400,200x200,100x100"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED), + GetDisplayNotificationText()); +} + +// Special case: tests that exiting mirror mode by removing a display shows the +// correct message. +TEST_F(ScreenLayoutObserverTest, + ExitMirrorModeNoInternalDisplayBecauseOfDisplayRemovedMessage) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400,200x200"); + display::Display::SetInternalDisplayId( + display_manager()->GetSecondaryDisplay().id()); + + // Mirroring. + display_manager()->SetSoftwareMirroring(true); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, + GetMirroringDisplayName()), + GetDisplayNotificationText()); + + // Removing one of the displays. We show that we exited mirror mode. + CloseNotification(); + display_manager()->SetSoftwareMirroring(false); + UpdateDisplay("400x400"); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT), + GetDisplayNotificationText()); +} + +// Tests notification messages shown when adding and removing displays in +// extended mode. +TEST_F(ScreenLayoutObserverTest, AddingRemovingDisplayExtendedModeMessage) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400"); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // Adding a display in extended mode. + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), + GetDisplayNotificationText()); + + // Removing a display. + CloseNotification(); + UpdateDisplay("400x400"); + EXPECT_TRUE(base::StartsWith( + GetDisplayNotificationText(), + l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED, + base::UTF8ToUTF16("")), + base::CompareCase::SENSITIVE)); +} + +// Tests notification messages shown when entering and exiting unified desktop +// mode. +TEST_F(ScreenLayoutObserverTest, EnteringExitingUnifiedModeMessage) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400"); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // Adding a display in extended mode. + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), + GetDisplayNotificationText()); + + // Enter unified mode. + display_manager()->SetUnifiedDesktopEnabled(true); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED), + GetDisplayNotificationText()); + + // Exit unified mode. + display_manager()->SetUnifiedDesktopEnabled(false); + EXPECT_EQ( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING), + GetDisplayNotificationText()); + + // Enter unified mode again and exit via closing the lid. The message "Exiting + // unified mode" should be shown. + display_manager()->SetUnifiedDesktopEnabled(true); + EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED), + GetDisplayNotificationText()); + + // Close the lid. + display::Display::SetInternalDisplayId(display_manager()->first_display_id()); + UpdateDisplay("200x200"); + display_manager()->SetUnifiedDesktopEnabled(false); + EXPECT_EQ( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING), + GetDisplayNotificationText()); +} + +// Special case: Tests notification messages shown when entering docked mode +// by closing the lid and the internal display is the secondary display. +TEST_F(ScreenLayoutObserverTest, DockedModeWithExternalPrimaryDisplayMessage) { + Shell::GetInstance() + ->screen_layout_observer() + ->set_show_notifications_for_testing(true); + UpdateDisplay("400x400,200x200"); + EXPECT_EQ(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), + GetDisplayNotificationText()); + CloseNotification(); + + const int64_t primary_id = display_manager()->GetDisplayAt(0).id(); + const int64_t internal_secondary_id = display_manager()->GetDisplayAt(1).id(); + display::Display::SetInternalDisplayId(internal_secondary_id); + display::DisplayLayoutBuilder builder(primary_id); + builder.AddDisplayPlacement(internal_secondary_id, primary_id, + display::DisplayPlacement::LEFT, 0); + display_manager()->SetLayoutForCurrentDisplays(builder.Build()); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + + // Close the lid. We go to docked mode, but we show no notifications. + UpdateDisplay("400x400"); + EXPECT_TRUE(GetDisplayNotificationText().empty()); + EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); +} + +} // namespace ash
diff --git a/ash/system/date/clock_observer.h b/ash/system/date/clock_observer.h deleted file mode 100644 index a62e2be..0000000 --- a/ash/system/date/clock_observer.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DATE_CLOCK_OBSERVER_H_ -#define ASH_SYSTEM_DATE_CLOCK_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -class ASH_EXPORT ClockObserver { - public: - virtual ~ClockObserver() {} - - virtual void OnDateFormatChanged() = 0; - virtual void OnSystemClockTimeUpdated() = 0; - virtual void OnSystemClockCanSetTimeChanged(bool can_set_time) = 0; - - // Force a refresh (e.g. after the system is resumed). - virtual void Refresh() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_DATE_CLOCK_OBSERVER_H_
diff --git a/ash/system/date/date_default_view.cc b/ash/system/date/date_default_view.cc deleted file mode 100644 index 023ebba..0000000 --- a/ash/system/date/date_default_view.cc +++ /dev/null
@@ -1,146 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/date_default_view.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/shutdown_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/date/date_view.h" -#include "ash/system/tray/special_popup_row.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_header_button.h" -#include "ash/wm/lock_state_controller.h" -#include "base/i18n/rtl.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/session_manager_client.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/view.h" - -namespace { - -// The ISO-639 code for the Hebrew locale. The help icon asset is a '?' which is -// not mirrored in this locale. -const char kHebrewLocale[] = "he"; - -const int kPaddingVertical = 19; - -} // namespace - -namespace ash { - -DateDefaultView::DateDefaultView(SystemTrayItem* owner, LoginStatus login) - : help_button_(nullptr), - shutdown_button_(nullptr), - lock_button_(nullptr), - date_view_(nullptr) { - SetLayoutManager(new views::FillLayout); - - date_view_ = new tray::DateView(owner); - date_view_->SetBorder(views::CreateEmptyBorder( - kPaddingVertical, ash::kTrayPopupPaddingHorizontal, 0, 0)); - SpecialPopupRow* view = new SpecialPopupRow(); - view->SetContent(date_view_); - AddChildView(view); - - WmShell* shell = WmShell::Get(); - const bool adding_user = - shell->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); - - if (login == LoginStatus::LOCKED || login == LoginStatus::NOT_LOGGED_IN || - adding_user) - return; - - date_view_->SetAction(tray::DateView::DateAction::SHOW_DATE_SETTINGS); - - help_button_ = new TrayPopupHeaderButton( - this, IDR_AURA_UBER_TRAY_HELP, IDR_AURA_UBER_TRAY_HELP, - IDR_AURA_UBER_TRAY_HELP_HOVER, IDR_AURA_UBER_TRAY_HELP_HOVER, - IDS_ASH_STATUS_TRAY_HELP); - - if (base::i18n::IsRTL() && - base::i18n::GetConfiguredLocale() == kHebrewLocale) { - // The asset for the help button is a question mark '?'. Normally this asset - // is flipped in RTL locales, however Hebrew uses the LTR '?'. So the - // flipping must be disabled. (crbug.com/475237) - help_button_->EnableCanvasFlippingForRTLUI(false); - } - help_button_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HELP)); - view->AddViewToRowNonMd(help_button_, true); - - if (login != LoginStatus::LOCKED) { - shutdown_button_ = new TrayPopupHeaderButton( - this, IDR_AURA_UBER_TRAY_SHUTDOWN, IDR_AURA_UBER_TRAY_SHUTDOWN, - IDR_AURA_UBER_TRAY_SHUTDOWN_HOVER, IDR_AURA_UBER_TRAY_SHUTDOWN_HOVER, - IDS_ASH_STATUS_TRAY_SHUTDOWN); - shutdown_button_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SHUTDOWN)); - view->AddViewToRowNonMd(shutdown_button_, true); - // This object is recreated every time the menu opens. Don't bother updating - // the tooltip if the shutdown policy changes while the menu is open. - bool reboot = WmShell::Get()->shutdown_controller()->reboot_on_shutdown(); - shutdown_button_->SetTooltipText(l10n_util::GetStringUTF16( - reboot ? IDS_ASH_STATUS_TRAY_REBOOT : IDS_ASH_STATUS_TRAY_SHUTDOWN)); - } - - if (shell->GetSessionStateDelegate()->CanLockScreen()) { - lock_button_ = new TrayPopupHeaderButton( - this, IDR_AURA_UBER_TRAY_LOCKSCREEN, IDR_AURA_UBER_TRAY_LOCKSCREEN, - IDR_AURA_UBER_TRAY_LOCKSCREEN_HOVER, - IDR_AURA_UBER_TRAY_LOCKSCREEN_HOVER, IDS_ASH_STATUS_TRAY_LOCK); - lock_button_->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCK)); - view->AddViewToRowNonMd(lock_button_, true); - } -} - -DateDefaultView::~DateDefaultView() {} - -views::View* DateDefaultView::GetHelpButtonView() { - return help_button_; -} - -const views::View* DateDefaultView::GetShutdownButtonViewForTest() const { - return shutdown_button_; -} - -tray::DateView* DateDefaultView::GetDateView() { - return date_view_; -} - -const tray::DateView* DateDefaultView::GetDateView() const { - return date_view_; -} - -void DateDefaultView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - WmShell* shell = WmShell::Get(); - if (sender == help_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_HELP); - shell->system_tray_controller()->ShowHelp(); - } else if (sender == shutdown_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_SHUT_DOWN); - Shell::GetInstance()->lock_state_controller()->RequestShutdown(); - } else if (sender == lock_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_LOCK_SCREEN); - chromeos::DBusThreadManager::Get() - ->GetSessionManagerClient() - ->RequestLockScreen(); - } else { - NOTREACHED(); - } - date_view_->CloseSystemBubble(); -} - -} // namespace ash
diff --git a/ash/system/date/date_default_view.h b/ash/system/date/date_default_view.h deleted file mode 100644 index 5a3217cf..0000000 --- a/ash/system/date/date_default_view.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DATE_DATE_DEFAULT_VIEW_H_ -#define ASH_SYSTEM_DATE_DATE_DEFAULT_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "base/macros.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" - -namespace ash { -namespace tray { -class DateView; -} // namespace tray - -class SystemTrayItem; -class TrayPopupHeaderButton; - -// The system tray bubble view with the date and buttons for help, lock and -// shutdown. -// TODO(tdanderson): Remove this class once material design is enabled by -// default. See crbug.com/614453. -class ASH_EXPORT DateDefaultView : public views::View, - public views::ButtonListener { - public: - DateDefaultView(SystemTrayItem* owner, LoginStatus login); - - ~DateDefaultView() override; - - views::View* GetHelpButtonView(); - const views::View* GetShutdownButtonViewForTest() const; - - tray::DateView* GetDateView(); - const tray::DateView* GetDateView() const; - - private: - // Overridden from views::ButtonListener. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - TrayPopupHeaderButton* help_button_; - TrayPopupHeaderButton* shutdown_button_; - TrayPopupHeaderButton* lock_button_; - tray::DateView* date_view_; - - DISALLOW_COPY_AND_ASSIGN(DateDefaultView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_DATE_DATE_DEFAULT_VIEW_H_
diff --git a/ash/system/date/date_view.cc b/ash/system/date/date_view.cc deleted file mode 100644 index 12440cd..0000000 --- a/ash/system/date/date_view.cc +++ /dev/null
@@ -1,408 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/date_view.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tray_utils.h" -#include "base/i18n/rtl.h" -#include "base/i18n/time_formatting.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "third_party/icu/source/i18n/unicode/datefmt.h" -#include "third_party/icu/source/i18n/unicode/dtptngen.h" -#include "third_party/icu/source/i18n/unicode/smpdtfmt.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/layout/grid_layout.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace tray { -namespace { - -// Amount of slop to add into the timer to make sure we're into the next minute -// when the timer goes off. -const int kTimerSlopSeconds = 1; - -// Text color of the vertical clock minutes. -const SkColor kVerticalClockMinuteColor = SkColorSetRGB(0xBA, 0xBA, 0xBA); - -// Padding between the left edge of the shelf and the left edge of the vertical -// clock. -const int kVerticalClockLeftPadding = 9; - -// Offset used to bring the minutes line closer to the hours line in the -// vertical clock. -const int kVerticalClockMinutesTopOffset = -4; -const int kVerticalClockMinutesTopOffsetMD = -2; - -// Leading padding used to draw the tray background to the left of the clock -// when the shelf is vertically aligned. -const int kClockLeadingPadding = 8; - -bool UseMd() { - return MaterialDesignController::IsSystemTrayMenuMaterial(); -} - -base::string16 FormatDateWithPattern(const base::Time& time, - const char* pattern) { - UErrorCode status = U_ZERO_ERROR; - std::unique_ptr<icu::DateTimePatternGenerator> generator( - icu::DateTimePatternGenerator::createInstance(status)); - DCHECK(U_SUCCESS(status)); - icu::UnicodeString generated_pattern = - generator->getBestPattern(icu::UnicodeString(pattern), status); - DCHECK(U_SUCCESS(status)); - icu::SimpleDateFormat simple_formatter(generated_pattern, status); - DCHECK(U_SUCCESS(status)); - icu::UnicodeString date_string; - simple_formatter.format(static_cast<UDate>(time.ToDoubleT() * 1000), - date_string, status); - DCHECK(U_SUCCESS(status)); - return base::string16(date_string.getBuffer(), - static_cast<size_t>(date_string.length())); -} - -base::string16 FormatDate(const base::Time& time) { - if (UseMd()) { - // Use 'short' month format (e.g., "Oct") followed by non-padded day of - // month (e.g., "2", "10"). - return FormatDateWithPattern(time, "LLLd"); - } else { - icu::UnicodeString date_string; - std::unique_ptr<icu::DateFormat> formatter( - icu::DateFormat::createDateInstance(icu::DateFormat::kMedium)); - formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string); - return base::string16(date_string.getBuffer(), - static_cast<size_t>(date_string.length())); - } -} - -base::string16 FormatDayOfWeek(const base::Time& time) { - // Use 'short' day of week format (e.g., "Wed"). - return FormatDateWithPattern(time, "EEE"); -} - -} // namespace - -BaseDateTimeView::~BaseDateTimeView() { - timer_.Stop(); -} - -void BaseDateTimeView::UpdateText() { - base::Time now = base::Time::Now(); - UpdateTextInternal(now); - SchedulePaint(); - SetTimer(now); -} - -void BaseDateTimeView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - ActionableView::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_TIME; -} - -BaseDateTimeView::BaseDateTimeView(SystemTrayItem* owner) - : ActionableView(owner, TrayPopupInkDropStyle::INSET_BOUNDS), - hour_type_(WmShell::Get()->system_tray_controller()->hour_clock_type()) { - SetTimer(base::Time::Now()); - SetFocusBehavior(FocusBehavior::NEVER); -} - -void BaseDateTimeView::SetTimer(const base::Time& now) { - // Try to set the timer to go off at the next change of the minute. We don't - // want to have the timer go off more than necessary since that will cause - // the CPU to wake up and consume power. - base::Time::Exploded exploded; - now.LocalExplode(&exploded); - - // Often this will be called at minute boundaries, and we'll actually want - // 60 seconds from now. - int seconds_left = 60 - exploded.second; - if (seconds_left == 0) - seconds_left = 60; - - // Make sure that the timer fires on the next minute. Without this, if it is - // called just a teeny bit early, then it will skip the next minute. - seconds_left += kTimerSlopSeconds; - - timer_.Stop(); - timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(seconds_left), this, - &BaseDateTimeView::UpdateText); -} - -void BaseDateTimeView::UpdateTextInternal(const base::Time& now) { - SetAccessibleName(base::TimeFormatTimeOfDayWithHourClockType( - now, hour_type_, base::kKeepAmPm) + - base::ASCIIToUTF16(", ") + - base::TimeFormatFriendlyDate(now)); - - NotifyAccessibilityEvent(ui::AX_EVENT_TEXT_CHANGED, true); -} - -void BaseDateTimeView::ChildPreferredSizeChanged(views::View* child) { - PreferredSizeChanged(); -} - -void BaseDateTimeView::OnLocaleChanged() { - UpdateText(); -} - -/////////////////////////////////////////////////////////////////////////////// - -DateView::DateView(SystemTrayItem* owner) - : BaseDateTimeView(owner), action_(DateAction::NONE) { - if (UseMd()) { - // TODO(tdanderson): Tweak spacing and layout for material design. - views::BoxLayout* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - box_layout->set_inside_border_insets(gfx::Insets(0, 12, 0, 0)); - box_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); - box_layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - SetLayoutManager(box_layout); - } else { - SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); - } - date_label_ = TrayPopupUtils::CreateDefaultLabel(); - date_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - if (!UseMd()) - date_label_->SetEnabledColor(kHeaderTextColorNormal); - UpdateTextInternal(base::Time::Now()); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); - style.SetupLabel(date_label_); - AddChildView(date_label_); -} - -DateView::~DateView() {} - -void DateView::SetAction(DateAction action) { - if (action == action_) - return; - if (IsMouseHovered() && !UseMd()) { - date_label_->SetEnabledColor(action == DateAction::NONE - ? kHeaderTextColorNormal - : kHeaderTextColorHover); - SchedulePaint(); - } - action_ = action; - SetFocusBehavior(action_ != DateAction::NONE ? FocusBehavior::ALWAYS - : FocusBehavior::NEVER); - - // Disable |this| when not clickable so that the material design ripple is - // not shown. - if (UseMd()) { - SetEnabled(action_ != DateAction::NONE); - if (action_ != DateAction::NONE) - SetInkDropMode(views::InkDropHostView::InkDropMode::ON); - } -} - -void DateView::UpdateTimeFormat() { - hour_type_ = WmShell::Get()->system_tray_controller()->hour_clock_type(); - UpdateText(); -} - -base::HourClockType DateView::GetHourTypeForTesting() const { - return hour_type_; -} - -void DateView::SetActive(bool active) { - if (UseMd()) - return; - - date_label_->SetEnabledColor(active ? kHeaderTextColorHover - : kHeaderTextColorNormal); - SchedulePaint(); -} - -void DateView::UpdateTextInternal(const base::Time& now) { - BaseDateTimeView::UpdateTextInternal(now); - date_label_->SetText(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DATE, FormatDayOfWeek(now), FormatDate(now))); -} - -bool DateView::PerformAction(const ui::Event& event) { - if (action_ == DateAction::NONE) - return false; - if (action_ == DateAction::SHOW_DATE_SETTINGS) - WmShell::Get()->system_tray_controller()->ShowDateSettings(); - else if (action_ == DateAction::SET_SYSTEM_TIME) - WmShell::Get()->system_tray_controller()->ShowSetTimeDialog(); - else - return false; - CloseSystemBubble(); - return true; -} - -void DateView::OnMouseEntered(const ui::MouseEvent& event) { - if (action_ == DateAction::NONE) - return; - SetActive(true); -} - -void DateView::OnMouseExited(const ui::MouseEvent& event) { - if (action_ == DateAction::NONE) - return; - SetActive(false); -} - -void DateView::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetActive(true); - } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || - event->type() == ui::ET_GESTURE_END) { - SetActive(false); - } - BaseDateTimeView::OnGestureEvent(event); -} - -/////////////////////////////////////////////////////////////////////////////// - -TimeView::TimeView(ClockLayout clock_layout) : BaseDateTimeView(nullptr) { - SetupLabels(); - UpdateTextInternal(base::Time::Now()); - UpdateClockLayout(clock_layout); -} - -TimeView::~TimeView() {} - -void TimeView::UpdateTimeFormat() { - hour_type_ = WmShell::Get()->system_tray_controller()->hour_clock_type(); - UpdateText(); -} - -base::HourClockType TimeView::GetHourTypeForTesting() const { - return hour_type_; -} - -void TimeView::UpdateTextInternal(const base::Time& now) { - // Just in case |now| is null, do NOT update time; otherwise, it will - // crash icu code by calling into base::TimeFormatTimeOfDayWithHourClockType, - // see details in crbug.com/147570. - if (now.is_null()) { - LOG(ERROR) << "Received null value from base::Time |now| in argument"; - return; - } - - BaseDateTimeView::UpdateTextInternal(now); - base::string16 current_time = base::TimeFormatTimeOfDayWithHourClockType( - now, hour_type_, base::kDropAmPm); - horizontal_label_->SetText(current_time); - horizontal_label_->SetTooltipText(base::TimeFormatFriendlyDate(now)); - - // Calculate vertical clock layout labels. - size_t colon_pos = current_time.find(base::ASCIIToUTF16(":")); - base::string16 hour = current_time.substr(0, colon_pos); - base::string16 minute = current_time.substr(colon_pos + 1); - - // Sometimes pad single-digit hours with a zero for aesthetic reasons. - if (hour.length() == 1 && hour_type_ == base::k24HourClock && - !base::i18n::IsRTL()) - hour = base::ASCIIToUTF16("0") + hour; - - vertical_label_hours_->SetText(hour); - vertical_label_minutes_->SetText(minute); - Layout(); -} - -bool TimeView::PerformAction(const ui::Event& event) { - return false; -} - -bool TimeView::OnMousePressed(const ui::MouseEvent& event) { - // Let the event fall through. - return false; -} - -void TimeView::OnGestureEvent(ui::GestureEvent* event) { - // Skip gesture handling happening in CustomButton so that the container views - // receive and handle them properly. - // TODO(mohsen): Refactor TimeView/DateView classes so that they are not - // ActionableView anymore. Create an ActionableView as a container for when - // needed. -} - -void TimeView::UpdateClockLayout(ClockLayout clock_layout) { - SetBorderFromLayout(clock_layout); - if (clock_layout == ClockLayout::HORIZONTAL_CLOCK) { - RemoveChildView(vertical_label_hours_.get()); - RemoveChildView(vertical_label_minutes_.get()); - SetLayoutManager(new views::FillLayout()); - AddChildView(horizontal_label_.get()); - } else { - const bool is_material_design = MaterialDesignController::IsShelfMaterial(); - RemoveChildView(horizontal_label_.get()); - views::GridLayout* layout = new views::GridLayout(this); - SetLayoutManager(layout); - const int kColumnId = 0; - views::ColumnSet* columns = layout->AddColumnSet(kColumnId); - columns->AddPaddingColumn(0, kVerticalClockLeftPadding); - columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, - 0, views::GridLayout::USE_PREF, 0, 0); - layout->AddPaddingRow( - 0, is_material_design ? kClockLeadingPadding - : kTrayLabelItemVerticalPaddingVerticalAlignment); - layout->StartRow(0, kColumnId); - layout->AddView(vertical_label_hours_.get()); - layout->StartRow(0, kColumnId); - layout->AddView(vertical_label_minutes_.get()); - layout->AddPaddingRow( - 0, - is_material_design - ? kTrayImageItemPadding + kVerticalClockMinutesTopOffsetMD - : kTrayLabelItemVerticalPaddingVerticalAlignment); - } - Layout(); -} - -void TimeView::SetBorderFromLayout(ClockLayout clock_layout) { - if (clock_layout == ClockLayout::HORIZONTAL_CLOCK) { - SetBorder(views::CreateEmptyBorder( - gfx::Insets(0, - UseMd() ? kTrayImageItemPadding - : kTrayLabelItemHorizontalPaddingBottomAlignment))); - } else { - SetBorder(views::NullBorder()); - } -} - -void TimeView::SetupLabels() { - horizontal_label_.reset(new views::Label()); - SetupLabel(horizontal_label_.get()); - vertical_label_hours_.reset(new views::Label()); - SetupLabel(vertical_label_hours_.get()); - vertical_label_minutes_.reset(new views::Label()); - SetupLabel(vertical_label_minutes_.get()); - // TODO(estade): this should use the NativeTheme's secondary text color. - vertical_label_minutes_->SetEnabledColor(kVerticalClockMinuteColor); - // Pull the minutes up closer to the hours by using a negative top border. - vertical_label_minutes_->SetBorder( - views::CreateEmptyBorder(MaterialDesignController::IsShelfMaterial() - ? kVerticalClockMinutesTopOffsetMD - : kVerticalClockMinutesTopOffset, - 0, 0, 0)); -} - -void TimeView::SetupLabel(views::Label* label) { - label->set_owned_by_client(); - SetupLabelForTray(label); - label->SetElideBehavior(gfx::NO_ELIDE); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/date/date_view.h b/ash/system/date/date_view.h deleted file mode 100644 index 2fadeb4..0000000 --- a/ash/system/date/date_view.h +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DATE_DATE_VIEW_H_ -#define ASH_SYSTEM_DATE_DATE_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/system/date/tray_date.h" -#include "ash/system/tray/actionable_view.h" -#include "base/i18n/time_formatting.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "ui/views/view.h" - -namespace base { -class Time; -} - -namespace views { -class Label; -} - -namespace ash { -namespace tray { - -// Abstract base class containing common updating and layout code for the -// DateView popup and the TimeView tray icon. Exported for tests. -class ASH_EXPORT BaseDateTimeView : public ActionableView { - public: - ~BaseDateTimeView() override; - - // Updates the displayed text for the current time and calls SetTimer(). - void UpdateText(); - - // views::View: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - - protected: - explicit BaseDateTimeView(SystemTrayItem* owner); - - // Updates labels to display the current time. - virtual void UpdateTextInternal(const base::Time& now); - - // Time format (12/24hr) used for accessibility string. - base::HourClockType hour_type_; - - private: - // Starts |timer_| to schedule the next update. - void SetTimer(const base::Time& now); - - // views::View: - void ChildPreferredSizeChanged(views::View* child) override; - void OnLocaleChanged() override; - - // Invokes UpdateText() when the displayed time should change. - base::OneShotTimer timer_; - - DISALLOW_COPY_AND_ASSIGN(BaseDateTimeView); -}; - -// Popup view used to display the date and day of week. -class ASH_EXPORT DateView : public BaseDateTimeView { - public: - enum class DateAction { - NONE, - SET_SYSTEM_TIME, - SHOW_DATE_SETTINGS, - }; - - explicit DateView(SystemTrayItem* owner); - ~DateView() override; - - // Sets the action the view should take. An actionable date view gives visual - // feedback on hover, can be focused by keyboard, and clicking/pressing space - // or enter on the view executes the action. - void SetAction(DateAction action); - - // Updates the format of the displayed time. - void UpdateTimeFormat(); - - base::HourClockType GetHourTypeForTesting() const; - - private: - // Sets active rendering state and updates the color of |date_label_|. - void SetActive(bool active); - - // BaseDateTimeView: - void UpdateTextInternal(const base::Time& now) override; - - // ActionableView: - bool PerformAction(const ui::Event& event) override; - - // views::View: - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - - views::Label* date_label_; - - DateAction action_; - - DISALLOW_COPY_AND_ASSIGN(DateView); -}; - -// Tray view used to display the current time. -// Exported for tests. -class ASH_EXPORT TimeView : public BaseDateTimeView { - public: - enum class ClockLayout { - HORIZONTAL_CLOCK, - VERTICAL_CLOCK, - }; - - explicit TimeView(ClockLayout clock_layout); - ~TimeView() override; - - // Updates the format of the displayed time. - void UpdateTimeFormat(); - - // Updates clock layout. - void UpdateClockLayout(ClockLayout clock_layout); - - base::HourClockType GetHourTypeForTesting() const; - - private: - friend class TimeViewTest; - - // BaseDateTimeView: - void UpdateTextInternal(const base::Time& now) override; - - // ActionableView: - bool PerformAction(const ui::Event& event) override; - - // views::View: - bool OnMousePressed(const ui::MouseEvent& event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - - void SetBorderFromLayout(ClockLayout clock_layout); - void SetupLabels(); - void SetupLabel(views::Label* label); - - // Label text used for the normal horizontal shelf. - std::unique_ptr<views::Label> horizontal_label_; - - // The time label is split into two lines for the vertical shelf. - std::unique_ptr<views::Label> vertical_label_hours_; - std::unique_ptr<views::Label> vertical_label_minutes_; - - DISALLOW_COPY_AND_ASSIGN(TimeView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_DATE_DATE_VIEW_H_
diff --git a/ash/system/date/date_view_unittest.cc b/ash/system/date/date_view_unittest.cc deleted file mode 100644 index 7d5d510e..0000000 --- a/ash/system/date/date_view_unittest.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/date_view.h" - -#include "ash/test/ash_test.h" -#include "ui/views/controls/label.h" - -namespace ash { -namespace tray { - -class TimeViewTest : public AshTest { - public: - TimeViewTest() {} - ~TimeViewTest() override {} - - TimeView* time_view() { return time_view_.get(); } - - // Access to private fields of |time_view_|. - views::Label* horizontal_label() { - return time_view_->horizontal_label_.get(); - } - views::Label* vertical_label_hours() { - return time_view_->vertical_label_hours_.get(); - } - views::Label* vertical_label_minutes() { - return time_view_->vertical_label_minutes_.get(); - } - - // Creates a time view with horizontal or vertical |clock_layout|. - void CreateTimeView(TimeView::ClockLayout clock_layout) { - time_view_.reset(new TimeView(clock_layout)); - } - - private: - std::unique_ptr<TimeView> time_view_; - - DISALLOW_COPY_AND_ASSIGN(TimeViewTest); -}; - -// Test the basics of the time view, mostly to ensure we don't leak memory. -TEST_F(TimeViewTest, Basics) { - // A newly created horizontal clock only has the horizontal label. - CreateTimeView(TimeView::ClockLayout::HORIZONTAL_CLOCK); - EXPECT_EQ(time_view(), horizontal_label()->parent()); - EXPECT_FALSE(vertical_label_hours()->parent()); - EXPECT_FALSE(vertical_label_minutes()->parent()); - - // Switching the clock to vertical updates the labels. - time_view()->UpdateClockLayout(TimeView::ClockLayout::VERTICAL_CLOCK); - EXPECT_FALSE(horizontal_label()->parent()); - EXPECT_EQ(time_view(), vertical_label_hours()->parent()); - EXPECT_EQ(time_view(), vertical_label_minutes()->parent()); - - // Switching back to horizontal updates the labels again. - time_view()->UpdateClockLayout(TimeView::ClockLayout::HORIZONTAL_CLOCK); - EXPECT_EQ(time_view(), horizontal_label()->parent()); - EXPECT_FALSE(vertical_label_hours()->parent()); - EXPECT_FALSE(vertical_label_minutes()->parent()); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/date/system_info_default_view.cc b/ash/system/date/system_info_default_view.cc deleted file mode 100644 index 40a07df..0000000 --- a/ash/system/date/system_info_default_view.cc +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/system_info_default_view.h" - -#include "ash/system/date/date_view.h" -#include "ash/system/power/power_status.h" -#include "ash/system/power/power_status_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/memory/ptr_util.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -// The minimum number of menu button widths that the date view should span -// horizontally. -const int kMinNumTileWidths = 2; - -// The maximum number of menu button widths that the date view should span -// horizontally. -const int kMaxNumTileWidths = 3; - -SystemInfoDefaultView::SystemInfoDefaultView(SystemTrayItem* owner, - LoginStatus login) - : date_view_(nullptr), - tri_view_(TrayPopupUtils::CreateMultiTargetRowView()) { - tri_view_->SetMinHeight(kTrayPopupSystemInfoRowHeight); - AddChildView(tri_view_); - SetLayoutManager(new views::FillLayout); - - date_view_ = new tray::DateView(owner); - tri_view_->AddView(TriView::Container::START, date_view_); - - if (PowerStatus::Get()->IsBatteryPresent()) { - power_status_view_ = new ash::PowerStatusView(false); - std::unique_ptr<views::BoxLayout> box_layout = - base::MakeUnique<views::BoxLayout>(views::BoxLayout::kHorizontal, 0, 0, - 0); - box_layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - box_layout->set_inside_border_insets( - gfx::Insets(0, 0, 0, kTrayPopupLabelRightPadding)); - tri_view_->SetContainerLayout(TriView::Container::CENTER, - std::move(box_layout)); - - tri_view_->AddView(TriView::Container::CENTER, - TrayPopupUtils::CreateVerticalSeparator()); - tri_view_->AddView(TriView::Container::CENTER, power_status_view_); - } - tri_view_->SetContainerVisible(TriView::Container::END, false); - - if (TrayPopupUtils::CanOpenWebUISettings(login)) - date_view_->SetAction(tray::DateView::DateAction::SHOW_DATE_SETTINGS); -} - -SystemInfoDefaultView::~SystemInfoDefaultView() {} - -tray::DateView* SystemInfoDefaultView::GetDateView() { - return date_view_; -} - -const tray::DateView* SystemInfoDefaultView::GetDateView() const { - return date_view_; -} - -void SystemInfoDefaultView::Layout() { - gfx::Size min_start_size = tri_view_->GetMinSize(TriView::Container::START); - min_start_size.set_width( - CalculateDateViewWidth(date_view_->GetPreferredSize().width())); - tri_view_->SetMinSize(TriView::Container::START, min_start_size); - - views::View::Layout(); -} - -int SystemInfoDefaultView::CalculateDateViewWidth(int preferred_width) { - const float snap_to_width = kSeparatorWidth + kMenuButtonSize; - int num_extra_tile_widths = 0; - if (preferred_width > kMenuButtonSize) { - const float extra_width = preferred_width - kMenuButtonSize; - const float preferred_width_ratio = extra_width / snap_to_width; - num_extra_tile_widths = std::ceil(preferred_width_ratio); - } - num_extra_tile_widths = - std::max(kMinNumTileWidths - 1, - std::min(num_extra_tile_widths, kMaxNumTileWidths - 1)); - - return kMenuButtonSize + num_extra_tile_widths * snap_to_width; -} - -} // namespace ash
diff --git a/ash/system/date/system_info_default_view.h b/ash/system/date/system_info_default_view.h deleted file mode 100644 index 287f7c1..0000000 --- a/ash/system/date/system_info_default_view.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DATE_SYSTEM_INFO_DEFAULT_VIEW_H_ -#define ASH_SYSTEM_DATE_SYSTEM_INFO_DEFAULT_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "base/macros.h" -#include "ui/views/view.h" - -namespace ash { -class PowerStatusView; -class SystemTrayItem; -class TriView; - -namespace tray { -class DateView; -} // namespace tray - -// The default view for the system info row in the system menu. Contains the -// current date and, if a battery is present, a string showing the current -// power status. -class ASH_EXPORT SystemInfoDefaultView : public views::View { - public: - SystemInfoDefaultView(SystemTrayItem* owner, LoginStatus login); - - ~SystemInfoDefaultView() override; - - tray::DateView* GetDateView(); - const tray::DateView* GetDateView() const; - - // views::View: - void Layout() override; - - private: - friend class SystemInfoDefaultViewTest; - - // Computes and returns the width for |date_view_| so that the separator to - // its right has the same x-position as a separator in the tiles row above. - // Depending on the width of the date string, we align the separator with - // either the second or third separator in the tiles row (|kMinNumTileWidths| - // and |kMaxNumTileWidths| respectively. - static int CalculateDateViewWidth(int preferred_width); - - tray::DateView* date_view_; - - PowerStatusView* power_status_view_ = nullptr; - - TriView* tri_view_; - - DISALLOW_COPY_AND_ASSIGN(SystemInfoDefaultView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_DATE_SYSTEM_INFO_DEFAULT_VIEW_H_
diff --git a/ash/system/date/system_info_default_view_unittest.cc b/ash/system/date/system_info_default_view_unittest.cc deleted file mode 100644 index 38d1d46..0000000 --- a/ash/system/date/system_info_default_view_unittest.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/system_info_default_view.h" -#include "ash/system/tray/tray_constants.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/view.h" - -namespace ash { - -class SystemInfoDefaultViewTest : public testing::Test { - public: - SystemInfoDefaultViewTest() {} - - protected: - // Wrapper calls for SystemInfoDefaultView internals. - int CalculateDateViewWidth(int preferred_width) { - return SystemInfoDefaultView::CalculateDateViewWidth(preferred_width); - } - - private: - DISALLOW_COPY_AND_ASSIGN(SystemInfoDefaultViewTest); -}; - -TEST_F(SystemInfoDefaultViewTest, PreferredWidthSmallerThanButtonWidth) { - const int kPreferredWidth = 10; - EXPECT_LT(kPreferredWidth, kMenuButtonSize); - const int effective_width = CalculateDateViewWidth(kPreferredWidth); - - EXPECT_EQ(effective_width, - kMenuButtonSize + kSeparatorWidth + kMenuButtonSize); -} - -TEST_F(SystemInfoDefaultViewTest, PreferredWidthGreaterThanOneButtonWidth) { - const int kPreferredWidth = kMenuButtonSize + 1; - const int effective_width = CalculateDateViewWidth(kPreferredWidth); - - EXPECT_EQ(effective_width, - kMenuButtonSize + kSeparatorWidth + kMenuButtonSize); -} - -TEST_F(SystemInfoDefaultViewTest, PreferredWidthEqualToTwoButtonWidths) { - const int kPreferredWidth = - kMenuButtonSize + kSeparatorWidth + kMenuButtonSize; - const int effective_width = CalculateDateViewWidth(kPreferredWidth); - - EXPECT_EQ(effective_width, kPreferredWidth); -} - -TEST_F(SystemInfoDefaultViewTest, PreferredWidthGreaterThanTwoButtonWidths) { - const int kPreferredWidth = - kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) + 1; - const int effective_width = CalculateDateViewWidth(kPreferredWidth); - - EXPECT_EQ(effective_width, - kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2); -} - -TEST_F(SystemInfoDefaultViewTest, PreferredWidthEqualToThreeButtonWidths) { - const int kPreferredWidth = - kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2; - const int effective_width = CalculateDateViewWidth(kPreferredWidth); - - EXPECT_EQ(effective_width, kPreferredWidth); -} - -TEST_F(SystemInfoDefaultViewTest, PreferredWidthGreaterThanThreeButtonWidths) { - const int kPreferredWidth = - kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2 + 1; - const int effective_width = CalculateDateViewWidth(kPreferredWidth); - - EXPECT_EQ(effective_width, - kMenuButtonSize + (kSeparatorWidth + kMenuButtonSize) * 2); -} - -} // namespace ash
diff --git a/ash/system/date/tray_date.cc b/ash/system/date/tray_date.cc deleted file mode 100644 index 28847c1..0000000 --- a/ash/system/date/tray_date.cc +++ /dev/null
@@ -1,126 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/tray_date.h" - -#include "ash/common/wm_shell.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/date/date_default_view.h" -#include "ash/system/date/date_view.h" -#include "ash/system/system_clock_observer.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_item_view.h" - -namespace ash { - -TrayDate::TrayDate(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_DATE), - time_tray_(NULL), - default_view_(NULL), - login_status_(LoginStatus::NOT_LOGGED_IN), - system_clock_observer_(new SystemClockObserver()) { - WmShell::Get()->system_tray_notifier()->AddClockObserver(this); -} - -TrayDate::~TrayDate() { - WmShell::Get()->system_tray_notifier()->RemoveClockObserver(this); -} - -views::View* TrayDate::GetHelpButtonView() const { - if (!default_view_) - return NULL; - return default_view_->GetHelpButtonView(); -} - -const tray::TimeView* TrayDate::GetTimeTrayForTesting() const { - return time_tray_; -} - -const DateDefaultView* TrayDate::GetDefaultViewForTesting() const { - return default_view_; -} - -views::View* TrayDate::CreateDefaultViewForTesting(LoginStatus status) { - return CreateDefaultView(status); -} - -views::View* TrayDate::CreateTrayView(LoginStatus status) { - CHECK(time_tray_ == NULL); - tray::TimeView::ClockLayout clock_layout = - IsHorizontalAlignment(system_tray()->shelf_alignment()) - ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK - : tray::TimeView::ClockLayout::VERTICAL_CLOCK; - time_tray_ = new tray::TimeView(clock_layout); - views::View* view = new TrayItemView(this); - view->AddChildView(time_tray_); - return view; -} - -views::View* TrayDate::CreateDefaultView(LoginStatus status) { - default_view_ = new DateDefaultView(this, status); - - // Save the login status we created the view with. - login_status_ = status; - - OnSystemClockCanSetTimeChanged(system_clock_observer_->can_set_time()); - return default_view_; -} - -views::View* TrayDate::CreateDetailedView(LoginStatus status) { - return NULL; -} - -void TrayDate::DestroyTrayView() { - time_tray_ = NULL; -} - -void TrayDate::DestroyDefaultView() { - default_view_ = NULL; -} - -void TrayDate::DestroyDetailedView() {} - -void TrayDate::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayDate::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - if (time_tray_) { - tray::TimeView::ClockLayout clock_layout = - IsHorizontalAlignment(alignment) - ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK - : tray::TimeView::ClockLayout::VERTICAL_CLOCK; - time_tray_->UpdateClockLayout(clock_layout); - } -} - -void TrayDate::OnDateFormatChanged() { - if (time_tray_) - time_tray_->UpdateTimeFormat(); - if (default_view_) - default_view_->GetDateView()->UpdateTimeFormat(); -} - -void TrayDate::OnSystemClockTimeUpdated() { - if (time_tray_) - time_tray_->UpdateTimeFormat(); - if (default_view_) - default_view_->GetDateView()->UpdateTimeFormat(); -} - -void TrayDate::OnSystemClockCanSetTimeChanged(bool can_set_time) { - // Outside of a logged-in session, the date button should launch the set time - // dialog if the time can be set. - if (default_view_ && login_status_ == LoginStatus::NOT_LOGGED_IN) { - default_view_->GetDateView()->SetAction( - can_set_time ? tray::DateView::DateAction::SET_SYSTEM_TIME - : tray::DateView::DateAction::NONE); - } -} - -void TrayDate::Refresh() { - if (time_tray_) - time_tray_->UpdateText(); -} - -} // namespace ash
diff --git a/ash/system/date/tray_date.h b/ash/system/date/tray_date.h deleted file mode 100644 index 2ef30fb..0000000 --- a/ash/system/date/tray_date.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DATE_TRAY_DATE_H_ -#define ASH_SYSTEM_DATE_TRAY_DATE_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/system/date/clock_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { -class DateDefaultView; -class SystemClockObserver; - -namespace tray { -class TimeView; -} - -// System tray item for the time and date. -class ASH_EXPORT TrayDate : public SystemTrayItem, public ClockObserver { - public: - enum ClockLayout { - HORIZONTAL_CLOCK, - VERTICAL_CLOCK, - }; - - enum DateAction { - NONE, - SET_SYSTEM_TIME, - SHOW_DATE_SETTINGS, - }; - - explicit TrayDate(SystemTray* system_tray); - ~TrayDate() override; - - // Returns view for help button if it is exists. Returns NULL otherwise. - views::View* GetHelpButtonView() const; - - const tray::TimeView* GetTimeTrayForTesting() const; - const DateDefaultView* GetDefaultViewForTesting() const; - views::View* CreateDefaultViewForTesting(LoginStatus status); - - private: - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // Overridden from ClockObserver. - void OnDateFormatChanged() override; - void OnSystemClockTimeUpdated() override; - void OnSystemClockCanSetTimeChanged(bool can_set_time) override; - void Refresh() override; - - tray::TimeView* time_tray_; - DateDefaultView* default_view_; - LoginStatus login_status_; - - std::unique_ptr<SystemClockObserver> system_clock_observer_; - - DISALLOW_COPY_AND_ASSIGN(TrayDate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_DATE_TRAY_DATE_H_
diff --git a/ash/system/date/tray_system_info.cc b/ash/system/date/tray_system_info.cc deleted file mode 100644 index 4b04912..0000000 --- a/ash/system/date/tray_system_info.cc +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/date/tray_system_info.h" - -#include "ash/common/wm_shell.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/date/date_view.h" -#include "ash/system/date/system_info_default_view.h" -#include "ash/system/system_clock_observer.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_item_view.h" - -namespace ash { - -TraySystemInfo::TraySystemInfo(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_DATE), - tray_view_(nullptr), - default_view_(nullptr), - login_status_(LoginStatus::NOT_LOGGED_IN), - system_clock_observer_(new SystemClockObserver()) { - WmShell::Get()->system_tray_notifier()->AddClockObserver(this); -} - -TraySystemInfo::~TraySystemInfo() { - WmShell::Get()->system_tray_notifier()->RemoveClockObserver(this); -} - -const tray::TimeView* TraySystemInfo::GetTimeTrayForTesting() const { - return tray_view_; -} - -const SystemInfoDefaultView* TraySystemInfo::GetDefaultViewForTesting() const { - return default_view_; -} - -views::View* TraySystemInfo::CreateDefaultViewForTesting(LoginStatus status) { - return CreateDefaultView(status); -} - -views::View* TraySystemInfo::CreateTrayView(LoginStatus status) { - CHECK(tray_view_ == nullptr); - tray::TimeView::ClockLayout clock_layout = - IsHorizontalAlignment(system_tray()->shelf_alignment()) - ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK - : tray::TimeView::ClockLayout::VERTICAL_CLOCK; - tray_view_ = new tray::TimeView(clock_layout); - views::View* view = new TrayItemView(this); - view->AddChildView(tray_view_); - return view; -} - -views::View* TraySystemInfo::CreateDefaultView(LoginStatus status) { - default_view_ = new SystemInfoDefaultView(this, status); - - // Save the login status we created the view with. - login_status_ = status; - - OnSystemClockCanSetTimeChanged(system_clock_observer_->can_set_time()); - return default_view_; -} - -void TraySystemInfo::DestroyTrayView() { - tray_view_ = nullptr; -} - -void TraySystemInfo::DestroyDefaultView() { - default_view_ = nullptr; -} - -void TraySystemInfo::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - if (tray_view_) { - tray::TimeView::ClockLayout clock_layout = - IsHorizontalAlignment(alignment) - ? tray::TimeView::ClockLayout::HORIZONTAL_CLOCK - : tray::TimeView::ClockLayout::VERTICAL_CLOCK; - tray_view_->UpdateClockLayout(clock_layout); - } -} - -void TraySystemInfo::OnDateFormatChanged() { - UpdateTimeFormat(); -} - -void TraySystemInfo::OnSystemClockTimeUpdated() { - UpdateTimeFormat(); -} - -void TraySystemInfo::OnSystemClockCanSetTimeChanged(bool can_set_time) { - // Outside of a logged-in session, the date button should launch the set time - // dialog if the time can be set. - if (default_view_ && login_status_ == LoginStatus::NOT_LOGGED_IN) { - default_view_->GetDateView()->SetAction( - can_set_time ? tray::DateView::DateAction::SET_SYSTEM_TIME - : tray::DateView::DateAction::NONE); - } -} - -void TraySystemInfo::Refresh() { - if (tray_view_) - tray_view_->UpdateText(); -} - -void TraySystemInfo::UpdateTimeFormat() { - if (tray_view_) - tray_view_->UpdateTimeFormat(); - if (default_view_) - default_view_->GetDateView()->UpdateTimeFormat(); -} - -} // namespace ash
diff --git a/ash/system/date/tray_system_info.h b/ash/system/date/tray_system_info.h deleted file mode 100644 index 6132b7f..0000000 --- a/ash/system/date/tray_system_info.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ -#define ASH_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/system/date/clock_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace views { -class Label; -} - -namespace ash { -class SystemClockObserver; -class SystemInfoDefaultView; - -namespace tray { -class TimeView; -} - -// The bottom row of the system menu. The default view shows the current date -// and power status. The tray view shows the current time. -class ASH_EXPORT TraySystemInfo : public SystemTrayItem, public ClockObserver { - public: - explicit TraySystemInfo(SystemTray* system_tray); - ~TraySystemInfo() override; - - const tray::TimeView* GetTimeTrayForTesting() const; - const SystemInfoDefaultView* GetDefaultViewForTesting() const; - views::View* CreateDefaultViewForTesting(LoginStatus status); - - private: - // SystemTrayItem: - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // ClockObserver: - void OnDateFormatChanged() override; - void OnSystemClockTimeUpdated() override; - void OnSystemClockCanSetTimeChanged(bool can_set_time) override; - void Refresh() override; - - void SetupLabelForTimeTray(views::Label* label); - void UpdateTimeFormat(); - - tray::TimeView* tray_view_; - SystemInfoDefaultView* default_view_; - LoginStatus login_status_; - - std::unique_ptr<SystemClockObserver> system_clock_observer_; - - DISALLOW_COPY_AND_ASSIGN(TraySystemInfo); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_DATE_TRAY_SYSTEM_INFO_H_
diff --git a/ash/system/devicetype_utils.cc b/ash/system/devicetype_utils.cc deleted file mode 100644 index fed5504..0000000 --- a/ash/system/devicetype_utils.cc +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/devicetype_utils.h" - -#include "ash/strings/grit/ash_strings.h" -#include "chromeos/system/devicetype.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -base::string16 SubstituteChromeOSDeviceType(int resource_id) { - return l10n_util::GetStringFUTF16(resource_id, GetChromeOSDeviceName()); -} - -base::string16 GetChromeOSDeviceName() { - return l10n_util::GetStringUTF16(GetChromeOSDeviceTypeResourceId()); -} - -int GetChromeOSDeviceTypeResourceId() { - switch (chromeos::GetDeviceType()) { - case chromeos::DeviceType::kChromebase: - return IDS_ASH_CHROMEBASE; - case chromeos::DeviceType::kChromebook: - return IDS_ASH_CHROMEBOOK; - case chromeos::DeviceType::kChromebox: - return IDS_ASH_CHROMEBOX; - case chromeos::DeviceType::kChromebit: - return IDS_ASH_CHROMEBIT; - case chromeos::DeviceType::kUnknown: - default: - return IDS_ASH_CHROMEDEVICE; - } -} - -} // namespace ash
diff --git a/ash/system/devicetype_utils.h b/ash/system/devicetype_utils.h deleted file mode 100644 index d958864..0000000 --- a/ash/system/devicetype_utils.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_DEVICETYPE_UTILS_H_ -#define ASH_SYSTEM_DEVICETYPE_UTILS_H_ - -#include "ash/ash_export.h" -#include "base/strings/string16.h" - -namespace ash { - -// Assuming the given localization resources takes a device type parameter, this -// will substitute the appropriate device in (e.g. Chromebook, Chromebox). -ASH_EXPORT base::string16 SubstituteChromeOSDeviceType(int resource_id); - -// Returns the name of the Chrome device type (e.g. Chromebook, Chromebox). -ASH_EXPORT base::string16 GetChromeOSDeviceName(); - -// Returns the resource ID for the current Chrome device type (e.g. Chromebook, -// Chromebox). -ASH_EXPORT int GetChromeOSDeviceTypeResourceId(); - -} // namespace ash - -#endif // ASH_SYSTEM_DEVICETYPE_UTILS_H_
diff --git a/ash/system/enterprise/enterprise_domain_observer.h b/ash/system/enterprise/enterprise_domain_observer.h deleted file mode 100644 index b76d526f..0000000 --- a/ash/system/enterprise/enterprise_domain_observer.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_ENTERPRISE_ENTERPRISE_DOMAIN_OBSERVER_H_ -#define ASH_SYSTEM_ENTERPRISE_ENTERPRISE_DOMAIN_OBSERVER_H_ - -namespace ash { - -class EnterpriseDomainObserver { - public: - virtual ~EnterpriseDomainObserver() {} - - virtual void OnEnterpriseDomainChanged() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_ENTERPRISE_ENTERPRISE_DOMAIN_OBSERVER_H_
diff --git a/ash/system/enterprise/tray_enterprise.cc b/ash/system/enterprise/tray_enterprise.cc deleted file mode 100644 index 747223c..0000000 --- a/ash/system/enterprise/tray_enterprise.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/enterprise/tray_enterprise.h" - -#include "ash/common/login_status.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/system/tray/label_tray_view.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "base/logging.h" -#include "base/strings/string16.h" - -namespace ash { - -TrayEnterprise::TrayEnterprise(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_ENTERPRISE), tray_view_(nullptr) { - WmShell::Get()->system_tray_notifier()->AddEnterpriseDomainObserver(this); -} - -TrayEnterprise::~TrayEnterprise() { - WmShell::Get()->system_tray_notifier()->RemoveEnterpriseDomainObserver(this); -} - -void TrayEnterprise::UpdateEnterpriseMessage() { - base::string16 message = - WmShell::Get()->system_tray_delegate()->GetEnterpriseMessage(); - if (tray_view_) - tray_view_->SetMessage(message); -} - -views::View* TrayEnterprise::CreateDefaultView(LoginStatus status) { - CHECK(tray_view_ == NULL); - // For public accounts, enterprise ownership is indicated in the user details - // instead. - if (status == LoginStatus::PUBLIC) - return NULL; - tray_view_ = new LabelTrayView(this, IDR_AURA_UBER_TRAY_ENTERPRISE); - UpdateEnterpriseMessage(); - return tray_view_; -} - -void TrayEnterprise::DestroyDefaultView() { - tray_view_ = NULL; -} - -void TrayEnterprise::OnEnterpriseDomainChanged() { - UpdateEnterpriseMessage(); -} - -void TrayEnterprise::OnViewClicked(views::View* sender) { - WmShell::Get()->system_tray_delegate()->ShowEnterpriseInfo(); -} - -} // namespace ash
diff --git a/ash/system/enterprise/tray_enterprise.h b/ash/system/enterprise/tray_enterprise.h deleted file mode 100644 index 72f04403..0000000 --- a/ash/system/enterprise/tray_enterprise.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_ENTERPRISE_TRAY_ENTERPRISE_H_ -#define ASH_SYSTEM_ENTERPRISE_TRAY_ENTERPRISE_H_ - -#include "ash/system/enterprise/enterprise_domain_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/view_click_listener.h" -#include "base/macros.h" - -namespace ash { -class LabelTrayView; -class SystemTray; - -class TrayEnterprise : public SystemTrayItem, - public ViewClickListener, - public EnterpriseDomainObserver { - public: - explicit TrayEnterprise(SystemTray* system_tray); - ~TrayEnterprise() override; - - // If message is not empty updates content of default view, otherwise hides - // tray items. - void UpdateEnterpriseMessage(); - - // Overridden from SystemTrayItem. - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyDefaultView() override; - - // Overridden from EnterpriseDomainObserver. - void OnEnterpriseDomainChanged() override; - - // Overridden from ViewClickListener. - void OnViewClicked(views::View* sender) override; - - private: - LabelTrayView* tray_view_; - - DISALLOW_COPY_AND_ASSIGN(TrayEnterprise); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_ENTERPRISE_TRAY_ENTERPRISE_H_
diff --git a/ash/system/ime/ime_observer.h b/ash/system/ime/ime_observer.h deleted file mode 100644 index 1707062..0000000 --- a/ash/system/ime/ime_observer.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_IME_IME_OBSERVER_H_ -#define ASH_SYSTEM_IME_IME_OBSERVER_H_ - -namespace ash { - -class IMEObserver { - public: - virtual ~IMEObserver() {} - - // Notify the observer that the IME state has changed, and should be - // refreshed. - virtual void OnIMERefresh() = 0; - - // Notify the observer that the IME menu activation state has changed, and - // should be refreshed. |is_active| represents whether the new IME menu is - // active, and IME related items in system tray should be removed if - // |is_active| is true. - virtual void OnIMEMenuActivationChanged(bool is_active) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_IME_IME_OBSERVER_H_
diff --git a/ash/system/ime/tray_ime_chromeos.cc b/ash/system/ime/tray_ime_chromeos.cc deleted file mode 100644 index 2660ffc..0000000 --- a/ash/system/ime/tray_ime_chromeos.cc +++ /dev/null
@@ -1,385 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/ime/tray_ime_chromeos.h" - -#include <vector> - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_item_more.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tray_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ash/system/tray_accessibility.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_enums.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/font.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/keyboard/keyboard_util.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace tray { - -// A |HoverHighlightView| that uses bold or normal font depending on whether -// it is selected. This view exposes itself as a checkbox to the accessibility -// framework. -class SelectableHoverHighlightView : public HoverHighlightView { - public: - SelectableHoverHighlightView(ViewClickListener* listener, - const base::string16& label, - bool selected) - : HoverHighlightView(listener), selected_(selected) { - AddLabel(label, gfx::ALIGN_LEFT, selected); - } - - ~SelectableHoverHighlightView() override {} - - protected: - // Overridden from views::View. - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - HoverHighlightView::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_CHECK_BOX; - if (selected_) - node_data->AddStateFlag(ui::AX_STATE_CHECKED); - } - - private: - bool selected_; - - DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView); -}; - -class IMEDefaultView : public TrayItemMore { - public: - IMEDefaultView(SystemTrayItem* owner, const base::string16& label) - : TrayItemMore(owner) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - SetImage(gfx::CreateVectorIcon(kSystemMenuKeyboardIcon, kMenuIconColor)); - } else { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - SetImage(*bundle.GetImageNamed(IDR_AURA_UBER_TRAY_IME).ToImageSkia()); - } - UpdateLabel(label); - } - - ~IMEDefaultView() override {} - - void UpdateLabel(const base::string16& label) { - SetLabel(label); - SetAccessibleName(label); - } - - protected: - // TrayItemMore: - void UpdateStyle() override { - TrayItemMore::UpdateStyle(); - - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - - std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); - SetImage( - gfx::CreateVectorIcon(kSystemMenuKeyboardIcon, style->GetIconColor())); - } - - private: - DISALLOW_COPY_AND_ASSIGN(IMEDefaultView); -}; - -class IMEDetailedView : public ImeListView { - public: - IMEDetailedView(SystemTrayItem* owner, LoginStatus login) - : ImeListView(owner), - login_(login), - settings_(nullptr), - settings_button_(nullptr) {} - - ~IMEDetailedView() override {} - - void SetImeManagedMessage(base::string16 ime_managed_message) { - ime_managed_message_ = ime_managed_message; - } - - void Update(const IMEInfoList& list, - const IMEPropertyInfoList& property_list, - bool show_keyboard_toggle, - SingleImeBehavior single_ime_behavior) override { - ImeListView::Update(list, property_list, show_keyboard_toggle, - single_ime_behavior); - if (!MaterialDesignController::IsSystemTrayMenuMaterial() && - TrayPopupUtils::CanOpenWebUISettings(login_)) { - AppendSettings(); - } - - CreateTitleRow(IDS_ASH_STATUS_TRAY_IME); - } - - private: - // ImeListView: - void HandleViewClicked(views::View* view) override { - ImeListView::HandleViewClicked(view); - if (view == settings_) - ShowSettings(); - } - - void ResetImeListView() override { - ImeListView::ResetImeListView(); - settings_button_ = nullptr; - controlled_setting_icon_ = nullptr; - } - - void HandleButtonPressed(views::Button* sender, - const ui::Event& event) override { - ImeListView::HandleButtonPressed(sender, event); - if (sender == settings_button_) - ShowSettings(); - } - - void CreateExtraTitleRowButtons() override { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - if (!ime_managed_message_.empty()) { - controlled_setting_icon_ = TrayPopupUtils::CreateMainImageView(); - controlled_setting_icon_->SetImage( - gfx::CreateVectorIcon(kSystemMenuBusinessIcon, kMenuIconColor)); - controlled_setting_icon_->SetTooltipText(ime_managed_message_); - tri_view()->AddView(TriView::Container::END, controlled_setting_icon_); - } - - tri_view()->SetContainerVisible(TriView::Container::END, true); - settings_button_ = - CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_IME_SETTINGS); - tri_view()->AddView(TriView::Container::END, settings_button_); - } - } - - void AppendSettings() { - HoverHighlightView* container = new HoverHighlightView(this); - container->AddLabel( - ui::ResourceBundle::GetSharedInstance().GetLocalizedString( - IDS_ASH_STATUS_TRAY_IME_SETTINGS), - gfx::ALIGN_LEFT, false /* highlight */); - AddChildView(container); - settings_ = container; - } - - void ShowSettings() { - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_IME_SHOW_DETAILED); - WmShell::Get()->system_tray_controller()->ShowIMESettings(); - if (owner()->system_tray()) - owner()->system_tray()->CloseSystemBubble(); - } - - LoginStatus login_; - - // Not used in material design. - views::View* settings_; - - // Only used in material design. - views::Button* settings_button_; - - // This icon says that the IMEs are managed by policy. - views::ImageView* controlled_setting_icon_; - // If non-empty, a controlled setting icon should be displayed with this - // string as tooltip. - base::string16 ime_managed_message_; - - DISALLOW_COPY_AND_ASSIGN(IMEDetailedView); -}; - -} // namespace tray - -TrayIME::TrayIME(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_IME), - tray_label_(NULL), - default_(NULL), - detailed_(NULL), - keyboard_suppressed_(false), - is_visible_(true) { - SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); - tray_notifier->AddVirtualKeyboardObserver(this); - tray_notifier->AddAccessibilityObserver(this); - tray_notifier->AddIMEObserver(this); -} - -TrayIME::~TrayIME() { - SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); - tray_notifier->RemoveIMEObserver(this); - tray_notifier->RemoveAccessibilityObserver(this); - tray_notifier->RemoveVirtualKeyboardObserver(this); -} - -void TrayIME::OnKeyboardSuppressionChanged(bool suppressed) { - keyboard_suppressed_ = suppressed; - Update(); -} - -void TrayIME::OnAccessibilityModeChanged( - AccessibilityNotificationVisibility notify) { - Update(); -} - -void TrayIME::Update() { - UpdateTrayLabel(current_ime_, ime_list_.size()); - if (default_) { - default_->SetVisible(ShouldDefaultViewBeVisible()); - default_->UpdateLabel(GetDefaultViewLabel(ime_list_.size() > 1)); - } - if (detailed_) { - detailed_->SetImeManagedMessage(ime_managed_message_); - detailed_->Update(ime_list_, property_list_, ShouldShowKeyboardToggle(), - GetSingleImeBehavior()); - } -} - -void TrayIME::UpdateTrayLabel(const IMEInfo& current, size_t count) { - if (tray_label_) { - bool visible = ShouldShowImeTrayItem(count) && is_visible_; - tray_label_->SetVisible(visible); - // Do not change label before hiding because this change is noticeable. - if (!visible) - return; - if (current.third_party) { - tray_label_->label()->SetText(current.short_name + - base::UTF8ToUTF16("*")); - } else { - tray_label_->label()->SetText(current.short_name); - } - SetTrayLabelItemBorder(tray_label_, system_tray()->shelf_alignment()); - tray_label_->Layout(); - } -} - -bool TrayIME::ShouldShowKeyboardToggle() { - return keyboard_suppressed_ && - !WmShell::Get()->accessibility_delegate()->IsVirtualKeyboardEnabled(); -} - -base::string16 TrayIME::GetDefaultViewLabel(bool show_ime_label) { - if (show_ime_label) { - IMEInfo current; - WmShell::Get()->system_tray_delegate()->GetCurrentIME(¤t); - return current.name; - } else { - // Display virtual keyboard status instead. - int id = keyboard::IsKeyboardEnabled() - ? IDS_ASH_STATUS_TRAY_KEYBOARD_ENABLED - : IDS_ASH_STATUS_TRAY_KEYBOARD_DISABLED; - return ui::ResourceBundle::GetSharedInstance().GetLocalizedString(id); - } -} - -views::View* TrayIME::CreateTrayView(LoginStatus status) { - CHECK(tray_label_ == NULL); - tray_label_ = new TrayItemView(this); - tray_label_->CreateLabel(); - SetupLabelForTray(tray_label_->label()); - // Hide IME tray when it is created, it will be updated when it is notified - // of the IME refresh event. - tray_label_->SetVisible(false); - return tray_label_; -} - -views::View* TrayIME::CreateDefaultView(LoginStatus status) { - CHECK(default_ == NULL); - default_ = new tray::IMEDefaultView( - this, GetDefaultViewLabel(ShouldShowImeTrayItem(ime_list_.size()))); - default_->SetVisible(ShouldDefaultViewBeVisible()); - return default_; -} - -views::View* TrayIME::CreateDetailedView(LoginStatus status) { - CHECK(detailed_ == NULL); - detailed_ = new tray::IMEDetailedView(this, status); - detailed_->SetImeManagedMessage(ime_managed_message_); - detailed_->Init(ShouldShowKeyboardToggle(), GetSingleImeBehavior()); - return detailed_; -} - -void TrayIME::DestroyTrayView() { - tray_label_ = NULL; -} - -void TrayIME::DestroyDefaultView() { - default_ = NULL; -} - -void TrayIME::DestroyDetailedView() { - detailed_ = NULL; -} - -void TrayIME::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - SetTrayLabelItemBorder(tray_label_, alignment); - tray_label_->Layout(); -} - -void TrayIME::OnIMERefresh() { - // Caches the current ime state. - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - ime_list_.clear(); - property_list_.clear(); - delegate->GetCurrentIME(¤t_ime_); - delegate->GetAvailableIMEList(&ime_list_); - delegate->GetCurrentIMEProperties(&property_list_); - ime_managed_message_ = delegate->GetIMEManagedMessage(); - - Update(); -} - -void TrayIME::OnIMEMenuActivationChanged(bool is_active) { - is_visible_ = !is_active; - if (is_visible_) - OnIMERefresh(); - else - Update(); -} - -bool TrayIME::IsIMEManaged() { - return !ime_managed_message_.empty(); -} - -bool TrayIME::ShouldDefaultViewBeVisible() { - return is_visible_ && - (ShouldShowImeTrayItem(ime_list_.size()) || - property_list_.size() > 1 || ShouldShowKeyboardToggle()); -} - -bool TrayIME::ShouldShowImeTrayItem(size_t ime_count) { - // If managed, we want to show the tray icon even if there's only one input - // method to choose from. - size_t threshold = IsIMEManaged() ? 1 : 2; - return ime_count >= threshold; -} - -ImeListView::SingleImeBehavior TrayIME::GetSingleImeBehavior() { - // If managed, we also want to show a single IME. - return IsIMEManaged() ? ImeListView::SHOW_SINGLE_IME - : ImeListView::HIDE_SINGLE_IME; -} - -} // namespace ash
diff --git a/ash/system/ime/tray_ime_chromeos.h b/ash/system/ime/tray_ime_chromeos.h deleted file mode 100644 index 7447f036..0000000 --- a/ash/system/ime/tray_ime_chromeos.h +++ /dev/null
@@ -1,102 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_IME_TRAY_IME_CHROMEOS_H_ -#define ASH_SYSTEM_IME_TRAY_IME_CHROMEOS_H_ - -#include <stddef.h> - -#include "ash/system/accessibility_observer.h" -#include "ash/system/ime/ime_observer.h" -#include "ash/system/ime_menu/ime_list_view.h" -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/virtual_keyboard/virtual_keyboard_observer.h" -#include "base/macros.h" - -namespace ash { - -namespace tray { -class IMEDefaultView; -class IMEDetailedView; -} - -class TrayItemView; - -class ASH_EXPORT TrayIME : public SystemTrayItem, - public IMEObserver, - public AccessibilityObserver, - public VirtualKeyboardObserver { - public: - explicit TrayIME(SystemTray* system_tray); - ~TrayIME() override; - - // Overridden from VirtualKeyboardObserver. - void OnKeyboardSuppressionChanged(bool suppressed) override; - - // Overridden from AccessibilityObserver: - void OnAccessibilityModeChanged( - AccessibilityNotificationVisibility notify) override; - - private: - friend class TrayIMETest; - - // Repopulates the DefaultView and DetailedView. - void Update(); - // Updates the System Tray label. - void UpdateTrayLabel(const IMEInfo& info, size_t count); - // Returns whether the virtual keyboard toggle should be shown in the - // detailed view. - bool ShouldShowKeyboardToggle(); - // Returns the appropriate label for the detailed view. - base::string16 GetDefaultViewLabel(bool show_ime_label); - - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // Overridden from IMEObserver. - void OnIMERefresh() override; - void OnIMEMenuActivationChanged(bool is_active) override; - - // Returns true input methods are managed by policy. - bool IsIMEManaged(); - - // Whether the default view should be shown. - bool ShouldDefaultViewBeVisible(); - - // Decides if a tray icon should be shown. - bool ShouldShowImeTrayItem(size_t ime_count); - // Mandates behavior for the single IME case for the detailed IME list - // sub-view. - ImeListView::SingleImeBehavior GetSingleImeBehavior(); - - TrayItemView* tray_label_; - tray::IMEDefaultView* default_; - tray::IMEDetailedView* detailed_; - // Whether the virtual keyboard is suppressed. - bool keyboard_suppressed_; - // Cached IME info. - IMEInfoList ime_list_; - IMEInfo current_ime_; - IMEPropertyInfoList property_list_; - // If non-empty, a controlled-setting icon should be displayed with a tooltip - // text defined by this string. - base::string16 ime_managed_message_; - - // Whether the IME label and tray items should be visible. - bool is_visible_; - - DISALLOW_COPY_AND_ASSIGN(TrayIME); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_IME_TRAY_IME_CHROMEOS_H_
diff --git a/ash/system/ime/tray_ime_chromeos_unittest.cc b/ash/system/ime/tray_ime_chromeos_unittest.cc deleted file mode 100644 index 4739228..0000000 --- a/ash/system/ime/tray_ime_chromeos_unittest.cc +++ /dev/null
@@ -1,204 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/ime/tray_ime_chromeos.h" - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/accessibility_types.h" -#include "ash/common/wm_shell.h" -#include "ash/system/ime_menu/ime_list_view.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/test/ash_test_base.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/events/devices/device_data_manager.h" -#include "ui/keyboard/keyboard_util.h" - -namespace ash { - -class TrayIMETest : public test::AshTestBase { - public: - TrayIMETest() {} - ~TrayIMETest() override {} - - views::View* default_view() const { return default_view_.get(); } - - views::View* detailed_view() const { return detailed_view_.get(); } - - // Mocks enabling the a11y virtual keyboard since the actual a11y manager - // is not created in ash tests. - void SetAccessibilityKeyboardEnabled(bool enabled); - - // Sets the current number of active IMEs. - void SetIMELength(int length); - - // Returns the view responsible for toggling virtual keyboard. - views::View* GetToggleView() const; - - // Sets the managed IMEs tooltip message (and thus also if IMEs are managed = - // non-empty or not = empty) - void SetManagedMessage(base::string16 managed_message); - - void SuppressKeyboard(); - void RestoreKeyboard(); - - // test::AshTestBase: - void SetUp() override; - void TearDown() override; - - private: - std::unique_ptr<TrayIME> tray_; - std::unique_ptr<views::View> default_view_; - std::unique_ptr<views::View> detailed_view_; - - bool keyboard_suppressed_ = false; - std::vector<ui::TouchscreenDevice> touchscreen_devices_to_restore_; - std::vector<ui::InputDevice> keyboard_devices_to_restore_; - - DISALLOW_COPY_AND_ASSIGN(TrayIMETest); -}; - -void TrayIMETest::SetAccessibilityKeyboardEnabled(bool enabled) { - WmShell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(enabled); - keyboard::SetAccessibilityKeyboardEnabled(enabled); - AccessibilityNotificationVisibility notification = - enabled ? A11Y_NOTIFICATION_SHOW : A11Y_NOTIFICATION_NONE; - WmShell::Get()->system_tray_notifier()->NotifyAccessibilityModeChanged( - notification); -} - -void TrayIMETest::SetIMELength(int length) { - tray_->ime_list_.clear(); - IMEInfo ime; - for (int i = 0; i < length; i++) { - tray_->ime_list_.push_back(ime); - } - tray_->Update(); -} - -views::View* TrayIMETest::GetToggleView() const { - ImeListViewTestApi test_api(static_cast<ImeListView*>(detailed_view())); - return test_api.GetToggleView(); -} - -void TrayIMETest::SetManagedMessage(base::string16 managed_message) { - tray_->ime_managed_message_ = managed_message; - tray_->Update(); -} - -void TrayIMETest::SuppressKeyboard() { - DCHECK(!keyboard_suppressed_); - keyboard_suppressed_ = true; - - ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); - touchscreen_devices_to_restore_ = device_manager->GetTouchscreenDevices(); - keyboard_devices_to_restore_ = device_manager->GetKeyboardDevices(); - - ui::DeviceHotplugEventObserver* manager = - ui::DeviceDataManager::GetInstance(); - std::vector<ui::TouchscreenDevice> screens; - screens.push_back( - ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, - "Touchscreen", gfx::Size(1024, 768), 0)); - manager->OnTouchscreenDevicesUpdated(screens); - - std::vector<ui::InputDevice> keyboards; - keyboards.push_back(ui::InputDevice( - 2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "keyboard")); - manager->OnKeyboardDevicesUpdated(keyboards); -} - -void TrayIMETest::RestoreKeyboard() { - DCHECK(keyboard_suppressed_); - ui::DeviceHotplugEventObserver* manager = - ui::DeviceDataManager::GetInstance(); - manager->OnTouchscreenDevicesUpdated(touchscreen_devices_to_restore_); - manager->OnKeyboardDevicesUpdated(keyboard_devices_to_restore_); -} - -void TrayIMETest::SetUp() { - test::AshTestBase::SetUp(); - tray_.reset(new TrayIME(GetPrimarySystemTray())); - default_view_.reset(tray_->CreateDefaultView(LoginStatus::USER)); - detailed_view_.reset(tray_->CreateDetailedView(LoginStatus::USER)); -} - -void TrayIMETest::TearDown() { - if (keyboard_suppressed_) - RestoreKeyboard(); - SetAccessibilityKeyboardEnabled(false); - tray_.reset(); - default_view_.reset(); - detailed_view_.reset(); - test::AshTestBase::TearDown(); -} - -// Tests that if the keyboard is not suppressed the default view is hidden -// if less than 2 IMEs are present. -TEST_F(TrayIMETest, HiddenWithNoIMEs) { - SetIMELength(0); - EXPECT_FALSE(default_view()->visible()); - SetIMELength(1); - EXPECT_FALSE(default_view()->visible()); - SetIMELength(2); - EXPECT_TRUE(default_view()->visible()); -} - -// Tests that if IMEs are managed, the default view is displayed even for a -// single IME. -TEST_F(TrayIMETest, ShownWithSingleIMEWhenManaged) { - SetManagedMessage(base::ASCIIToUTF16("managed")); - SetIMELength(0); - EXPECT_FALSE(default_view()->visible()); - SetIMELength(1); - EXPECT_TRUE(default_view()->visible()); - SetIMELength(2); - EXPECT_TRUE(default_view()->visible()); -} - -// Tests that if no IMEs are present the default view is hidden when a11y is -// enabled. -TEST_F(TrayIMETest, HidesOnA11yEnabled) { - // TODO: investigate failure in mash. http://crbug.com/695561. - if (WmShell::Get()->IsRunningInMash()) - return; - - SetIMELength(0); - SuppressKeyboard(); - EXPECT_TRUE(default_view()->visible()); - // Enable a11y keyboard. - SetAccessibilityKeyboardEnabled(true); - EXPECT_FALSE(default_view()->visible()); - // Disable the a11y keyboard. - SetAccessibilityKeyboardEnabled(false); - EXPECT_TRUE(default_view()->visible()); -} - -// Tests that clicking on the keyboard toggle causes the virtual keyboard -// to toggle between enabled and disabled. -TEST_F(TrayIMETest, PerformActionOnDetailedView) { - // TODO: investigate failure in mash. http://crbug.com/695561. - if (WmShell::Get()->IsRunningInMash()) - return; - - SetIMELength(0); - SuppressKeyboard(); - EXPECT_FALSE(keyboard::IsKeyboardEnabled()); - views::View* toggle = GetToggleView(); - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - // Enable the keyboard. - toggle->OnGestureEvent(&tap); - EXPECT_TRUE(keyboard::IsKeyboardEnabled()); - EXPECT_TRUE(default_view()->visible()); - - // Clicking again should disable the keyboard. - toggle = GetToggleView(); - tap = ui::GestureEvent(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - toggle->OnGestureEvent(&tap); - EXPECT_FALSE(keyboard::IsKeyboardEnabled()); - EXPECT_TRUE(default_view()->visible()); -} - -} // namespace ash
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc deleted file mode 100644 index 0b2947b8..0000000 --- a/ash/system/ime_menu/ime_list_view.cc +++ /dev/null
@@ -1,469 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/ime_menu/ime_list_view.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_popup_header_button.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/keyboard/keyboard_util.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/toggle_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/painter.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -const int kMinFontSizeDelta = -10; - -const SkColor kKeyboardRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); - -// A |HoverHighlightView| that uses bold or normal font depending on whether it -// is selected. This view exposes itself as a checkbox to the accessibility -// framework. -class SelectableHoverHighlightView : public HoverHighlightView { - public: - SelectableHoverHighlightView(ViewClickListener* listener, - const base::string16& label, - bool selected) - : HoverHighlightView(listener), selected_(selected) { - AddLabel(label, gfx::ALIGN_LEFT, selected); - } - - ~SelectableHoverHighlightView() override {} - - protected: - // views::View: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - HoverHighlightView::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_CHECK_BOX; - if (selected_) - node_data->AddStateFlag(ui::AX_STATE_CHECKED); - } - - private: - bool selected_; - - DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView); -}; - -// The IME list item view used in the material design. It contains IME info -// (name and label) and a check button if the item is selected. It's also used -// for IME property item, which has no name but label and a gray checked icon. -class ImeListItemView : public ActionableView { - public: - ImeListItemView(SystemTrayItem* owner, - ImeListView* list_view, - const base::string16& id, - const base::string16& label, - bool selected, - const SkColor button_color) - : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), - ime_list_view_(list_view), - selected_(selected) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - SetInkDropMode(InkDropHostView::InkDropMode::ON); - - TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view); - SetLayoutManager(new views::FillLayout); - - // The id button shows the IME short name. - views::Label* id_label = TrayPopupUtils::CreateDefaultLabel(); - id_label->SetText(id); - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const gfx::FontList& base_font_list = - rb.GetFontList(ui::ResourceBundle::MediumBoldFont); - id_label->SetFontList(base_font_list); - - // For IMEs whose short name are more than 2 characters (INTL, EXTD, etc.), - // |kMenuIconSize| is not enough. The label will trigger eliding as "I..." - // or "...". So we shrink the font size until it fits within the bounds. - int size_delta = -1; - while ((id_label->GetPreferredSize().width() - - id_label->GetInsets().width()) > kMenuIconSize && - size_delta >= kMinFontSizeDelta) { - id_label->SetFontList(base_font_list.DeriveWithSizeDelta(size_delta)); - --size_delta; - } - tri_view->AddView(TriView::Container::START, id_label); - - // The label shows the IME name. - auto* label_view = TrayPopupUtils::CreateDefaultLabel(); - label_view->SetText(label); - TrayPopupItemStyle style( - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - style.SetupLabel(label_view); - - label_view->SetHorizontalAlignment(gfx::ALIGN_LEFT); - tri_view->AddView(TriView::Container::CENTER, label_view); - - if (selected) { - // The checked button indicates the IME is selected. - views::ImageView* checked_image = TrayPopupUtils::CreateMainImageView(); - checked_image->SetImage(gfx::CreateVectorIcon( - gfx::VectorIconId::CHECK_CIRCLE, kMenuIconSize, button_color)); - tri_view->AddView(TriView::Container::END, checked_image); - } - SetAccessibleName(label_view->text()); - } - - ~ImeListItemView() override {} - - // ActionableView: - bool PerformAction(const ui::Event& event) override { - if (ime_list_view_->should_focus_ime_after_selection_with_keyboard() && - event.type() == ui::EventType::ET_KEY_PRESSED) { - ime_list_view_->set_last_item_selected_with_keyboard(true); - } else { - ime_list_view_->set_last_item_selected_with_keyboard(false); - } - - ime_list_view_->HandleViewClicked(this); - return true; - } - - void OnFocus() override { - ActionableView::OnFocus(); - if (ime_list_view_ && ime_list_view_->scroll_content()) - ime_list_view_->scroll_content()->ScrollRectToVisible(bounds()); - } - - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - ActionableView::GetAccessibleNodeData(node_data); - node_data->role = ui::AX_ROLE_CHECK_BOX; - node_data->AddStateFlag(selected_ ? ui::AX_STATE_CHECKED - : ui::AX_STATE_NONE); - } - - private: - ImeListView* ime_list_view_; - bool selected_; - - DISALLOW_COPY_AND_ASSIGN(ImeListItemView); -}; - -} // namespace - -// The view that contains a |KeyboardButtonView| and a toggle button. -class MaterialKeyboardStatusRowView : public views::View { - public: - MaterialKeyboardStatusRowView(views::ButtonListener* listener, bool enabled) - : listener_(listener), toggle_(nullptr) { - Init(); - toggle_->SetIsOn(enabled, false); - } - - ~MaterialKeyboardStatusRowView() override {} - - views::Button* toggle() const { return toggle_; } - bool is_toggled() const { return toggle_->is_on(); } - - protected: - // views::View: - int GetHeightForWidth(int w) const override { - return GetPreferredSize().height(); - } - - private: - void Init() { - TrayPopupUtils::ConfigureAsStickyHeader(this); - SetLayoutManager(new views::FillLayout); - - TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view); - - // The on-screen keyboard image button. - views::ImageView* keyboard_image = TrayPopupUtils::CreateMainImageView(); - keyboard_image->SetImage(gfx::CreateVectorIcon( - kImeMenuOnScreenKeyboardIcon, kMenuIconSize, kMenuIconColor)); - tri_view->AddView(TriView::Container::START, keyboard_image); - - // The on-screen keyboard label ('On-screen keyboard'). - auto* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(ui::ResourceBundle::GetSharedInstance().GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD)); - TrayPopupItemStyle style( - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - style.SetupLabel(label); - tri_view->AddView(TriView::Container::CENTER, label); - - // The on-screen keyboard toggle button. - toggle_ = TrayPopupUtils::CreateToggleButton( - listener_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD); - tri_view->AddView(TriView::Container::END, toggle_); - } - - // ButtonListener to notify when |toggle_| is clicked. - views::ButtonListener* listener_; - - // ToggleButton to toggle keyboard on or off. - views::ToggleButton* toggle_; - - DISALLOW_COPY_AND_ASSIGN(MaterialKeyboardStatusRowView); -}; - -ImeListView::ImeListView(SystemTrayItem* owner) - : TrayDetailsView(owner), - last_item_selected_with_keyboard_(false), - should_focus_ime_after_selection_with_keyboard_(false), - current_ime_view_(nullptr) {} - -ImeListView::~ImeListView() {} - -void ImeListView::Init(bool show_keyboard_toggle, - SingleImeBehavior single_ime_behavior) { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - IMEInfoList list; - delegate->GetAvailableIMEList(&list); - IMEPropertyInfoList property_list; - delegate->GetCurrentIMEProperties(&property_list); - Update(list, property_list, show_keyboard_toggle, single_ime_behavior); -} - -void ImeListView::Update(const IMEInfoList& list, - const IMEPropertyInfoList& property_list, - bool show_keyboard_toggle, - SingleImeBehavior single_ime_behavior) { - ResetImeListView(); - ime_map_.clear(); - property_map_.clear(); - CreateScrollableList(); - - // Appends IME list and IME properties. - if (single_ime_behavior == ImeListView::SHOW_SINGLE_IME || list.size() > 1) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - AppendImeListAndProperties(list, property_list); - } else { - AppendIMEList(list); - if (!property_list.empty()) - AppendIMEProperties(property_list); - } - } - - if (show_keyboard_toggle) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - PrependMaterialKeyboardStatus(); - } else { - if (list.size() > 1 || !property_list.empty()) - AddScrollSeparator(); - AppendKeyboardStatus(); - } - } - - Layout(); - SchedulePaint(); - - if (should_focus_ime_after_selection_with_keyboard_ && - last_item_selected_with_keyboard_) { - FocusCurrentImeIfNeeded(); - } else if (current_ime_view_) { - scroll_content()->ScrollRectToVisible(current_ime_view_->bounds()); - } -} - -void ImeListView::ResetImeListView() { - // Children are removed from the view hierarchy and deleted in Reset(). - Reset(); - material_keyboard_status_view_ = nullptr; - keyboard_status_ = nullptr; - current_ime_view_ = nullptr; -} - -void ImeListView::CloseImeListView() { - last_selected_item_id_.clear(); - current_ime_view_ = nullptr; - last_item_selected_with_keyboard_ = false; - GetWidget()->Close(); -} - -void ImeListView::AppendIMEList(const IMEInfoList& list) { - DCHECK(ime_map_.empty()); - for (size_t i = 0; i < list.size(); i++) { - HoverHighlightView* container = - new SelectableHoverHighlightView(this, list[i].name, list[i].selected); - scroll_content()->AddChildView(container); - ime_map_[container] = list[i].id; - } -} - -void ImeListView::AppendIMEProperties( - const IMEPropertyInfoList& property_list) { - DCHECK(property_map_.empty()); - for (size_t i = 0; i < property_list.size(); i++) { - HoverHighlightView* container = new SelectableHoverHighlightView( - this, property_list[i].name, property_list[i].selected); - if (i == 0) - container->SetBorder( - views::CreateSolidSidedBorder(1, 0, 0, 0, kBorderLightColor)); - scroll_content()->AddChildView(container); - property_map_[container] = property_list[i].key; - } -} - -void ImeListView::AppendImeListAndProperties( - const IMEInfoList& list, - const IMEPropertyInfoList& property_list) { - DCHECK(ime_map_.empty()); - for (size_t i = 0; i < list.size(); i++) { - views::View* ime_view = - new ImeListItemView(owner(), this, list[i].short_name, list[i].name, - list[i].selected, gfx::kGoogleGreen700); - scroll_content()->AddChildView(ime_view); - ime_map_[ime_view] = list[i].id; - - if (list[i].selected) - current_ime_view_ = ime_view; - - // In material design, the property items will be added after the current - // selected IME item. - if (list[i].selected && !property_list.empty()) { - // Adds a separator on the top of property items. - scroll_content()->AddChildView( - TrayPopupUtils::CreateListItemSeparator(true)); - - // Adds the property items. - for (size_t i = 0; i < property_list.size(); i++) { - ImeListItemView* property_view = new ImeListItemView( - owner(), this, base::string16(), property_list[i].name, - property_list[i].selected, kMenuIconColor); - scroll_content()->AddChildView(property_view); - property_map_[property_view] = property_list[i].key; - } - - // Adds a separator on the bottom of property items if there are still - // other IMEs under the current one. - if (i < list.size() - 1) - scroll_content()->AddChildView( - TrayPopupUtils::CreateListItemSeparator(true)); - } - } -} - -void ImeListView::AppendKeyboardStatus() { - DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); - HoverHighlightView* container = new HoverHighlightView(this); - int id = keyboard::IsKeyboardEnabled() ? IDS_ASH_STATUS_TRAY_DISABLE_KEYBOARD - : IDS_ASH_STATUS_TRAY_ENABLE_KEYBOARD; - container->AddLabel( - ui::ResourceBundle::GetSharedInstance().GetLocalizedString(id), - gfx::ALIGN_LEFT, false /* highlight */); - scroll_content()->AddChildView(container); - keyboard_status_ = container; -} - -void ImeListView::PrependMaterialKeyboardStatus() { - DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); - DCHECK(!material_keyboard_status_view_); - MaterialKeyboardStatusRowView* view = - new MaterialKeyboardStatusRowView(this, keyboard::IsKeyboardEnabled()); - scroll_content()->AddChildViewAt(view, 0); - material_keyboard_status_view_ = view; -} - -void ImeListView::HandleViewClicked(views::View* view) { - if (view == keyboard_status_) { - WmShell::Get()->ToggleIgnoreExternalKeyboard(); - last_selected_item_id_.clear(); - last_item_selected_with_keyboard_ = false; - return; - } - - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - std::map<views::View*, std::string>::const_iterator ime = ime_map_.find(view); - if (ime != ime_map_.end()) { - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_IME_SWITCH_MODE); - std::string ime_id = ime->second; - last_selected_item_id_ = ime_id; - delegate->SwitchIME(ime_id); - } else { - std::map<views::View*, std::string>::const_iterator property = - property_map_.find(view); - if (property == property_map_.end()) - return; - const std::string key = property->second; - last_selected_item_id_ = key; - delegate->ActivateIMEProperty(key); - } - - if (!should_focus_ime_after_selection_with_keyboard_ || - !last_item_selected_with_keyboard_) { - CloseImeListView(); - } -} - -void ImeListView::HandleButtonPressed(views::Button* sender, - const ui::Event& event) { - if (material_keyboard_status_view_ && - sender == material_keyboard_status_view_->toggle()) { - WmShell::Get()->ToggleIgnoreExternalKeyboard(); - last_selected_item_id_.clear(); - last_item_selected_with_keyboard_ = false; - } -} - -void ImeListView::VisibilityChanged(View* starting_from, bool is_visible) { - if (!is_visible || (should_focus_ime_after_selection_with_keyboard_ && - last_item_selected_with_keyboard_) || - !current_ime_view_) { - return; - } - - scroll_content()->ScrollRectToVisible(current_ime_view_->bounds()); -} - -void ImeListView::FocusCurrentImeIfNeeded() { - views::FocusManager* manager = GetFocusManager(); - if (!manager || manager->GetFocusedView() || last_selected_item_id_.empty()) - return; - - for (auto ime_map : ime_map_) { - if (ime_map.second == last_selected_item_id_) { - (ime_map.first)->RequestFocus(); - return; - } - } - - for (auto property_map : property_map_) { - if (property_map.second == last_selected_item_id_) { - (property_map.first)->RequestFocus(); - return; - } - } -} - -ImeListViewTestApi::ImeListViewTestApi(ImeListView* ime_list_view) - : ime_list_view_(ime_list_view) {} - -ImeListViewTestApi::~ImeListViewTestApi() {} - -views::View* ImeListViewTestApi::GetToggleView() const { - return ime_list_view_->material_keyboard_status_view_->toggle(); -} - -} // namespace ash
diff --git a/ash/system/ime_menu/ime_list_view.h b/ash/system/ime_menu/ime_list_view.h deleted file mode 100644 index 526122485..0000000 --- a/ash/system/ime_menu/ime_list_view.h +++ /dev/null
@@ -1,135 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_IME_MENU_IME_LIST_VIEW_H_ -#define ASH_SYSTEM_IME_MENU_IME_LIST_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/tray_details_view.h" -#include "ui/views/controls/button/button.h" - -namespace ash { -class MaterialKeyboardStatusRowView; - -// The detailed view for showing IME list. -class ImeListView : public TrayDetailsView { - public: - enum SingleImeBehavior { - // Shows the IME menu if there's only one IME in system. - SHOW_SINGLE_IME, - // Hides the IME menu if there's only one IME in system. - HIDE_SINGLE_IME - }; - - ImeListView(SystemTrayItem* owner); - - ~ImeListView() override; - - // Initializes the contents of a newly-instantiated ImeListView. - void Init(bool show_keyboard_toggle, SingleImeBehavior single_ime_behavior); - - // Updates the view. - virtual void Update(const IMEInfoList& list, - const IMEPropertyInfoList& property_list, - bool show_keyboard_toggle, - SingleImeBehavior single_ime_behavior); - - // Removes (and destroys) all child views. - virtual void ResetImeListView(); - - // Closes the view. - void CloseImeListView(); - - void set_last_item_selected_with_keyboard( - bool last_item_selected_with_keyboard) { - last_item_selected_with_keyboard_ = last_item_selected_with_keyboard; - } - - void set_should_focus_ime_after_selection_with_keyboard( - const bool focus_current_ime) { - should_focus_ime_after_selection_with_keyboard_ = focus_current_ime; - } - - bool should_focus_ime_after_selection_with_keyboard() const { - return should_focus_ime_after_selection_with_keyboard_; - } - - // TrayDetailsView: - void HandleViewClicked(views::View* view) override; - void HandleButtonPressed(views::Button* sender, - const ui::Event& event) override; - - // views::View: - void VisibilityChanged(View* starting_from, bool is_visible) override; - - private: - friend class ImeListViewTestApi; - - // Appends the IMEs to the scrollable area of the detailed view. - void AppendIMEList(const IMEInfoList& list); - - // Appends the IME listed to the scrollable area of the detailed view. - void AppendIMEProperties(const IMEPropertyInfoList& property_list); - - // Appends the IMEs and properties to the scrollable area in the material - // design IME menu. - void AppendImeListAndProperties(const IMEInfoList& list, - const IMEPropertyInfoList& property_list); - - // Appends the on-screen keyboard status to the last area of the detailed - // view. - void AppendKeyboardStatus(); - - // Inserts the material on-screen keyboard status in the detailed view. - void PrependMaterialKeyboardStatus(); - - // Requests focus on the current IME if it was selected with keyboard so that - // accessible text will alert the user of the IME change. - void FocusCurrentImeIfNeeded(); - - std::map<views::View*, std::string> ime_map_; - std::map<views::View*, std::string> property_map_; - // On-screen keyboard view which is not used in material design. - views::View* keyboard_status_; - // On-screen keyboard view which is only used in material design. - MaterialKeyboardStatusRowView* material_keyboard_status_view_; - - // The id of the last item selected with keyboard. It will be empty if the - // item is not selected with keyboard. - std::string last_selected_item_id_; - - // True if the last item is selected with keyboard. - bool last_item_selected_with_keyboard_; - - // True if focus should be requested after switching IMEs with keyboard in - // order to trigger spoken feedback with ChromeVox enabled. - bool should_focus_ime_after_selection_with_keyboard_; - - // The item view of the current selected IME. - views::View* current_ime_view_; - - DISALLOW_COPY_AND_ASSIGN(ImeListView); -}; - -class ASH_EXPORT ImeListViewTestApi { - public: - explicit ImeListViewTestApi(ImeListView* ime_list_view); - virtual ~ImeListViewTestApi(); - - views::View* GetToggleView() const; - - const std::map<views::View*, std::string>& ime_map() const { - return ime_list_view_->ime_map_; - } - - private: - ImeListView* ime_list_view_; - - DISALLOW_COPY_AND_ASSIGN(ImeListViewTestApi); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_IME_MENU_IME_LIST_VIEW_H_
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc deleted file mode 100644 index 700207fd..0000000 --- a/ash/system/ime_menu/ime_menu_tray.cc +++ /dev/null
@@ -1,650 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/ime_menu/ime_menu_tray.h" - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/ash_constants.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/ime_menu/ime_list_view.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tray_utils.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/ime/chromeos/input_method_manager.h" -#include "ui/base/ime/ime_bridge.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/range/range.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_util.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" - -using chromeos::input_method::InputMethodManager; - -namespace ash { - -namespace { -// Returns the height range of ImeListView. -gfx::Range GetImeListViewRange() { - const int max_items = 5; - const int min_items = 1; - const int tray_item_height = kTrayPopupItemMinHeight; - return gfx::Range(tray_item_height * min_items, tray_item_height * max_items); -} - -// Returns the minimum with of IME menu. -int GetMinimumMenuWidth() { - return MaterialDesignController::IsSystemTrayMenuMaterial() - ? kTrayMenuMinimumWidthMd - : kTrayMenuMinimumWidth; -} - -// Shows language and input settings page. -void ShowIMESettings() { - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_IME_SHOW_DETAILED); - WmShell::Get()->system_tray_controller()->ShowIMESettings(); -} - -// Records the number of times users click buttons in opt-in IME menu. -void RecordButtonsClicked(const std::string& button_name) { - enum { - UNKNOWN = 0, - EMOJI = 1, - HANDWRITING = 2, - VOICE = 3, - // SETTINGS is not used for now. - SETTINGS = 4, - BUTTON_MAX - } button = UNKNOWN; - if (button_name == "emoji") { - button = EMOJI; - } else if (button_name == "hwt") { - button = HANDWRITING; - } else if (button_name == "voice") { - button = VOICE; - } - UMA_HISTOGRAM_ENUMERATION("InputMethod.ImeMenu.EmojiHandwritingVoiceButton", - button, BUTTON_MAX); -} - -// Returns true if the current screen is login or lock screen. -bool IsInLoginOrLockScreen() { - LoginStatus login = - WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); - return !TrayPopupUtils::CanOpenWebUISettings(login); -} - -// Returns true if the current input context type is password. -bool IsInPasswordInputContext() { - return ui::IMEBridge::Get()->GetCurrentInputContext().type == - ui::TEXT_INPUT_TYPE_PASSWORD; -} - -class ImeMenuLabel : public views::Label { - public: - ImeMenuLabel() {} - ~ImeMenuLabel() override {} - - // views:Label: - gfx::Size GetPreferredSize() const override { - return gfx::Size(kTrayItemSize, kTrayItemSize); - } - int GetHeightForWidth(int width) const override { return kTrayItemSize; } - - private: - DISALLOW_COPY_AND_ASSIGN(ImeMenuLabel); -}; - -SystemMenuButton* CreateImeMenuButton(views::ButtonListener* listener, - const gfx::VectorIcon& icon, - int accessible_name_id, - int right_border) { - SystemMenuButton* button = new SystemMenuButton( - listener, TrayPopupInkDropStyle::HOST_CENTERED, icon, accessible_name_id); - if (!MaterialDesignController::IsShelfMaterial()) { - button->SetBorder( - views::CreateSolidSidedBorder(0, 0, 0, right_border, kBorderDarkColor)); - } - return button; -} - -// The view that contains IME menu title in the material design. -class ImeTitleView : public views::View, public views::ButtonListener { - public: - explicit ImeTitleView(bool show_settings_button) : settings_button_(nullptr) { - SetBorder(views::CreatePaddedBorder( - views::CreateSolidSidedBorder(0, 0, kSeparatorWidth, 0, - kMenuSeparatorColor), - gfx::Insets(kMenuSeparatorVerticalPadding - kSeparatorWidth, 0))); - auto* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - box_layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); - SetLayoutManager(box_layout); - auto* title_label = - new views::Label(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME)); - title_label->SetBorder( - views::CreateEmptyBorder(0, kMenuEdgeEffectivePadding, 1, 0)); - title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); - style.SetupLabel(title_label); - - AddChildView(title_label); - box_layout->SetFlexForView(title_label, 1); - - if (show_settings_button) { - settings_button_ = CreateImeMenuButton( - this, kSystemMenuSettingsIcon, IDS_ASH_STATUS_TRAY_IME_SETTINGS, 0); - if (IsInLoginOrLockScreen()) - settings_button_->SetEnabled(false); - AddChildView(settings_button_); - } - } - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override { - DCHECK_EQ(sender, settings_button_); - ShowIMESettings(); - } - - ~ImeTitleView() override {} - - private: - // Settings button that is only used in material design, and only if the - // emoji, handwriting and voice buttons are not available. - SystemMenuButton* settings_button_; - - DISALLOW_COPY_AND_ASSIGN(ImeTitleView); -}; - -// The view that contains buttons shown on the bottom of IME menu. -class ImeButtonsView : public views::View, - public views::ButtonListener, - public ViewClickListener { - public: - ImeButtonsView(ImeMenuTray* ime_menu_tray, - bool show_emoji_button, - bool show_voice_button, - bool show_handwriting_button, - bool show_settings_button) - : ime_menu_tray_(ime_menu_tray) { - DCHECK(ime_menu_tray_); - - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) - SetBorder(views::CreateSolidSidedBorder(1, 0, 0, 0, kBorderDarkColor)); - - // If there's only one settings button, the bottom should be a label with - // normal background. Otherwise, show button icons with header background. - if (show_settings_button && !show_emoji_button && - !show_handwriting_button && !show_voice_button) { - DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); - ShowOneSettingButton(); - } else { - ShowButtons(show_emoji_button, show_handwriting_button, show_voice_button, - show_settings_button); - } - } - - ~ImeButtonsView() override {} - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override { - if (sender == settings_button_) { - ime_menu_tray_->HideImeMenuBubble(); - ShowIMESettings(); - return; - } - - // The |keyset| will be used for drawing input view keyset in IME - // extensions. InputMethodManager::ShowKeyboardWithKeyset() will deal with - // the |keyset| string to generate the right input view url. - std::string keyset; - if (sender == emoji_button_) { - keyset = "emoji"; - RecordButtonsClicked(keyset); - } else if (sender == voice_button_) { - keyset = "voice"; - RecordButtonsClicked(keyset); - } else if (sender == handwriting_button_) { - keyset = "hwt"; - RecordButtonsClicked(keyset); - } else { - NOTREACHED(); - } - - ime_menu_tray_->ShowKeyboardWithKeyset(keyset); - } - - // ViewClickListener: - void OnViewClicked(views::View* sender) override { - if (one_settings_button_view_ && sender == one_settings_button_view_) { - ime_menu_tray_->HideImeMenuBubble(); - ShowIMESettings(); - } - } - - private: - // Shows the UI of one settings button. - void ShowOneSettingButton() { - auto* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - box_layout->SetDefaultFlex(1); - SetLayoutManager(box_layout); - one_settings_button_view_ = new HoverHighlightView(this); - one_settings_button_view_->AddLabel( - ui::ResourceBundle::GetSharedInstance().GetLocalizedString( - IDS_ASH_STATUS_TRAY_IME_SETTINGS), - gfx::ALIGN_LEFT, false /* highlight */); - if (IsInLoginOrLockScreen()) - one_settings_button_view_->SetEnabled(false); - AddChildView(one_settings_button_view_); - } - - // Shows the UI of more than one buttons. - void ShowButtons(bool show_emoji_button, - bool show_handwriting_button, - bool show_voice_button, - bool show_settings_button) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - auto* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - box_layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); - SetLayoutManager(box_layout); - SetBorder(views::CreatePaddedBorder( - views::CreateSolidSidedBorder(kSeparatorWidth, 0, 0, 0, - kMenuSeparatorColor), - gfx::Insets(kMenuSeparatorVerticalPadding - kSeparatorWidth, - kMenuExtraMarginFromLeftEdge))); - } else { - auto* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 4, 4, 0); - set_background( - views::Background::CreateSolidBackground(kHeaderBackgroundColor)); - box_layout->SetDefaultFlex(1); - SetLayoutManager(box_layout); - } - - const int right_border = 1; - if (show_emoji_button) { - emoji_button_ = - CreateImeMenuButton(this, kImeMenuEmoticonIcon, - IDS_ASH_STATUS_TRAY_IME_EMOJI, right_border); - AddChildView(emoji_button_); - } - - if (show_handwriting_button) { - handwriting_button_ = CreateImeMenuButton( - this, kImeMenuWriteIcon, IDS_ASH_STATUS_TRAY_IME_HANDWRITING, - right_border); - AddChildView(handwriting_button_); - } - - if (show_voice_button) { - voice_button_ = - CreateImeMenuButton(this, kImeMenuMicrophoneIcon, - IDS_ASH_STATUS_TRAY_IME_VOICE, right_border); - AddChildView(voice_button_); - } - - if (show_settings_button) { - settings_button_ = CreateImeMenuButton( - this, kSystemMenuSettingsIcon, IDS_ASH_STATUS_TRAY_IME_SETTINGS, 0); - AddChildView(settings_button_); - } - } - - ImeMenuTray* ime_menu_tray_; - SystemMenuButton* emoji_button_; - SystemMenuButton* handwriting_button_; - SystemMenuButton* voice_button_; - SystemMenuButton* settings_button_; - HoverHighlightView* one_settings_button_view_; - - DISALLOW_COPY_AND_ASSIGN(ImeButtonsView); -}; - -// The list view that contains the selected IME and property items. -class ImeMenuListView : public ImeListView { - public: - ImeMenuListView(SystemTrayItem* owner) : ImeListView(owner) { - set_should_focus_ime_after_selection_with_keyboard(true); - } - - ~ImeMenuListView() override {} - - protected: - void Layout() override { - gfx::Range height_range = GetImeListViewRange(); - scroller()->ClipHeightTo(height_range.start(), height_range.end()); - ImeListView::Layout(); - } - - DISALLOW_COPY_AND_ASSIGN(ImeMenuListView); -}; - -} // namespace - -ImeMenuTray::ImeMenuTray(WmShelf* wm_shelf) - : TrayBackgroundView(wm_shelf), - label_(new ImeMenuLabel()), - show_keyboard_(false), - force_show_keyboard_(false), - should_block_shelf_auto_hide_(false), - keyboard_suppressed_(false), - show_bubble_after_keyboard_hidden_(false) { - if (MaterialDesignController::IsShelfMaterial()) { - SetInkDropMode(InkDropMode::ON); - SetContentsBackground(false); - } else { - SetContentsBackground(true); - } - SetupLabelForTray(label_); - tray_container()->AddChildView(label_); - SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); - tray_notifier->AddIMEObserver(this); - tray_notifier->AddVirtualKeyboardObserver(this); -} - -ImeMenuTray::~ImeMenuTray() { - if (bubble_) - bubble_->bubble_view()->reset_delegate(); - SystemTrayNotifier* tray_notifier = WmShell::Get()->system_tray_notifier(); - tray_notifier->RemoveIMEObserver(this); - tray_notifier->RemoveVirtualKeyboardObserver(this); - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) - keyboard_controller->RemoveObserver(this); -} - -void ImeMenuTray::ShowImeMenuBubble() { - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller && keyboard_controller->keyboard_visible()) { - show_bubble_after_keyboard_hidden_ = true; - keyboard_controller->AddObserver(this); - keyboard_controller->HideKeyboard( - keyboard::KeyboardController::HIDE_REASON_AUTOMATIC); - } else { - ShowImeMenuBubbleInternal(); - } -} - -void ImeMenuTray::ShowImeMenuBubbleInternal() { - int minimum_menu_width = GetMinimumMenuWidth(); - should_block_shelf_auto_hide_ = true; - views::TrayBubbleView::InitParams init_params( - GetAnchorAlignment(), minimum_menu_width, minimum_menu_width); - init_params.can_activate = true; - init_params.close_on_deactivate = true; - - views::TrayBubbleView* bubble_view = - views::TrayBubbleView::Create(GetBubbleAnchor(), this, &init_params); - bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets()); - - // In the material design, we will add a title item with a separator on the - // top of the IME menu. - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - bubble_view->AddChildView( - new ImeTitleView(!ShouldShowEmojiHandwritingVoiceButtons())); - } else { - bubble_view->set_margins(gfx::Insets(7, 0, 0, 0)); - } - - // Adds IME list to the bubble. - ime_list_view_ = new ImeMenuListView(nullptr); - ime_list_view_->Init(ShouldShowKeyboardToggle(), - ImeListView::SHOW_SINGLE_IME); - bubble_view->AddChildView(ime_list_view_); - - if (ShouldShowEmojiHandwritingVoiceButtons()) { - bubble_view->AddChildView(new ImeButtonsView(this, true, true, true, true)); - } else if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { - // For MD, we don't need |ImeButtonsView| as the settings button will be - // shown in the title row. - bubble_view->AddChildView( - new ImeButtonsView(this, false, false, false, true)); - } - - bubble_.reset(new TrayBubbleWrapper(this, bubble_view)); - SetIsActive(true); -} - -void ImeMenuTray::HideImeMenuBubble() { - bubble_.reset(); - ime_list_view_ = nullptr; - SetIsActive(false); - should_block_shelf_auto_hide_ = false; - shelf()->UpdateAutoHideState(); -} - -bool ImeMenuTray::IsImeMenuBubbleShown() { - return !!bubble_; -} - -void ImeMenuTray::ShowKeyboardWithKeyset(const std::string& keyset) { - HideImeMenuBubble(); - - // Overrides the keyboard url ref to make it shown with the given keyset. - if (InputMethodManager::Get()) - InputMethodManager::Get()->OverrideKeyboardUrlRef(keyset); - - // If onscreen keyboard has been enabled, shows the keyboard directly. - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - show_keyboard_ = true; - if (keyboard_controller) { - keyboard_controller->AddObserver(this); - // If the keyboard window hasn't been created yet, it means the extension - // cannot receive anything to show the keyboard. Therefore, instead of - // relying the extension to show the keyboard, forcibly show the keyboard - // window here (which will cause the keyboard window to be created). - // Otherwise, the extension will show keyboard by calling private api. The - // native side could just skip showing the keyboard. - if (!keyboard_controller->IsKeyboardWindowCreated()) - keyboard_controller->ShowKeyboard(false); - return; - } - - AccessibilityDelegate* accessibility_delegate = - WmShell::Get()->accessibility_delegate(); - // Fails to show the keyboard. - if (accessibility_delegate->IsVirtualKeyboardEnabled()) - return; - - // Onscreen keyboard has not been enabled yet, forces to bring out the - // keyboard for one time. - force_show_keyboard_ = true; - accessibility_delegate->SetVirtualKeyboardEnabled(true); - keyboard_controller = keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) { - keyboard_controller->AddObserver(this); - keyboard_controller->ShowKeyboard(false); - } -} - -bool ImeMenuTray::ShouldBlockShelfAutoHide() const { - return should_block_shelf_auto_hide_; -} - -bool ImeMenuTray::ShouldShowEmojiHandwritingVoiceButtons() const { - // Emoji, handwriting and voice input is not supported for these cases: - // 1) features::kEHVInputOnImeMenu is not enabled. - // 2) third party IME extensions. - // 3) login/lock screen. - // 4) password input client. - return InputMethodManager::Get() && - InputMethodManager::Get()->IsEmojiHandwritingVoiceOnImeMenuEnabled() && - !current_ime_.third_party && !IsInLoginOrLockScreen() && - !IsInPasswordInputContext(); -} - -bool ImeMenuTray::ShouldShowKeyboardToggle() const { - return keyboard_suppressed_ && - !WmShell::Get()->accessibility_delegate()->IsVirtualKeyboardEnabled(); -} - -void ImeMenuTray::SetShelfAlignment(ShelfAlignment alignment) { - TrayBackgroundView::SetShelfAlignment(alignment); - if (!MaterialDesignController::IsShelfMaterial()) - tray_container()->SetBorder(views::NullBorder()); -} - -base::string16 ImeMenuTray::GetAccessibleNameForTray() { - return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME); -} - -void ImeMenuTray::HideBubbleWithView(const views::TrayBubbleView* bubble_view) { - if (bubble_->bubble_view() == bubble_view) - HideImeMenuBubble(); -} - -void ImeMenuTray::ClickedOutsideBubble() { - HideImeMenuBubble(); -} - -bool ImeMenuTray::PerformAction(const ui::Event& event) { - if (bubble_) - HideImeMenuBubble(); - else - ShowImeMenuBubble(); - return true; -} - -void ImeMenuTray::OnIMERefresh() { - UpdateTrayLabel(); - if (bubble_ && ime_list_view_) { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - IMEInfoList list; - delegate->GetAvailableIMEList(&list); - IMEPropertyInfoList property_list; - delegate->GetCurrentIMEProperties(&property_list); - ime_list_view_->Update(list, property_list, false, - ImeListView::SHOW_SINGLE_IME); - } -} - -void ImeMenuTray::OnIMEMenuActivationChanged(bool is_activated) { - SetVisible(is_activated); - if (is_activated) - UpdateTrayLabel(); - else - HideImeMenuBubble(); -} - -void ImeMenuTray::BubbleViewDestroyed() { -} - -void ImeMenuTray::OnMouseEnteredView() {} - -void ImeMenuTray::OnMouseExitedView() {} - -base::string16 ImeMenuTray::GetAccessibleNameForBubble() { - return l10n_util::GetStringUTF16(IDS_ASH_IME_MENU_ACCESSIBLE_NAME); -} - -void ImeMenuTray::OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const { - // Place the bubble in the same root window as |anchor_widget|. - WmWindow::Get(anchor_widget->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - bubble_widget, kShellWindowId_SettingBubbleContainer, params); -} - -void ImeMenuTray::HideBubble(const views::TrayBubbleView* bubble_view) { - HideBubbleWithView(bubble_view); -} - -void ImeMenuTray::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) {} - -void ImeMenuTray::OnKeyboardClosed() { - if (InputMethodManager::Get()) - InputMethodManager::Get()->OverrideKeyboardUrlRef(std::string()); - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) - keyboard_controller->RemoveObserver(this); - - show_keyboard_ = false; - force_show_keyboard_ = false; -} - -void ImeMenuTray::OnKeyboardHidden() { - if (show_bubble_after_keyboard_hidden_) { - show_bubble_after_keyboard_hidden_ = false; - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) - keyboard_controller->RemoveObserver(this); - - ShowImeMenuBubbleInternal(); - return; - } - - if (!show_keyboard_) - return; - - // If the the IME menu has overriding the input view url, we should write it - // back to normal keyboard when hiding the input view. - if (InputMethodManager::Get()) - InputMethodManager::Get()->OverrideKeyboardUrlRef(std::string()); - show_keyboard_ = false; - - // If the keyboard is forced to be shown by IME menu for once, we need to - // disable the keyboard when it's hidden. - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) - keyboard_controller->RemoveObserver(this); - - if (!force_show_keyboard_) - return; - - WmShell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(false); - force_show_keyboard_ = false; -} - -void ImeMenuTray::OnKeyboardSuppressionChanged(bool suppressed) { - if (suppressed != keyboard_suppressed_ && bubble_) - HideImeMenuBubble(); - keyboard_suppressed_ = suppressed; -} - -void ImeMenuTray::UpdateTrayLabel() { - WmShell::Get()->system_tray_delegate()->GetCurrentIME(¤t_ime_); - - // Updates the tray label based on the current input method. - if (current_ime_.third_party) - label_->SetText(current_ime_.short_name + base::UTF8ToUTF16("*")); - else - label_->SetText(current_ime_.short_name); -} - -} // namespace ash
diff --git a/ash/system/ime_menu/ime_menu_tray.h b/ash/system/ime_menu/ime_menu_tray.h deleted file mode 100644 index 278a102..0000000 --- a/ash/system/ime_menu/ime_menu_tray.h +++ /dev/null
@@ -1,118 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_IME_MENU_IME_MENU_TRAY_H_ -#define ASH_SYSTEM_IME_MENU_IME_MENU_TRAY_H_ - -#include "ash/ash_export.h" -#include "ash/system/ime/ime_observer.h" -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/tray_background_view.h" -#include "ash/system/tray/tray_bubble_wrapper.h" -#include "ash/system/virtual_keyboard/virtual_keyboard_observer.h" -#include "base/macros.h" -#include "ui/keyboard/keyboard_controller_observer.h" -#include "ui/views/bubble/tray_bubble_view.h" - -namespace views { -class Label; -} // namespace views - -namespace ash { -class ImeListView; - -// The tray item for IME menu, which shows the detailed view of a null single -// item. -class ASH_EXPORT ImeMenuTray : public TrayBackgroundView, - public IMEObserver, - public views::TrayBubbleView::Delegate, - public keyboard::KeyboardControllerObserver, - public VirtualKeyboardObserver { - public: - explicit ImeMenuTray(WmShelf* wm_shelf); - ~ImeMenuTray() override; - - // Shows the IME menu bubble and highlights the button. - void ShowImeMenuBubble(); - - // Hides the IME menu bubble and lowlights the button. - void HideImeMenuBubble(); - - // Returns true if the IME menu bubble has been shown. - bool IsImeMenuBubbleShown(); - - // Shows the virtual keyboard with the given keyset: emoji, handwriting or - // voice. - void ShowKeyboardWithKeyset(const std::string& keyset); - - // Returns true if it should block the auto hide behavior of the shelf. - bool ShouldBlockShelfAutoHide() const; - - // Returns true if the menu should show emoji, handwriting and voice buttons - // on the bottom. Otherwise, the menu will show a 'Customize...' bottom row - // for non-MD UI, and a Settings button in the title row for MD. - bool ShouldShowEmojiHandwritingVoiceButtons() const; - - // Returns whether the virtual keyboard toggle should be shown in shown in the - // opt-in IME menu. - bool ShouldShowKeyboardToggle() const; - - // TrayBackgroundView: - void SetShelfAlignment(ShelfAlignment alignment) override; - base::string16 GetAccessibleNameForTray() override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void ClickedOutsideBubble() override; - bool PerformAction(const ui::Event& event) override; - - // IMEObserver: - void OnIMERefresh() override; - void OnIMEMenuActivationChanged(bool is_activated) override; - - // views::TrayBubbleView::Delegate: - void BubbleViewDestroyed() override; - void OnMouseEnteredView() override; - void OnMouseExitedView() override; - base::string16 GetAccessibleNameForBubble() override; - void OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const override; - void HideBubble(const views::TrayBubbleView* bubble_view) override; - - // keyboard::KeyboardControllerObserver: - void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; - void OnKeyboardClosed() override; - void OnKeyboardHidden() override; - - // VirtualKeyboardObserver: - void OnKeyboardSuppressionChanged(bool suppressed) override; - - private: - // To allow the test class to access |label_|. - friend class ImeMenuTrayTest; - - // Show the IME menu bubble immediately. - void ShowImeMenuBubbleInternal(); - - // Updates the text of the label on the tray. - void UpdateTrayLabel(); - - // Bubble for default and detailed views. - std::unique_ptr<TrayBubbleWrapper> bubble_; - ImeListView* ime_list_view_; - - views::Label* label_; - IMEInfo current_ime_; - bool show_keyboard_; - bool force_show_keyboard_; - bool should_block_shelf_auto_hide_; - bool keyboard_suppressed_; - bool show_bubble_after_keyboard_hidden_; - - DISALLOW_COPY_AND_ASSIGN(ImeMenuTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_IME_MENU_IME_MENU_TRAY_H_
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc deleted file mode 100644 index d001a85..0000000 --- a/ash/system/ime_menu/ime_menu_tray_unittest.cc +++ /dev/null
@@ -1,313 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/ime_menu/ime_menu_tray.h" - -#include "ash/accelerators/accelerator_controller.h" -#include "ash/common/accessibility_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/system/ime_menu/ime_list_view.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/status_area_widget_test_helper.h" -#include "ash/test/test_system_tray_delegate.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/ime/chromeos/input_method_manager.h" -#include "ui/base/ime/chromeos/mock_input_method_manager.h" -#include "ui/base/ime/ime_bridge.h" -#include "ui/base/ime/text_input_flags.h" -#include "ui/events/event.h" -#include "ui/views/controls/label.h" - -using base::UTF8ToUTF16; - -namespace ash { - -ImeMenuTray* GetTray() { - return StatusAreaWidgetTestHelper::GetStatusAreaWidget()->ime_menu_tray(); -} - -class ImeMenuTrayTest : public test::AshTestBase { - public: - ImeMenuTrayTest() {} - ~ImeMenuTrayTest() override {} - - protected: - // Returns true if the IME menu tray is visible. - bool IsVisible() { return GetTray()->visible(); } - - // Returns the label text of the tray. - const base::string16& GetTrayText() { return GetTray()->label_->text(); } - - // Returns true if the background color of the tray is active. - bool IsTrayBackgroundActive() { return GetTray()->is_active(); } - - // Returns true if the IME menu bubble has been shown. - bool IsBubbleShown() { return GetTray()->IsImeMenuBubbleShown(); } - - // Returns true if the IME menu list has been updated with the right IME list. - bool IsTrayImeListValid(const std::vector<IMEInfo>& expected_imes, - const IMEInfo& expected_current_ime) { - const std::map<views::View*, std::string>& ime_map = - ImeListViewTestApi(GetTray()->ime_list_view_).ime_map(); - if (ime_map.size() != expected_imes.size()) - return false; - - std::vector<std::string> expected_ime_ids; - for (const auto& ime : expected_imes) { - expected_ime_ids.push_back(ime.id); - } - for (const auto& ime : ime_map) { - // Tests that all the IMEs on the view is in the list of selected IMEs. - if (std::find(expected_ime_ids.begin(), expected_ime_ids.end(), - ime.second) == expected_ime_ids.end()) { - return false; - } - - // Tests that the checked IME is the current IME. - ui::AXNodeData node_data; - node_data.state = 0; - ime.first->GetAccessibleNodeData(&node_data); - if (node_data.HasStateFlag(ui::AX_STATE_CHECKED)) { - if (ime.second != expected_current_ime.id) - return false; - } - } - return true; - } - - // Focuses in the given type of input context. - void FocusInInputContext(ui::TextInputType input_type) { - ui::IMEEngineHandlerInterface::InputContext input_context( - input_type, ui::TEXT_INPUT_MODE_DEFAULT, ui::TEXT_INPUT_FLAG_NONE); - ui::IMEBridge::Get()->SetCurrentInputContext(input_context); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ImeMenuTrayTest); -}; - -// Tests that visibility of IME menu tray should be consistent with the -// activation of the IME menu. -TEST_F(ImeMenuTrayTest, ImeMenuTrayVisibility) { - ASSERT_FALSE(IsVisible()); - - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); - EXPECT_TRUE(IsVisible()); - - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(false); - EXPECT_FALSE(IsVisible()); -} - -// Tests that IME menu tray shows the right info of the current IME. -TEST_F(ImeMenuTrayTest, TrayLabelTest) { - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); - ASSERT_TRUE(IsVisible()); - - // Changes the input method to "ime1". - IMEInfo info1; - info1.id = "ime1"; - info1.name = UTF8ToUTF16("English"); - info1.medium_name = UTF8ToUTF16("English"); - info1.short_name = UTF8ToUTF16("US"); - info1.third_party = false; - info1.selected = true; - GetSystemTrayDelegate()->SetCurrentIME(info1); - WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); - EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); - - // Changes the input method to a third-party IME extension. - IMEInfo info2; - info2.id = "ime2"; - info2.name = UTF8ToUTF16("English UK"); - info2.medium_name = UTF8ToUTF16("English UK"); - info2.short_name = UTF8ToUTF16("UK"); - info2.third_party = true; - info2.selected = true; - GetSystemTrayDelegate()->SetCurrentIME(info2); - WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); - EXPECT_EQ(UTF8ToUTF16("UK*"), GetTrayText()); -} - -// Tests that IME menu tray changes background color when tapped/clicked. And -// tests that the background color becomes 'inactive' when disabling the IME -// menu feature. -TEST_F(ImeMenuTrayTest, PerformAction) { - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); - ASSERT_TRUE(IsVisible()); - ASSERT_FALSE(IsTrayBackgroundActive()); - - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - GetTray()->PerformAction(tap); - EXPECT_TRUE(IsTrayBackgroundActive()); - EXPECT_TRUE(IsBubbleShown()); - - GetTray()->PerformAction(tap); - EXPECT_FALSE(IsTrayBackgroundActive()); - EXPECT_FALSE(IsBubbleShown()); - - // If disabling the IME menu feature when the menu tray is activated, the tray - // element will be deactivated. - GetTray()->PerformAction(tap); - EXPECT_TRUE(IsTrayBackgroundActive()); - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(false); - EXPECT_FALSE(IsVisible()); - EXPECT_FALSE(IsBubbleShown()); - EXPECT_FALSE(IsTrayBackgroundActive()); -} - -// Tests that IME menu list updates when changing the current IME. This should -// only happen by using shortcuts (Ctrl + Space / Ctrl + Shift + Space) to -// switch IMEs. -TEST_F(ImeMenuTrayTest, RefreshImeWithListViewCreated) { - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - GetTray()->PerformAction(tap); - - EXPECT_TRUE(IsTrayBackgroundActive()); - EXPECT_TRUE(IsBubbleShown()); - - IMEInfo info1, info2, info3; - info1.id = "ime1"; - info1.name = UTF8ToUTF16("English"); - info1.medium_name = UTF8ToUTF16("English"); - info1.short_name = UTF8ToUTF16("US"); - info1.third_party = false; - info1.selected = true; - - info2.id = "ime2"; - info2.name = UTF8ToUTF16("English UK"); - info2.medium_name = UTF8ToUTF16("English UK"); - info2.short_name = UTF8ToUTF16("UK"); - info2.third_party = true; - info2.selected = false; - - info3.id = "ime3"; - info3.name = UTF8ToUTF16("Pinyin"); - info3.medium_name = UTF8ToUTF16("Chinese Pinyin"); - info3.short_name = UTF8ToUTF16("拼"); - info3.third_party = false; - info3.selected = false; - - std::vector<IMEInfo> ime_info_list{info1, info2, info3}; - - GetSystemTrayDelegate()->SetAvailableIMEList(ime_info_list); - GetSystemTrayDelegate()->SetCurrentIME(info1); - WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); - EXPECT_EQ(UTF8ToUTF16("US"), GetTrayText()); - EXPECT_TRUE(IsTrayImeListValid(ime_info_list, info1)); - - ime_info_list[0].selected = false; - ime_info_list[2].selected = true; - GetSystemTrayDelegate()->SetAvailableIMEList(ime_info_list); - GetSystemTrayDelegate()->SetCurrentIME(info3); - WmShell::Get()->system_tray_notifier()->NotifyRefreshIME(); - EXPECT_EQ(UTF8ToUTF16("拼"), GetTrayText()); - EXPECT_TRUE(IsTrayImeListValid(ime_info_list, info3)); - - // Closes the menu before quitting. - GetTray()->PerformAction(tap); - EXPECT_FALSE(IsTrayBackgroundActive()); - EXPECT_FALSE(IsBubbleShown()); -} - -// Tests that quits Chrome with IME menu openned will not crash. -TEST_F(ImeMenuTrayTest, QuitChromeWithMenuOpen) { - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); - ASSERT_TRUE(IsVisible()); - ASSERT_FALSE(IsTrayBackgroundActive()); - - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - GetTray()->PerformAction(tap); - EXPECT_TRUE(IsTrayBackgroundActive()); - EXPECT_TRUE(IsBubbleShown()); -} - -// Tests using 'Alt+Shift+K' to open the menu. -TEST_F(ImeMenuTrayTest, TestAccelerator) { - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); - ASSERT_TRUE(IsVisible()); - ASSERT_FALSE(IsTrayBackgroundActive()); - - WmShell::Get()->accelerator_controller()->PerformActionIfEnabled( - SHOW_IME_MENU_BUBBLE); - EXPECT_TRUE(IsTrayBackgroundActive()); - EXPECT_TRUE(IsBubbleShown()); - - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - GetTray()->PerformAction(tap); - EXPECT_FALSE(IsTrayBackgroundActive()); - EXPECT_FALSE(IsBubbleShown()); -} - -TEST_F(ImeMenuTrayTest, ShowEmojiKeyset) { - WmShell::Get()->system_tray_notifier()->NotifyRefreshIMEMenu(true); - ASSERT_TRUE(IsVisible()); - ASSERT_FALSE(IsTrayBackgroundActive()); - - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - GetTray()->PerformAction(tap); - EXPECT_TRUE(IsTrayBackgroundActive()); - EXPECT_TRUE(IsBubbleShown()); - - AccessibilityDelegate* accessibility_delegate = - WmShell::Get()->accessibility_delegate(); - - accessibility_delegate->SetVirtualKeyboardEnabled(true); - EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); - - GetTray()->ShowKeyboardWithKeyset("emoji"); - // The menu should be hidden. - EXPECT_FALSE(IsBubbleShown()); - // The virtual keyboard should be enabled. - EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); - - // Hides the keyboard. - GetTray()->OnKeyboardHidden(); - // The keyboard should still be enabled. - EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); -} - -TEST_F(ImeMenuTrayTest, ForceToShowEmojiKeyset) { - AccessibilityDelegate* accessibility_delegate = - WmShell::Get()->accessibility_delegate(); - accessibility_delegate->SetVirtualKeyboardEnabled(false); - ASSERT_FALSE(accessibility_delegate->IsVirtualKeyboardEnabled()); - - GetTray()->ShowKeyboardWithKeyset("emoji"); - // The virtual keyboard should be enabled. - EXPECT_TRUE(accessibility_delegate->IsVirtualKeyboardEnabled()); - - // Hides the keyboard. - GetTray()->OnKeyboardHidden(); - // The keyboard should still be disabled. - EXPECT_FALSE(accessibility_delegate->IsVirtualKeyboardEnabled()); -} - -TEST_F(ImeMenuTrayTest, ShowEmojiHandwritingVoiceButtons) { - FocusInInputContext(ui::TEXT_INPUT_TYPE_TEXT); - EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons()); - - chromeos::input_method::InputMethodManager* input_method_manager = - chromeos::input_method::InputMethodManager::Get(); - EXPECT_FALSE(input_method_manager); - chromeos::input_method::InputMethodManager::Initialize( - new chromeos::input_method::MockInputMethodManager); - input_method_manager = chromeos::input_method::InputMethodManager::Get(); - EXPECT_TRUE(input_method_manager && - input_method_manager->IsEmojiHandwritingVoiceOnImeMenuEnabled()); - EXPECT_TRUE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons()); - - FocusInInputContext(ui::TEXT_INPUT_TYPE_PASSWORD); - EXPECT_FALSE(GetTray()->ShouldShowEmojiHandwritingVoiceButtons()); -} - -} // namespace ash
diff --git a/ash/system/keyboard_brightness_control_delegate.h b/ash/system/keyboard_brightness_control_delegate.h deleted file mode 100644 index 75f240d..0000000 --- a/ash/system/keyboard_brightness_control_delegate.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROL_DELEGATE_H_ -#define ASH_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROL_DELEGATE_H_ - -namespace ui { -class Accelerator; -} // namespace ui - -namespace ash { - -// Delegate for controlling the keyboard brightness. -class KeyboardBrightnessControlDelegate { - public: - virtual ~KeyboardBrightnessControlDelegate() {} - - // Handles an accelerator-driven request to decrease or increase the keyboard - // brightness. - virtual void HandleKeyboardBrightnessDown( - const ui::Accelerator& accelerator) = 0; - virtual void HandleKeyboardBrightnessUp( - const ui::Accelerator& accelerator) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROL_DELEGATE_H_
diff --git a/ash/system/keyboard_brightness_controller.cc b/ash/system/keyboard_brightness_controller.cc deleted file mode 100644 index 6cb803f6..0000000 --- a/ash/system/keyboard_brightness_controller.cc +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/keyboard_brightness_controller.h" - -#include "ash/common/wm_shell.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/base/accelerators/accelerator.h" - -namespace ash { - -void KeyboardBrightnessController::HandleKeyboardBrightnessDown( - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_DOWN) { - WmShell::Get()->RecordUserMetricsAction( - UMA_ACCEL_KEYBOARD_BRIGHTNESS_DOWN_F6); - } - - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->DecreaseKeyboardBrightness(); -} - -void KeyboardBrightnessController::HandleKeyboardBrightnessUp( - const ui::Accelerator& accelerator) { - if (accelerator.key_code() == ui::VKEY_BRIGHTNESS_UP) { - WmShell::Get()->RecordUserMetricsAction( - UMA_ACCEL_KEYBOARD_BRIGHTNESS_UP_F7); - } - - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->IncreaseKeyboardBrightness(); -} - -} // namespace ash
diff --git a/ash/system/keyboard_brightness_controller.h b/ash/system/keyboard_brightness_controller.h deleted file mode 100644 index 2a6777c..0000000 --- a/ash/system/keyboard_brightness_controller.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROLLER_H_ -#define ASH_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROLLER_H_ - -#include "ash/ash_export.h" -#include "ash/system/keyboard_brightness_control_delegate.h" -#include "base/compiler_specific.h" -#include "base/macros.h" - -namespace ash { - -// A class which controls keyboard brightness when Alt+F6, Alt+F7 or a -// multimedia key for keyboard brightness is pressed. -class ASH_EXPORT KeyboardBrightnessController - : public KeyboardBrightnessControlDelegate { - public: - KeyboardBrightnessController() {} - ~KeyboardBrightnessController() override {} - - private: - // Overridden from KeyboardBrightnessControlDelegate: - void HandleKeyboardBrightnessDown( - const ui::Accelerator& accelerator) override; - void HandleKeyboardBrightnessUp(const ui::Accelerator& accelerator) override; - - DISALLOW_COPY_AND_ASSIGN(KeyboardBrightnessController); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_KEYBOARD_BRIGHTNESS_CONTROLLER_H_
diff --git a/ash/system/locale/locale_notification_controller.cc b/ash/system/locale/locale_notification_controller.cc deleted file mode 100644 index bf45085..0000000 --- a/ash/system/locale/locale_notification_controller.cc +++ /dev/null
@@ -1,132 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/locale/locale_notification_controller.h" - -#include <memory> -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "base/strings/string16.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/message_center/notification_types.h" - -using message_center::Notification; - -namespace ash { -namespace { - -const char kLocaleChangeNotificationId[] = "chrome://settings/locale"; - -class LocaleNotificationDelegate : public message_center::NotificationDelegate { - public: - explicit LocaleNotificationDelegate( - const base::Callback<void(ash::mojom::LocaleNotificationResult)>& - callback); - - protected: - ~LocaleNotificationDelegate() override; - - // message_center::NotificationDelegate overrides: - void Close(bool by_user) override; - bool HasClickedListener() override; - void Click() override; - void ButtonClick(int button_index) override; - - private: - base::Callback<void(ash::mojom::LocaleNotificationResult)> callback_; - - DISALLOW_COPY_AND_ASSIGN(LocaleNotificationDelegate); -}; - -LocaleNotificationDelegate::LocaleNotificationDelegate( - const base::Callback<void(ash::mojom::LocaleNotificationResult)>& callback) - : callback_(callback) {} - -LocaleNotificationDelegate::~LocaleNotificationDelegate() { - if (callback_) { - // We're being destroyed but the user didn't click on anything. Run the - // callback so that we don't crash. - callback_.Run(ash::mojom::LocaleNotificationResult::ACCEPT); - } -} - -void LocaleNotificationDelegate::Close(bool by_user) { - if (callback_) { - callback_.Run(ash::mojom::LocaleNotificationResult::ACCEPT); - callback_.Reset(); - } -} - -bool LocaleNotificationDelegate::HasClickedListener() { - return true; -} - -void LocaleNotificationDelegate::Click() { - if (callback_) { - callback_.Run(ash::mojom::LocaleNotificationResult::ACCEPT); - callback_.Reset(); - } -} - -void LocaleNotificationDelegate::ButtonClick(int button_index) { - DCHECK_EQ(0, button_index); - - if (callback_) { - callback_.Run(ash::mojom::LocaleNotificationResult::REVERT); - callback_.Reset(); - } -} - -} // namespace - -LocaleNotificationController::LocaleNotificationController() {} - -LocaleNotificationController::~LocaleNotificationController() {} - -void LocaleNotificationController::BindRequest( - mojom::LocaleNotificationControllerRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void LocaleNotificationController::OnLocaleChanged( - const std::string& cur_locale, - const std::string& from_locale, - const std::string& to_locale, - const OnLocaleChangedCallback& callback) { - base::string16 from = - l10n_util::GetDisplayNameForLocale(from_locale, cur_locale, true); - base::string16 to = - l10n_util::GetDisplayNameForLocale(to_locale, cur_locale, true); - - message_center::RichNotificationData optional; - optional.buttons.push_back( - message_center::ButtonInfo(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_LOCALE_REVERT_MESSAGE, from))); - optional.never_timeout = true; - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kLocaleChangeNotificationId, - base::string16() /* title */, - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_MESSAGE, - from, to), - bundle.GetImageNamed(IDR_AURA_UBER_TRAY_LOCALE), - base::string16() /* display_source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierLocale), - optional, new LocaleNotificationDelegate(callback))); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -} // namespace ash
diff --git a/ash/system/locale/locale_notification_controller.h b/ash/system/locale/locale_notification_controller.h deleted file mode 100644 index 7ea476a..0000000 --- a/ash/system/locale/locale_notification_controller.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_LOCALE_LOCALE_NOTIFICATION_CONTROLLER_H_ -#define ASH_SYSTEM_LOCALE_LOCALE_NOTIFICATION_CONTROLLER_H_ - -#include <string> - -#include "ash/public/interfaces/locale.mojom.h" -#include "base/macros.h" -#include "mojo/public/cpp/bindings/binding_set.h" - -namespace ash { - -// Observes the locale change and creates rich notification for the change. -class LocaleNotificationController - : public mojom::LocaleNotificationController { - public: - LocaleNotificationController(); - ~LocaleNotificationController() override; - - // Binds the mojom::LocaleNotificationController interface request to this - // object. - void BindRequest(mojom::LocaleNotificationControllerRequest request); - - private: - // Overridden from mojom::LocaleNotificationController: - void OnLocaleChanged(const std::string& cur_locale, - const std::string& from_locale, - const std::string& to_locale, - const OnLocaleChangedCallback& callback) override; - - std::string cur_locale_; - std::string from_locale_; - std::string to_locale_; - - // Bindings for the LocaleNotificationController interface. - mojo::BindingSet<mojom::LocaleNotificationController> bindings_; - - DISALLOW_COPY_AND_ASSIGN(LocaleNotificationController); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_LOCALE_LOCALE_NOTIFICATION_CONTROLLER_H_
diff --git a/ash/system/media_security/multi_profile_media_tray_item.cc b/ash/system/media_security/multi_profile_media_tray_item.cc deleted file mode 100644 index be37005..0000000 --- a/ash/system/media_security/multi_profile_media_tray_item.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/media_security/multi_profile_media_tray_item.h" - -#include "ash/common/ash_view_ids.h" -#include "ash/common/media_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_view.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/image_view.h" - -namespace ash { -namespace tray { - -class MultiProfileMediaTrayView : public TrayItemView, - public MediaCaptureObserver { - public: - explicit MultiProfileMediaTrayView(SystemTrayItem* system_tray_item) - : TrayItemView(system_tray_item) { - CreateImageView(); - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - image_view()->SetImage( - UseMd() - ? gfx::CreateVectorIcon(kSystemTrayRecordingIcon, kTrayIconColor) - : *bundle.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_RECORDING)); - WmShell::Get()->media_controller()->AddObserver(this); - SetVisible(false); - WmShell::Get()->media_controller()->RequestCaptureState(); - set_id(VIEW_ID_MEDIA_TRAY_VIEW); - } - - ~MultiProfileMediaTrayView() override { - WmShell::Get()->media_controller()->RemoveObserver(this); - } - - // MediaCaptureObserver: - void OnMediaCaptureChanged( - const std::vector<mojom::MediaCaptureState>& capture_states) override { - SessionStateDelegate* session_state_delegate = - WmShell::Get()->GetSessionStateDelegate(); - // The user at 0 is the current desktop user. - for (UserIndex index = 1; - index < session_state_delegate->NumberOfLoggedInUsers(); ++index) { - if (capture_states[index] != mojom::MediaCaptureState::NONE) { - SetVisible(true); - return; - } - } - SetVisible(false); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayView); -}; - -} // namespace tray - -MultiProfileMediaTrayItem::MultiProfileMediaTrayItem(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_MULTI_PROFILE_MEDIA) {} - -MultiProfileMediaTrayItem::~MultiProfileMediaTrayItem() {} - -views::View* MultiProfileMediaTrayItem::CreateTrayView(LoginStatus status) { - return new tray::MultiProfileMediaTrayView(this); -} - -} // namespace ash
diff --git a/ash/system/media_security/multi_profile_media_tray_item.h b/ash/system/media_security/multi_profile_media_tray_item.h deleted file mode 100644 index 6c2718a5..0000000 --- a/ash/system/media_security/multi_profile_media_tray_item.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_MEDIA_SECURITY_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ -#define ASH_SYSTEM_MEDIA_SECURITY_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_ - -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { - -// The tray item for media recording. -class ASH_EXPORT MultiProfileMediaTrayItem : public SystemTrayItem { - public: - explicit MultiProfileMediaTrayItem(SystemTray* system_tray); - ~MultiProfileMediaTrayItem() override; - - // SystemTrayItem: - views::View* CreateTrayView(LoginStatus status) override; - - private: - DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayItem); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_MEDIA_SECURITY_MULTI_PROFILE_MEDIA_TRAY_ITEM_H_
diff --git a/ash/system/media_security/multi_profile_media_tray_item_unittest.cc b/ash/system/media_security/multi_profile_media_tray_item_unittest.cc deleted file mode 100644 index e6417cb..0000000 --- a/ash/system/media_security/multi_profile_media_tray_item_unittest.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/media_security/multi_profile_media_tray_item.h" - -#include "ash/common/ash_view_ids.h" -#include "ash/common/media_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/public/interfaces/media.mojom.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_bubble.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/ash_test_helper.h" -#include "ash/test/status_area_widget_test_helper.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/test/test_shell_delegate.h" -#include "ui/views/bubble/tray_bubble_view.h" - -namespace ash { - -class MultiProfileMediaTrayItemTest : public test::AshTestBase { - public: - MultiProfileMediaTrayItemTest() {} - ~MultiProfileMediaTrayItemTest() override {} - - void SetMediaCaptureState(mojom::MediaCaptureState state) { - // Create the fake update. - test::TestSessionStateDelegate* session_state_delegate = - test::AshTestHelper::GetTestSessionStateDelegate(); - std::vector<mojom::MediaCaptureState> v; - for (int i = 0; i < session_state_delegate->NumberOfLoggedInUsers(); ++i) - v.push_back(state); - WmShell::Get()->media_controller()->NotifyCaptureState(v); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MultiProfileMediaTrayItemTest); -}; - -// ash_unittests. still failing. -TEST_F(MultiProfileMediaTrayItemTest, NotifyMediaCaptureChange) { - TrayItemView::DisableAnimationsForTest(); - test::TestSessionStateDelegate* session_state_delegate = - test::AshTestHelper::GetTestSessionStateDelegate(); - session_state_delegate->set_logged_in_users(2); - - SystemTray* system_tray = GetPrimarySystemTray(); - system_tray->ShowDefaultView(BUBBLE_CREATE_NEW); - views::View* in_user_view = - system_tray->GetSystemBubble()->bubble_view()->GetViewByID( - VIEW_ID_USER_VIEW_MEDIA_INDICATOR); - - StatusAreaWidget* widget = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); - EXPECT_TRUE(widget->GetRootView()->visible()); - views::View* tray_view = - widget->GetRootView()->GetViewByID(VIEW_ID_MEDIA_TRAY_VIEW); - - SetMediaCaptureState(mojom::MediaCaptureState::NONE); - EXPECT_FALSE(tray_view->visible()); - EXPECT_FALSE(in_user_view->visible()); - - SetMediaCaptureState(mojom::MediaCaptureState::AUDIO); - EXPECT_TRUE(tray_view->visible()); - EXPECT_TRUE(in_user_view->visible()); - - SetMediaCaptureState(mojom::MediaCaptureState::AUDIO_VIDEO); - EXPECT_TRUE(tray_view->visible()); - EXPECT_TRUE(in_user_view->visible()); - - SetMediaCaptureState(mojom::MediaCaptureState::NONE); - EXPECT_FALSE(tray_view->visible()); - EXPECT_FALSE(in_user_view->visible()); -} - -} // namespace ash
diff --git a/ash/system/network/network_detailed_view.h b/ash/system/network/network_detailed_view.h deleted file mode 100644 index 11a0d451..0000000 --- a/ash/system/network/network_detailed_view.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_DETAILED_VIEW_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_DETAILED_VIEW_H_ - -#include "ash/system/tray/tray_details_view.h" -#include "chromeos/network/network_state_handler.h" - -namespace ash { -namespace tray { - -// Abstract base class for all NetworkDetailedView derived subclasses, -// which includes NetworkWifiDetailedView and NetworkStateListDetailedView. -class NetworkDetailedView : public TrayDetailsView { - public: - enum DetailedViewType { - LIST_VIEW, - STATE_LIST_VIEW, - WIFI_VIEW, - }; - - explicit NetworkDetailedView(SystemTrayItem* owner) - : TrayDetailsView(owner) {} - - virtual void Init() = 0; - - virtual DetailedViewType GetViewType() const = 0; - - // Called when the contents of the network list have changed or when any - // Manager properties (e.g. technology state) have changed. - // (Called only from TrayNetworkStateObserver). - virtual void Update() = 0; - - protected: - ~NetworkDetailedView() override {} -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_DETAILED_VIEW_H_
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc deleted file mode 100644 index 256fe23..0000000 --- a/ash/system/network/network_icon.cc +++ /dev/null
@@ -1,957 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_icon.h" - -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_icon_animation_observer.h" -#include "ash/system/tray/tray_constants.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "chromeos/network/device_state.h" -#include "chromeos/network/network_connection_handler.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "chromeos/network/portal_detector/network_portal_detector.h" -#include "third_party/cros_system_api/dbus/service_constants.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size_conversions.h" -#include "ui/gfx/image/canvas_image_source.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/gfx/image/image_skia_source.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/skia_util.h" -#include "ui/gfx/vector_icon_types.h" - -using chromeos::DeviceState; -using chromeos::NetworkConnectionHandler; -using chromeos::NetworkHandler; -using chromeos::NetworkPortalDetector; -using chromeos::NetworkState; -using chromeos::NetworkStateHandler; -using chromeos::NetworkTypePattern; - -namespace ash { -namespace network_icon { - -namespace { - -// Constants for offseting the badge displayed on top of the signal strength -// icon. The badge will extend outside of the base icon bounds by these amounts. -// All values are in dp. - -// The badge offsets are different depending on whether the icon is in the tray -// or menu. -const int kTrayIconBadgeOffset = 3; -const int kMenuIconBadgeOffset = 2; - -//------------------------------------------------------------------------------ -// Struct to pass icon badges to NetworkIconImageSource. -struct Badges { - gfx::ImageSkia top_left; - gfx::ImageSkia top_right; - gfx::ImageSkia bottom_left; - gfx::ImageSkia bottom_right; -}; - -//------------------------------------------------------------------------------ -// class used for maintaining a map of network state and images. -class NetworkIconImpl { - public: - NetworkIconImpl(const std::string& path, IconType icon_type); - - // Determines whether or not the associated network might be dirty and if so - // updates and generates the icon. Does nothing if network no longer exists. - void Update(const chromeos::NetworkState* network); - - const gfx::ImageSkia& image() const { return image_; } - - private: - // Updates |strength_index_| for wireless networks. Returns true if changed. - bool UpdateWirelessStrengthIndex(const chromeos::NetworkState* network); - - // Updates the local state for cellular networks. Returns true if changed. - bool UpdateCellularState(const chromeos::NetworkState* network); - - // Updates the portal state for wireless networks. Returns true if changed. - bool UpdatePortalState(const chromeos::NetworkState* network); - - // Updates the VPN badge. Returns true if changed. - bool UpdateVPNBadge(); - - // Gets |badges| based on |network| and the current state. - void GetBadges(const NetworkState* network, Badges* badges); - - // Gets the appropriate icon and badges and composites the image. - void GenerateImage(const chromeos::NetworkState* network); - - // Network path, used for debugging. - std::string network_path_; - - // Defines color theme and VPN badging - const IconType icon_type_; - - // Cached state of the network when the icon was last generated. - std::string state_; - - // Cached strength index of the network when the icon was last generated. - int strength_index_; - - // Cached technology badge for the network when the icon was last generated. - gfx::ImageSkia technology_badge_; - - // Cached vpn badge for the network when the icon was last generated. - gfx::ImageSkia vpn_badge_; - - // Cached roaming state of the network when the icon was last generated. - std::string roaming_state_; - - // Cached portal state of the network when the icon was last generated. - bool behind_captive_portal_; - - // Generated icon image. - gfx::ImageSkia image_; - - DISALLOW_COPY_AND_ASSIGN(NetworkIconImpl); -}; - -//------------------------------------------------------------------------------ -// Maintain a static (global) icon map. Note: Icons are never destroyed; -// it is assumed that a finite and reasonable number of network icons will be -// created during a session. - -typedef std::map<std::string, NetworkIconImpl*> NetworkIconMap; - -NetworkIconMap* GetIconMapInstance(IconType icon_type, bool create) { - typedef std::map<IconType, NetworkIconMap*> IconTypeMap; - static IconTypeMap* s_icon_map = nullptr; - if (s_icon_map == nullptr) { - if (!create) - return nullptr; - s_icon_map = new IconTypeMap; - } - if (s_icon_map->count(icon_type) == 0) { - if (!create) - return nullptr; - (*s_icon_map)[icon_type] = new NetworkIconMap; - } - return (*s_icon_map)[icon_type]; -} - -NetworkIconMap* GetIconMap(IconType icon_type) { - return GetIconMapInstance(icon_type, true); -} - -void PurgeIconMap(IconType icon_type, - const std::set<std::string>& network_paths) { - NetworkIconMap* icon_map = GetIconMapInstance(icon_type, false); - if (!icon_map) - return; - for (NetworkIconMap::iterator loop_iter = icon_map->begin(); - loop_iter != icon_map->end();) { - NetworkIconMap::iterator cur_iter = loop_iter++; - if (network_paths.count(cur_iter->first) == 0) { - delete cur_iter->second; - icon_map->erase(cur_iter); - } - } -} - -//------------------------------------------------------------------------------ -// Utilities for generating icon images. - -// 'NONE' will default to ARCS behavior where appropriate (e.g. no network or -// if a new type gets added). -enum ImageType { ARCS, BARS, NONE }; - -// Amount to fade icons while connecting. -const double kConnectingImageAlpha = 0.5; - -// Images for strength arcs for wireless networks or strength bars for cellular -// networks. -const int kNumNetworkImages = 5; - -// Number of discrete images to use for alpha fade animation -const int kNumFadeImages = 10; - -SkColor GetDefaultColorForIconType(IconType icon_type) { - return icon_type == ICON_TYPE_TRAY ? kTrayIconColor : kMenuIconColor; -} - -bool IconTypeIsDark(IconType icon_type) { - return (icon_type != ICON_TYPE_TRAY); -} - -bool IconTypeHasVPNBadge(IconType icon_type) { - return (icon_type != ICON_TYPE_LIST && icon_type != ICON_TYPE_MENU_LIST); -} - -// This defines how we assemble a network icon. -class NetworkIconImageSource : public gfx::CanvasImageSource { - public: - static gfx::ImageSkia CreateImage(const gfx::ImageSkia& icon, - const Badges& badges) { - auto* source = new NetworkIconImageSource(icon, badges); - return gfx::ImageSkia(source, source->size()); - } - - // gfx::CanvasImageSource: - void Draw(gfx::Canvas* canvas) override { - const int width = size().width(); - const int height = size().height(); - - // The base icon is centered in both dimensions. - const int icon_y = (height - icon_.height()) / 2; - canvas->DrawImageInt(icon_, (width - icon_.width()) / 2, icon_y); - - // The badges are flush against the edges of the canvas, except at the top, - // where the badge is only 1dp higher than the base image. - const int top_badge_y = icon_y - 1; - if (!badges_.top_left.isNull()) - canvas->DrawImageInt(badges_.top_left, 0, top_badge_y); - if (!badges_.top_right.isNull()) { - canvas->DrawImageInt(badges_.top_right, width - badges_.top_right.width(), - top_badge_y); - } - if (!badges_.bottom_left.isNull()) { - canvas->DrawImageInt(badges_.bottom_left, 0, - height - badges_.bottom_left.height()); - } - if (!badges_.bottom_right.isNull()) { - canvas->DrawImageInt(badges_.bottom_right, - width - badges_.bottom_right.width(), - height - badges_.bottom_right.height()); - } - } - - bool HasRepresentationAtAllScales() const override { return true; } - - private: - NetworkIconImageSource(const gfx::ImageSkia& icon, const Badges& badges) - : CanvasImageSource(GetSizeForBaseIconSize(icon.size()), false), - icon_(icon), - badges_(badges) {} - ~NetworkIconImageSource() override {} - - static gfx::Size GetSizeForBaseIconSize(const gfx::Size& base_icon_size) { - gfx::Size size = base_icon_size; - const int badge_offset = base_icon_size.width() == kTrayIconSize - ? kTrayIconBadgeOffset - : kMenuIconBadgeOffset; - size.Enlarge(badge_offset * 2, badge_offset * 2); - return size; - } - - const gfx::ImageSkia icon_; - const Badges badges_; - - DISALLOW_COPY_AND_ASSIGN(NetworkIconImageSource); -}; - -// Depicts a given signal strength using arcs (e.g. for WiFi connections) or -// bars (e.g. for cell connections). -class SignalStrengthImageSource : public gfx::CanvasImageSource { - public: - SignalStrengthImageSource(ImageType image_type, - IconType icon_type, - int signal_strength) - : CanvasImageSource(GetSizeForIconType(icon_type), false), - image_type_(image_type), - icon_type_(icon_type), - color_(GetDefaultColorForIconType(icon_type_)), - signal_strength_(signal_strength) { - if (image_type_ == NONE) - image_type_ = ARCS; - - DCHECK_GE(signal_strength, 0); - DCHECK_LT(signal_strength, kNumNetworkImages); - } - ~SignalStrengthImageSource() override {} - - void set_color(SkColor color) { color_ = color; } - - // gfx::CanvasImageSource: - void Draw(gfx::Canvas* canvas) override { - if (image_type_ == ARCS) - DrawArcs(canvas); - else - DrawBars(canvas); - } - - bool HasRepresentationAtAllScales() const override { return true; } - - private: - static gfx::Size GetSizeForIconType(IconType icon_type) { - int side = icon_type == ICON_TYPE_TRAY ? kTrayIconSize : kMenuIconSize; - return gfx::Size(side, side); - } - - void DrawArcs(gfx::Canvas* canvas) { - gfx::RectF oval_bounds((gfx::Rect(size()))); - oval_bounds.Inset(gfx::Insets(kIconInset)); - // Double the width and height. The new midpoint should be the former - // bottom center. - oval_bounds.Inset(-oval_bounds.width() / 2, 0, -oval_bounds.width() / 2, - -oval_bounds.height()); - - const SkScalar kAngleAboveHorizontal = 51.f; - const SkScalar kStartAngle = 180.f + kAngleAboveHorizontal; - const SkScalar kSweepAngle = 180.f - 2 * kAngleAboveHorizontal; - - cc::PaintFlags flags; - flags.setAntiAlias(true); - flags.setStyle(cc::PaintFlags::kFill_Style); - // Background. Skip drawing for full signal. - if (signal_strength_ != kNumNetworkImages - 1) { - flags.setColor(SkColorSetA(color_, kBgAlpha)); - canvas->sk_canvas()->drawArc(gfx::RectFToSkRect(oval_bounds), kStartAngle, - kSweepAngle, true, flags); - } - // Foreground (signal strength). - if (signal_strength_ != 0) { - flags.setColor(color_); - // Percent of the height of the background wedge that we draw the - // foreground wedge, indexed by signal strength. - static const float kWedgeHeightPercentages[] = {0.f, 0.375f, 0.5833f, - 0.75f, 1.f}; - const float wedge_percent = kWedgeHeightPercentages[signal_strength_]; - oval_bounds.Inset( - gfx::InsetsF((oval_bounds.height() / 2) * (1.f - wedge_percent))); - canvas->sk_canvas()->drawArc(gfx::RectFToSkRect(oval_bounds), kStartAngle, - kSweepAngle, true, flags); - } - } - - void DrawBars(gfx::Canvas* canvas) { - // Undo the canvas's device scaling and round values to the nearest whole - // number so we can draw on exact pixel boundaries. - const float dsf = canvas->UndoDeviceScaleFactor(); - auto scale = [dsf](SkScalar dimension) { - return std::round(dimension * dsf); - }; - - // Length of short side of an isosceles right triangle, in dip. - const SkScalar kFullTriangleSide = - SkIntToScalar(size().width()) - kIconInset * 2; - - auto make_triangle = [scale, kFullTriangleSide](SkScalar side) { - SkPath triangle; - triangle.moveTo(scale(kIconInset), scale(kIconInset + kFullTriangleSide)); - triangle.rLineTo(scale(side), 0); - triangle.rLineTo(0, -scale(side)); - triangle.close(); - return triangle; - }; - - cc::PaintFlags flags; - flags.setAntiAlias(true); - flags.setStyle(cc::PaintFlags::kFill_Style); - // Background. Skip drawing for full signal. - if (signal_strength_ != kNumNetworkImages - 1) { - flags.setColor(SkColorSetA(color_, kBgAlpha)); - canvas->DrawPath(make_triangle(kFullTriangleSide), flags); - } - // Foreground (signal strength). - if (signal_strength_ != 0) { - flags.setColor(color_); - // As a percentage of the bg triangle, the length of one of the short - // sides of the fg triangle, indexed by signal strength. - static const float kTriangleSidePercents[] = {0.f, 0.5f, 0.625f, 0.75f, - 1.f}; - canvas->DrawPath(make_triangle(kTriangleSidePercents[signal_strength_] * - kFullTriangleSide), - flags); - } - } - - ImageType image_type_; - IconType icon_type_; - SkColor color_; - - // On a scale of 0 to kNum{Arcs,Bars}Images - 1, how connected we are. - int signal_strength_; - - // Padding between outside of icon and edge of the canvas, in dp. This value - // stays the same regardless of the canvas size (which depends on - // |icon_type_|). - static constexpr int kIconInset = 2; - - // TODO(estade): share this alpha with other things in ash (battery, etc.). - // See crbug.com/623987 and crbug.com/632827 - static constexpr int kBgAlpha = 0x4D; - - DISALLOW_COPY_AND_ASSIGN(SignalStrengthImageSource); -}; - -//------------------------------------------------------------------------------ -// Utilities for extracting icon images. - -ImageType ImageTypeForNetworkType(const std::string& type) { - if (type == shill::kTypeWifi) - return ARCS; - else if (type == shill::kTypeCellular || type == shill::kTypeWimax) - return BARS; - return NONE; -} - -gfx::ImageSkia GetImageForIndex(ImageType image_type, - IconType icon_type, - int index) { - gfx::CanvasImageSource* source = - new SignalStrengthImageSource(image_type, icon_type, index); - return gfx::ImageSkia(source, source->size()); -} - -const gfx::ImageSkia GetDisconnectedImage(IconType icon_type, - const std::string& network_type) { - DCHECK_NE(shill::kTypeVPN, network_type); - ImageType image_type = ImageTypeForNetworkType(network_type); - const int disconnected_index = 0; - return GetImageForIndex(image_type, icon_type, disconnected_index); -} - -gfx::ImageSkia* ConnectingWirelessImage(ImageType image_type, - IconType icon_type, - double animation) { - static const int kImageCount = kNumNetworkImages - 1; - static gfx::ImageSkia* s_bars_images_dark[kImageCount]; - static gfx::ImageSkia* s_bars_images_light[kImageCount]; - static gfx::ImageSkia* s_arcs_images_dark[kImageCount]; - static gfx::ImageSkia* s_arcs_images_light[kImageCount]; - int index = animation * nextafter(static_cast<float>(kImageCount), 0); - index = std::max(std::min(index, kImageCount - 1), 0); - gfx::ImageSkia** images; - bool dark = IconTypeIsDark(icon_type); - if (image_type == BARS) - images = dark ? s_bars_images_dark : s_bars_images_light; - else - images = dark ? s_arcs_images_dark : s_arcs_images_light; - if (!images[index]) { - // Lazily cache images. - // TODO(estade): should the alpha be applied in SignalStrengthImageSource? - gfx::ImageSkia source = GetImageForIndex(image_type, icon_type, index + 1); - images[index] = - new gfx::ImageSkia(gfx::ImageSkiaOperations::CreateTransparentImage( - source, kConnectingImageAlpha)); - } - return images[index]; -} - -gfx::ImageSkia ConnectingVpnImage(double animation) { - int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); - static gfx::ImageSkia* s_vpn_images[kNumFadeImages]; - if (!s_vpn_images[index]) { - // Lazily cache images. - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - // TODO(estade): update this icon to MD. See crbug.com/690176 - gfx::ImageSkia* icon = rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_VPN); - s_vpn_images[index] = new gfx::ImageSkia( - gfx::ImageSkiaOperations::CreateTransparentImage(*icon, animation)); - } - return *s_vpn_images[index]; -} - -gfx::ImageSkia ConnectingVpnBadge(double animation, IconType icon_type) { - int index = animation * nextafter(static_cast<float>(kNumFadeImages), 0); - static gfx::ImageSkia* s_vpn_badges[kNumFadeImages]; - if (!s_vpn_badges[index]) { - // Lazily cache images. - gfx::ImageSkia badge = gfx::CreateVectorIcon( - kNetworkBadgeVpnIcon, GetDefaultColorForIconType(icon_type)); - s_vpn_badges[index] = new gfx::ImageSkia( - gfx::ImageSkiaOperations::CreateTransparentImage(badge, animation)); - } - return *s_vpn_badges[index]; -} - -int StrengthIndex(int strength) { - // Return an index in the range [1, kNumNetworkImages - 1]. - const float findex = (static_cast<float>(strength) / 100.0f) * - nextafter(static_cast<float>(kNumNetworkImages - 1), 0); - int index = 1 + static_cast<int>(findex); - index = std::max(std::min(index, kNumNetworkImages - 1), 1); - return index; -} - -gfx::ImageSkia BadgeForNetworkTechnology(const NetworkState* network, - IconType icon_type) { - const std::string& technology = network->network_technology(); - const gfx::VectorIcon* icon = &gfx::kNoneIcon; - if (technology == shill::kNetworkTechnologyEvdo) { - icon = &kNetworkBadgeTechnologyEvdoIcon; - } else if (technology == shill::kNetworkTechnology1Xrtt) { - icon = &kNetworkBadgeTechnology1xIcon; - } else if (technology == shill::kNetworkTechnologyGprs || - technology == shill::kNetworkTechnologyGsm) { - icon = &kNetworkBadgeTechnologyGprsIcon; - } else if (technology == shill::kNetworkTechnologyEdge) { - icon = &kNetworkBadgeTechnologyEdgeIcon; - } else if (technology == shill::kNetworkTechnologyUmts) { - icon = &kNetworkBadgeTechnology3gIcon; - } else if (technology == shill::kNetworkTechnologyHspa) { - icon = &kNetworkBadgeTechnologyHspaIcon; - } else if (technology == shill::kNetworkTechnologyHspaPlus) { - icon = &kNetworkBadgeTechnologyHspaPlusIcon; - } else if (technology == shill::kNetworkTechnologyLte) { - icon = &kNetworkBadgeTechnologyLteIcon; - } else if (technology == shill::kNetworkTechnologyLteAdvanced) { - icon = &kNetworkBadgeTechnologyLteAdvancedIcon; - } else { - return gfx::ImageSkia(); - } - return gfx::CreateVectorIcon(*icon, GetDefaultColorForIconType(icon_type)); -} - -gfx::ImageSkia GetIcon(const NetworkState* network, - IconType icon_type, - int strength_index) { - if (network->Matches(NetworkTypePattern::Ethernet())) { - DCHECK_NE(ICON_TYPE_TRAY, icon_type); - return gfx::CreateVectorIcon(kNetworkEthernetIcon, - GetDefaultColorForIconType(ICON_TYPE_LIST)); - } else if (network->Matches(NetworkTypePattern::Wireless())) { - DCHECK(strength_index > 0); - return GetImageForIndex(ImageTypeForNetworkType(network->type()), icon_type, - strength_index); - } else if (network->Matches(NetworkTypePattern::VPN())) { - DCHECK_NE(ICON_TYPE_TRAY, icon_type); - return gfx::CreateVectorIcon(kNetworkVpnIcon, - GetDefaultColorForIconType(ICON_TYPE_LIST)); - } - - NOTREACHED() << "Request for icon for unsupported type: " << network->type(); - return gfx::ImageSkia(); -} - -//------------------------------------------------------------------------------ -// Get connecting images - -gfx::ImageSkia GetConnectingVpnImage(IconType icon_type) { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - const NetworkState* connected_network = nullptr; - if (icon_type == ICON_TYPE_TRAY) { - connected_network = - handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); - } - double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); - - gfx::ImageSkia icon; - Badges badges; - if (connected_network) { - icon = GetImageForNetwork(connected_network, icon_type); - badges.bottom_left = ConnectingVpnBadge(animation, icon_type); - } else { - icon = ConnectingVpnImage(animation); - } - return NetworkIconImageSource::CreateImage(icon, badges); -} - -gfx::ImageSkia GetConnectingImage(IconType icon_type, - const std::string& network_type) { - if (network_type == shill::kTypeVPN) - return GetConnectingVpnImage(icon_type); - - ImageType image_type = ImageTypeForNetworkType(network_type); - double animation = NetworkIconAnimation::GetInstance()->GetAnimation(); - - return NetworkIconImageSource::CreateImage( - *ConnectingWirelessImage(image_type, icon_type, animation), Badges()); -} - -} // namespace - -//------------------------------------------------------------------------------ -// NetworkIconImpl - -NetworkIconImpl::NetworkIconImpl(const std::string& path, IconType icon_type) - : network_path_(path), - icon_type_(icon_type), - strength_index_(-1), - behind_captive_portal_(false) { - // Default image - image_ = GetDisconnectedImage(icon_type, shill::kTypeWifi); -} - -void NetworkIconImpl::Update(const NetworkState* network) { - DCHECK(network); - // Determine whether or not we need to update the icon. - bool dirty = image_.isNull(); - - // If the network state has changed, the icon needs updating. - if (state_ != network->connection_state()) { - state_ = network->connection_state(); - dirty = true; - } - - dirty |= UpdatePortalState(network); - - if (network->Matches(NetworkTypePattern::Wireless())) { - dirty |= UpdateWirelessStrengthIndex(network); - } - - if (network->Matches(NetworkTypePattern::Cellular())) - dirty |= UpdateCellularState(network); - - if (IconTypeHasVPNBadge(icon_type_) && - network->Matches(NetworkTypePattern::NonVirtual())) { - dirty |= UpdateVPNBadge(); - } - - if (dirty) { - // Set the icon and badges based on the network and generate the image. - GenerateImage(network); - } -} - -bool NetworkIconImpl::UpdateWirelessStrengthIndex(const NetworkState* network) { - int index = StrengthIndex(network->signal_strength()); - if (index != strength_index_) { - strength_index_ = index; - return true; - } - return false; -} - -bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) { - bool dirty = false; - const gfx::ImageSkia technology_badge = - BadgeForNetworkTechnology(network, icon_type_); - if (!technology_badge.BackedBySameObjectAs(technology_badge_)) { - technology_badge_ = technology_badge; - dirty = true; - } - std::string roaming_state = network->roaming(); - if (roaming_state != roaming_state_) { - roaming_state_ = roaming_state; - dirty = true; - } - return dirty; -} - -bool NetworkIconImpl::UpdatePortalState(const NetworkState* network) { - bool behind_captive_portal = false; - if (network && chromeos::network_portal_detector::IsInitialized()) { - NetworkPortalDetector::CaptivePortalState state = - chromeos::network_portal_detector::GetInstance()->GetCaptivePortalState( - network->guid()); - behind_captive_portal = - state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL; - } - - if (behind_captive_portal == behind_captive_portal_) - return false; - behind_captive_portal_ = behind_captive_portal; - return true; -} - -bool NetworkIconImpl::UpdateVPNBadge() { - const NetworkState* vpn = - NetworkHandler::Get()->network_state_handler()->ConnectedNetworkByType( - NetworkTypePattern::VPN()); - if (vpn && vpn_badge_.isNull()) { - vpn_badge_ = gfx::CreateVectorIcon(kNetworkBadgeVpnIcon, - GetDefaultColorForIconType(icon_type_)); - return true; - } - if (!vpn && !vpn_badge_.isNull()) { - vpn_badge_ = gfx::ImageSkia(); - return true; - } - return false; -} - -void NetworkIconImpl::GetBadges(const NetworkState* network, Badges* badges) { - DCHECK(network); - - const std::string& type = network->type(); - const SkColor icon_color = GetDefaultColorForIconType(icon_type_); - if (type == shill::kTypeWifi) { - if (network->security_class() != shill::kSecurityNone && - IconTypeIsDark(icon_type_)) { - badges->bottom_right = - gfx::CreateVectorIcon(kNetworkBadgeSecureIcon, icon_color); - } - } else if (type == shill::kTypeWimax) { - technology_badge_ = - gfx::CreateVectorIcon(kNetworkBadgeTechnology4gIcon, icon_color); - } else if (type == shill::kTypeCellular) { - if (network->roaming() == shill::kRoamingStateRoaming) { - // For networks that are always in roaming don't show roaming badge. - const DeviceState* device = - NetworkHandler::Get()->network_state_handler()->GetDeviceState( - network->device_path()); - LOG_IF(WARNING, !device) << "Could not find device state for " - << network->device_path(); - if (!device || !device->provider_requires_roaming()) { - badges->bottom_right = - gfx::CreateVectorIcon(kNetworkBadgeRoamingIcon, icon_color); - } - } - } - if (!network->IsConnectingState()) { - badges->top_left = technology_badge_; - badges->bottom_left = vpn_badge_; - } - - if (behind_captive_portal_) { - badges->bottom_right = - gfx::CreateVectorIcon(kNetworkBadgeCaptivePortalIcon, icon_color); - } -} - -void NetworkIconImpl::GenerateImage(const NetworkState* network) { - DCHECK(network); - gfx::ImageSkia icon = GetIcon(network, icon_type_, strength_index_); - Badges badges; - GetBadges(network, &badges); - image_ = NetworkIconImageSource::CreateImage(icon, badges); -} - -namespace { - -NetworkIconImpl* FindAndUpdateImageImpl(const NetworkState* network, - IconType icon_type) { - // Find or add the icon. - NetworkIconMap* icon_map = GetIconMap(icon_type); - NetworkIconImpl* icon; - NetworkIconMap::iterator iter = icon_map->find(network->path()); - if (iter == icon_map->end()) { - icon = new NetworkIconImpl(network->path(), icon_type); - icon_map->insert(std::make_pair(network->path(), icon)); - } else { - icon = iter->second; - } - - // Update and return the icon's image. - icon->Update(network); - return icon; -} - -} // namespace - -//------------------------------------------------------------------------------ -// Public interface - -gfx::ImageSkia GetImageForNetwork(const NetworkState* network, - IconType icon_type) { - DCHECK(network); - if (!network->visible()) - return GetDisconnectedImage(icon_type, network->type()); - - if (network->IsConnectingState()) - return GetConnectingImage(icon_type, network->type()); - - NetworkIconImpl* icon = FindAndUpdateImageImpl(network, icon_type); - return icon->image(); -} - -gfx::ImageSkia GetImageForConnectedMobileNetwork() { - ImageType image_type = ImageTypeForNetworkType(shill::kTypeWifi); - const IconType icon_type = ICON_TYPE_LIST; - const int connected_index = kNumNetworkImages - 1; - return GetImageForIndex(image_type, icon_type, connected_index); -} - -gfx::ImageSkia GetImageForDisconnectedCellNetwork() { - return GetDisconnectedImage(ICON_TYPE_LIST, shill::kTypeCellular); -} - -gfx::ImageSkia GetImageForNewWifiNetwork(SkColor icon_color, - SkColor badge_color) { - SignalStrengthImageSource* source = - new SignalStrengthImageSource(ImageTypeForNetworkType(shill::kTypeWifi), - ICON_TYPE_LIST, kNumNetworkImages - 1); - source->set_color(icon_color); - gfx::ImageSkia icon = gfx::ImageSkia(source, source->size()); - Badges badges; - badges.bottom_right = - gfx::CreateVectorIcon(kNetworkBadgeAddOtherIcon, badge_color); - return NetworkIconImageSource::CreateImage(icon, badges); -} - -base::string16 GetLabelForNetwork(const chromeos::NetworkState* network, - IconType icon_type) { - DCHECK(network); - std::string activation_state = network->activation_state(); - if (icon_type == ICON_TYPE_LIST || icon_type == ICON_TYPE_MENU_LIST) { - // Show "<network>: [Connecting|Activating|Reconnecting]..." - // TODO(varkha): Remaining states should migrate to secondary status in the - // network item and no longer be part of the label. - // See http://crbug.com/676181 . - if (network->IsReconnecting()) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_LIST_RECONNECTING, - base::UTF8ToUTF16(network->name())); - } - if (icon_type != ICON_TYPE_MENU_LIST && network->IsConnectingState()) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_LIST_CONNECTING, - base::UTF8ToUTF16(network->name())); - } - if (activation_state == shill::kActivationStateActivating) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATING, - base::UTF8ToUTF16(network->name())); - } - // Show "Activate <network>" in list view only. - if (activation_state == shill::kActivationStateNotActivated || - activation_state == shill::kActivationStatePartiallyActivated) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_LIST_ACTIVATE, - base::UTF8ToUTF16(network->name())); - } - } else { - // Show "[Connected to|Connecting to|Activating|Reconnecting to] <network>" - // (non-list view). - if (network->IsReconnecting()) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_RECONNECTING, - base::UTF8ToUTF16(network->name())); - } - if (network->IsConnectedState()) { - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, - base::UTF8ToUTF16(network->name())); - } - if (network->IsConnectingState()) { - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_CONNECTING, - base::UTF8ToUTF16(network->name())); - } - if (activation_state == shill::kActivationStateActivating) { - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_ACTIVATING, - base::UTF8ToUTF16(network->name())); - } - } - - // Otherwise just show the network name or 'Ethernet'. - if (network->Matches(NetworkTypePattern::Ethernet())) { - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ETHERNET); - } else { - return base::UTF8ToUTF16(network->name()); - } -} - -int GetCellularUninitializedMsg() { - static base::Time s_uninitialized_state_time; - static int s_uninitialized_msg(0); - - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - if (handler->GetTechnologyState(NetworkTypePattern::Mobile()) == - NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) { - s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR; - s_uninitialized_state_time = base::Time::Now(); - return s_uninitialized_msg; - } else if (handler->GetScanningByType(NetworkTypePattern::Mobile())) { - s_uninitialized_msg = IDS_ASH_STATUS_TRAY_MOBILE_SCANNING; - s_uninitialized_state_time = base::Time::Now(); - return s_uninitialized_msg; - } - // There can be a delay between leaving the Initializing state and when - // a Cellular device shows up, so keep showing the initializing - // animation for a bit to avoid flashing the disconnect icon. - const int kInitializingDelaySeconds = 1; - base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time; - if (dtime.InSeconds() < kInitializingDelaySeconds) - return s_uninitialized_msg; - return 0; -} - -void GetDefaultNetworkImageAndLabel(IconType icon_type, - gfx::ImageSkia* image, - base::string16* label, - bool* animating) { - NetworkStateHandler* state_handler = - NetworkHandler::Get()->network_state_handler(); - NetworkConnectionHandler* connect_handler = - NetworkHandler::Get()->network_connection_handler(); - const NetworkState* connected_network = - state_handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); - const NetworkState* connecting_network = - state_handler->ConnectingNetworkByType(NetworkTypePattern::Wireless()); - if (!connecting_network && icon_type == ICON_TYPE_TRAY) { - connecting_network = - state_handler->ConnectingNetworkByType(NetworkTypePattern::VPN()); - } - - const NetworkState* network; - // If we are connecting to a network, and there is either no connected - // network, or the connection was user requested, or shill triggered a - // reconnection, use the connecting network. - if (connecting_network && - (!connected_network || connecting_network->IsReconnecting() || - connect_handler->HasConnectingNetwork(connecting_network->path()))) { - network = connecting_network; - } else { - network = connected_network; - } - - // Don't show ethernet in the tray - if (icon_type == ICON_TYPE_TRAY && network && - network->Matches(NetworkTypePattern::Ethernet())) { - *image = gfx::ImageSkia(); - *animating = false; - return; - } - - if (!network) { - // If no connecting network, check if we are activating a network. - const NetworkState* mobile_network = - state_handler->FirstNetworkByType(NetworkTypePattern::Mobile()); - if (mobile_network && (mobile_network->activation_state() == - shill::kActivationStateActivating)) { - network = mobile_network; - } - } - if (!network) { - // If no connecting network, check for cellular initializing. - int uninitialized_msg = GetCellularUninitializedMsg(); - if (uninitialized_msg != 0) { - *image = GetConnectingImage(icon_type, shill::kTypeCellular); - if (label) - *label = l10n_util::GetStringUTF16(uninitialized_msg); - *animating = true; - } else { - // Otherwise show the disconnected wifi icon. - *image = GetDisconnectedImage(icon_type, shill::kTypeWifi); - if (label) { - *label = l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_NOT_CONNECTED); - } - *animating = false; - } - return; - } - *animating = network->IsConnectingState(); - // Get icon and label for connected or connecting network. - *image = GetImageForNetwork(network, icon_type); - if (label) - *label = GetLabelForNetwork(network, icon_type); -} - -void PurgeNetworkIconCache() { - NetworkStateHandler::NetworkStateList networks; - NetworkHandler::Get()->network_state_handler()->GetVisibleNetworkList( - &networks); - std::set<std::string> network_paths; - for (NetworkStateHandler::NetworkStateList::iterator iter = networks.begin(); - iter != networks.end(); ++iter) { - network_paths.insert((*iter)->path()); - } - PurgeIconMap(ICON_TYPE_TRAY, network_paths); - PurgeIconMap(ICON_TYPE_DEFAULT_VIEW, network_paths); - PurgeIconMap(ICON_TYPE_LIST, network_paths); - PurgeIconMap(ICON_TYPE_MENU_LIST, network_paths); -} - -} // namespace network_icon -} // namespace ash
diff --git a/ash/system/network/network_icon.h b/ash/system/network/network_icon.h deleted file mode 100644 index 7e12ef5..0000000 --- a/ash/system/network/network_icon.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_ICON_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_ICON_H_ - -#include <string> - -#include "ash/ash_export.h" -#include "base/strings/string16.h" -#include "ui/gfx/image/image_skia.h" - -namespace chromeos { -class NetworkState; -} - -namespace ash { -namespace network_icon { - -// Type of icon which dictates color theme and VPN badging -enum IconType { - ICON_TYPE_TRAY, // light icons with VPN badges - ICON_TYPE_DEFAULT_VIEW, // dark icons with VPN badges - ICON_TYPE_LIST, // dark icons without VPN badges; in-line status - ICON_TYPE_MENU_LIST, // dark icons without VPN badges; separate status -}; - -// Gets the image for provided |network|. |network| must not be NULL. -// |icon_type| determines the color theme and whether or not to show the VPN -// badge. This caches badged icons per network per |icon_type|. -ASH_EXPORT gfx::ImageSkia GetImageForNetwork( - const chromeos::NetworkState* network, - IconType icon_type); - -// Gets the full strength image for a Wi-Fi network. -// TODO(estade): Expose SignalStrengthImageSource and use that instead. -ASH_EXPORT gfx::ImageSkia GetImageForConnectedMobileNetwork(); - -// Gets the disconnected image for a cell network. -// TODO(estade): Expose SignalStrengthImageSource and use that instead. -ASH_EXPORT gfx::ImageSkia GetImageForDisconnectedCellNetwork(); - -// Gets the full strength image for a Wi-Fi network using |icon_color| for the -// main icon and |badge_color| for the badge. -ASH_EXPORT gfx::ImageSkia GetImageForNewWifiNetwork(SkColor icon_color, - SkColor badge_color); - -// Returns the label for |network| based on |icon_type|. |network| cannot be -// nullptr. -ASH_EXPORT base::string16 GetLabelForNetwork( - const chromeos::NetworkState* network, - IconType icon_type); - -// Updates and returns the appropriate message id if the cellular network -// is uninitialized. -ASH_EXPORT int GetCellularUninitializedMsg(); - -// Gets the correct icon and label for |icon_type|. Also sets |animating| -// based on whether or not the icon is animating (i.e. connecting). -ASH_EXPORT void GetDefaultNetworkImageAndLabel(IconType icon_type, - gfx::ImageSkia* image, - base::string16* label, - bool* animating); - -// Called when the list of networks changes. Retreives the list of networks -// from the global NetworkStateHandler instance and removes cached entries -// that are no longer in the list. -ASH_EXPORT void PurgeNetworkIconCache(); - -} // namespace network_icon -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_ICON_H_
diff --git a/ash/system/network/network_icon_animation.cc b/ash/system/network/network_icon_animation.cc deleted file mode 100644 index 37430391..0000000 --- a/ash/system/network/network_icon_animation.cc +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_icon_animation.h" - -#include "ash/system/network/network_icon_animation_observer.h" - -namespace { -const int kThrobDurationMs = 750; // Animation cycle length. -} - -namespace ash { -namespace network_icon { - -NetworkIconAnimation::NetworkIconAnimation() : animation_(this) { - // Set up the animation throbber. - animation_.SetThrobDuration(kThrobDurationMs); - animation_.SetTweenType(gfx::Tween::LINEAR); -} - -NetworkIconAnimation::~NetworkIconAnimation() {} - -void NetworkIconAnimation::AnimationProgressed( - const gfx::Animation* animation) { - if (animation != &animation_) - return; - for (AnimationObserver& observer : observers_) - observer.NetworkIconChanged(); -} - -double NetworkIconAnimation::GetAnimation() { - if (!animation_.is_animating()) { - animation_.Reset(); - animation_.StartThrobbing(-1 /*throb indefinitely*/); - return 0; - } - return animation_.GetCurrentValue(); -} - -void NetworkIconAnimation::AddObserver(AnimationObserver* observer) { - if (!observers_.HasObserver(observer)) - observers_.AddObserver(observer); -} - -void NetworkIconAnimation::RemoveObserver(AnimationObserver* observer) { - observers_.RemoveObserver(observer); - if (!observers_.might_have_observers()) - animation_.Reset(); // Stops the animation and resets the current value. -} - -// static -NetworkIconAnimation* NetworkIconAnimation::GetInstance() { - static NetworkIconAnimation* s_icon_animation = new NetworkIconAnimation(); - return s_icon_animation; -} - -} // namespace network_icon -} // namespace ash
diff --git a/ash/system/network/network_icon_animation.h b/ash/system/network/network_icon_animation.h deleted file mode 100644 index 9c1636b9..0000000 --- a/ash/system/network/network_icon_animation.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_ICON_ANIMATION_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_ICON_ANIMATION_H_ - -#include <set> -#include <string> - -#include "ash/ash_export.h" -#include "base/observer_list.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/gfx/animation/throb_animation.h" - -namespace ash { -namespace network_icon { - -class AnimationObserver; - -// Single instance class to handle icon animations and keep them in sync. -class ASH_EXPORT NetworkIconAnimation : public gfx::AnimationDelegate { - public: - NetworkIconAnimation(); - ~NetworkIconAnimation() override; - - // Returns the current animation value, [0-1]. - double GetAnimation(); - - // The animation stops when all observers have been removed. - // Be sure to remove observers when no associated icons are animating. - void AddObserver(AnimationObserver* observer); - void RemoveObserver(AnimationObserver* observer); - - // gfx::AnimationDelegate implementation. - void AnimationProgressed(const gfx::Animation* animation) override; - - static NetworkIconAnimation* GetInstance(); - - private: - gfx::ThrobAnimation animation_; - base::ObserverList<AnimationObserver> observers_; -}; - -} // namespace network_icon -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_ICON_ANIMATION_H_
diff --git a/ash/system/network/network_icon_animation_observer.h b/ash/system/network/network_icon_animation_observer.h deleted file mode 100644 index 47aef3c1..0000000 --- a/ash/system/network/network_icon_animation_observer.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_ICON_ANIMATION_OBSERVER_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_ICON_ANIMATION_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { -namespace network_icon { - -// Observer interface class for animating network icons. -class ASH_EXPORT AnimationObserver { - public: - // Called when the image has changed due to animation. The callback should - // trigger a call to GetImageForNetwork() to retrieve the image. - virtual void NetworkIconChanged() = 0; - - protected: - virtual ~AnimationObserver() {} -}; - -} // namespace network_icon -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_ICON_ANIMATION_OBSERVER_H_
diff --git a/ash/system/network/network_info.cc b/ash/system/network/network_info.cc deleted file mode 100644 index 6a1ef049..0000000 --- a/ash/system/network/network_info.cc +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_info.h" - -namespace ash { - -NetworkInfo::NetworkInfo() - : disable(false), - highlight(false), - connected(false), - connecting(false), - type(Type::UNKNOWN) {} - -NetworkInfo::NetworkInfo(const std::string& guid) - : guid(guid), - disable(false), - highlight(false), - connected(false), - connecting(false), - type(Type::UNKNOWN) {} - -NetworkInfo::~NetworkInfo() {} - -} // namespace ash
diff --git a/ash/system/network/network_info.h b/ash/system/network/network_info.h deleted file mode 100644 index d710f387..0000000 --- a/ash/system/network/network_info.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_INFO_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_INFO_H_ - -#include <string> - -#include "base/strings/string16.h" -#include "ui/gfx/image/image_skia.h" - -namespace gfx { -class ImageSkia; -} - -namespace ash { - -// Includes information necessary about a network for displaying the appropriate -// UI to the user. -struct NetworkInfo { - enum class Type { UNKNOWN, WIFI, TETHER, CELLULAR }; - - NetworkInfo(); - NetworkInfo(const std::string& guid); - ~NetworkInfo(); - - std::string guid; - base::string16 label; - base::string16 tooltip; - gfx::ImageSkia image; - bool disable; - bool highlight; - bool connected; - bool connecting; - Type type; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_INFO_H_
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc deleted file mode 100644 index 8576daff..0000000 --- a/ash/system/network/network_list.cc +++ /dev/null
@@ -1,322 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_list.h" - -#include <stddef.h> - -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_info.h" -#include "ash/system/network/network_list_delegate.h" -#include "base/memory/ptr_util.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" -#include "chromeos/dbus/power_manager_client.h" -#include "chromeos/login/login_state.h" -#include "chromeos/network/managed_network_configuration_handler.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "chromeos/network/network_state_handler_observer.h" -#include "components/device_event_log/device_event_log.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/font.h" -#include "ui/views/controls/label.h" -#include "ui/views/view.h" - -using chromeos::LoginState; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; -using chromeos::ManagedNetworkConfigurationHandler; -using chromeos::NetworkTypePattern; - -namespace ash { - -namespace { - -bool IsProhibitedByPolicy(const chromeos::NetworkState* network) { - if (!NetworkTypePattern::WiFi().MatchesType(network->type())) - return false; - if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn()) - return false; - ManagedNetworkConfigurationHandler* managed_configuration_handler = - NetworkHandler::Get()->managed_network_configuration_handler(); - const base::DictionaryValue* global_network_config = - managed_configuration_handler->GetGlobalConfigFromPolicy( - std::string() /* no username hash, device policy */); - bool policy_prohibites_unmanaged = false; - if (global_network_config) { - global_network_config->GetBooleanWithoutPathExpansion( - ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect, - &policy_prohibites_unmanaged); - } - if (!policy_prohibites_unmanaged) - return false; - return !managed_configuration_handler->FindPolicyByGuidAndProfile( - network->guid(), network->profile_path()); -} - -} // namespace - -// NetworkListView: - -NetworkListView::NetworkListView(NetworkListDelegate* delegate) - : delegate_(delegate), - no_wifi_networks_view_(nullptr), - no_cellular_networks_view_(nullptr) { - CHECK(delegate_); -} - -NetworkListView::~NetworkListView() { - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); -} - -void NetworkListView::Update() { - CHECK(container()); - NetworkStateHandler::NetworkStateList network_list; - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - handler->GetVisibleNetworkList(&network_list); - UpdateNetworks(network_list); - UpdateNetworkIcons(); - UpdateNetworkListInternal(); -} - -bool NetworkListView::IsNetworkEntry(views::View* view, - std::string* guid) const { - std::map<views::View*, std::string>::const_iterator found = - network_map_.find(view); - if (found == network_map_.end()) - return false; - *guid = found->second; - return true; -} - -void NetworkListView::UpdateNetworks( - const NetworkStateHandler::NetworkStateList& networks) { - SCOPED_NET_LOG_IF_SLOW(); - network_list_.clear(); - const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); - for (NetworkStateHandler::NetworkStateList::const_iterator iter = - networks.begin(); - iter != networks.end(); ++iter) { - const chromeos::NetworkState* network = *iter; - if (!pattern.MatchesType(network->type())) - continue; - network_list_.push_back(base::MakeUnique<NetworkInfo>(network->guid())); - } -} - -void NetworkListView::UpdateNetworkIcons() { - SCOPED_NET_LOG_IF_SLOW(); - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - // First, update state for all networks - bool animating = false; - - for (auto& info : network_list_) { - const chromeos::NetworkState* network = - handler->GetNetworkStateFromGuid(info->guid); - if (!network) - continue; - bool prohibited_by_policy = IsProhibitedByPolicy(network); - info->image = - network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); - info->label = - network_icon::GetLabelForNetwork(network, network_icon::ICON_TYPE_LIST); - info->highlight = - network->IsConnectedState() || network->IsConnectingState(); - info->disable = - (network->activation_state() == shill::kActivationStateActivating) || - prohibited_by_policy; - if (network->Matches(NetworkTypePattern::WiFi())) - info->type = NetworkInfo::Type::WIFI; - else if (network->Matches(NetworkTypePattern::Cellular())) - info->type = NetworkInfo::Type::CELLULAR; - if (prohibited_by_policy) { - info->tooltip = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED); - } - if (!animating && network->IsConnectingState()) - animating = true; - } - if (animating) - network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); - else - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); -} - -void NetworkListView::UpdateNetworkListInternal() { - SCOPED_NET_LOG_IF_SLOW(); - // Get the updated list entries - network_map_.clear(); - std::set<std::string> new_guids; - bool needs_relayout = UpdateNetworkListEntries(&new_guids); - - // Remove old children - std::set<std::string> remove_guids; - for (NetworkGuidMap::const_iterator it = network_guid_map_.begin(); - it != network_guid_map_.end(); ++it) { - if (new_guids.find(it->first) == new_guids.end()) { - remove_guids.insert(it->first); - network_map_.erase(it->second); - delete it->second; - needs_relayout = true; - } - } - - for (std::set<std::string>::const_iterator remove_it = remove_guids.begin(); - remove_it != remove_guids.end(); ++remove_it) { - network_guid_map_.erase(*remove_it); - } - - if (needs_relayout) - HandleRelayout(); -} - -void NetworkListView::HandleRelayout() { - views::View* selected_view = nullptr; - for (auto& iter : network_guid_map_) { - if (delegate_->IsViewHovered(iter.second)) { - selected_view = iter.second; - break; - } - } - container()->SizeToPreferredSize(); - delegate_->RelayoutScrollList(); - if (selected_view) - container()->ScrollRectToVisible(selected_view->bounds()); -} - -bool NetworkListView::UpdateNetworkListEntries( - std::set<std::string>* new_guids) { - bool needs_relayout = false; - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - // Insert child views - int index = 0; - - // Highlighted networks - needs_relayout |= - UpdateNetworkChildren(new_guids, &index, true /* highlighted */); - - const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); - if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) { - // Cellular initializing - int message_id = network_icon::GetCellularUninitializedMsg(); - if (!message_id && - handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) && - !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) { - message_id = IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS; - } - needs_relayout |= - UpdateInfoLabel(message_id, index, &no_cellular_networks_view_); - - if (message_id) - ++index; - } - - if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) { - // "Wifi Enabled / Disabled" - int message_id = 0; - if (network_list_.empty()) { - message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()) - ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED - : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; - } - needs_relayout |= - UpdateInfoLabel(message_id, index, &no_wifi_networks_view_); - if (message_id) - ++index; - } - - // Un-highlighted networks - needs_relayout |= - UpdateNetworkChildren(new_guids, &index, false /* not highlighted */); - - // No networks or other messages (fallback) - if (index == 0) { - needs_relayout |= UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, index, - &no_wifi_networks_view_); - } - - return needs_relayout; -} - -bool NetworkListView::UpdateNetworkChildren(std::set<std::string>* new_guids, - int* child_index, - bool highlighted) { - bool needs_relayout = false; - int index = *child_index; - for (auto& info : network_list_) { - if (info->highlight != highlighted) - continue; - needs_relayout |= UpdateNetworkChild(index++, info.get()); - new_guids->insert(info->guid); - } - *child_index = index; - return needs_relayout; -} - -bool NetworkListView::UpdateNetworkChild(int index, const NetworkInfo* info) { - bool needs_relayout = false; - views::View* network_view = nullptr; - NetworkGuidMap::const_iterator found = network_guid_map_.find(info->guid); - if (found == network_guid_map_.end()) { - network_view = delegate_->CreateViewForNetwork(*info); - container()->AddChildViewAt(network_view, index); - needs_relayout = true; - } else { - network_view = found->second; - network_view->RemoveAllChildViews(true); - delegate_->UpdateViewForNetwork(network_view, *info); - network_view->Layout(); - network_view->SchedulePaint(); - needs_relayout = PlaceViewAtIndex(network_view, index); - } - if (info->disable) - network_view->SetEnabled(false); - network_map_[network_view] = info->guid; - network_guid_map_[info->guid] = network_view; - return needs_relayout; -} - -bool NetworkListView::PlaceViewAtIndex(views::View* view, int index) { - if (container()->child_at(index) == view) - return false; - container()->ReorderChildView(view, index); - return true; -} - -bool NetworkListView::UpdateInfoLabel(int message_id, - int index, - views::Label** label) { - CHECK(label); - bool needs_relayout = false; - if (message_id) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - base::string16 text = rb.GetLocalizedString(message_id); - if (!*label) { - *label = delegate_->CreateInfoLabel(); - (*label)->SetText(text); - container()->AddChildViewAt(*label, index); - needs_relayout = true; - } else { - (*label)->SetText(text); - needs_relayout = PlaceViewAtIndex(*label, index); - } - } else if (*label) { - delete *label; - *label = nullptr; - needs_relayout = true; - } - return needs_relayout; -} - -void NetworkListView::NetworkIconChanged() { - Update(); -} - -} // namespace ash
diff --git a/ash/system/network/network_list.h b/ash/system/network/network_list.h deleted file mode 100644 index 7f43e1f..0000000 --- a/ash/system/network/network_list.h +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_LIST_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_LIST_H_ - -#include <map> -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "ash/system/network/network_icon_animation_observer.h" -#include "ash/system/network/network_list_view_base.h" -#include "base/macros.h" -#include "chromeos/network/network_state_handler.h" -#include "ui/gfx/image/image_skia.h" - -namespace views { -class Label; -class View; -} - -namespace ash { - -struct NetworkInfo; -class NetworkListDelegate; - -// A list of available networks of a given type. This class is used for all -// network types except VPNs. For VPNs, see the |VPNList| class. -class NetworkListView : public NetworkListViewBase, - public network_icon::AnimationObserver { - public: - explicit NetworkListView(NetworkListDelegate* delegate); - ~NetworkListView() override; - - // NetworkListViewBase: - void Update() override; - bool IsNetworkEntry(views::View* view, std::string* guid) const override; - - private: - void UpdateNetworks( - const chromeos::NetworkStateHandler::NetworkStateList& networks); - void UpdateNetworkIcons(); - void UpdateNetworkListInternal(); - void HandleRelayout(); - bool UpdateNetworkListEntries(std::set<std::string>* new_guids); - bool UpdateNetworkChildren(std::set<std::string>* new_guids, - int* child_index, - bool highlighted); - bool UpdateNetworkChild(int index, const NetworkInfo* info); - bool PlaceViewAtIndex(views::View* view, int index); - bool UpdateInfoLabel(int message_id, int index, views::Label** label); - - // network_icon::AnimationObserver: - void NetworkIconChanged() override; - - NetworkListDelegate* delegate_; - - views::Label* no_wifi_networks_view_; - views::Label* no_cellular_networks_view_; - - // An owned list of network info. - std::vector<std::unique_ptr<NetworkInfo>> network_list_; - - typedef std::map<views::View*, std::string> NetworkMap; - NetworkMap network_map_; - - // A map of network guids to their view. - typedef std::map<std::string, views::View*> NetworkGuidMap; - NetworkGuidMap network_guid_map_; - - DISALLOW_COPY_AND_ASSIGN(NetworkListView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_LIST_H_
diff --git a/ash/system/network/network_list_delegate.h b/ash/system/network/network_list_delegate.h deleted file mode 100644 index d64901c..0000000 --- a/ash/system/network/network_list_delegate.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_LIST_DELEGATE_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_LIST_DELEGATE_H_ - -namespace chromeos { -class NetworkTypePattern; -} - -namespace views { -class Label; -class View; -} - -namespace ash { - -struct NetworkInfo; - -class NetworkListDelegate { - public: - virtual ~NetworkListDelegate() {} - - // Creates and returns a View with the information in |info|. - virtual views::View* CreateViewForNetwork(const NetworkInfo& info) = 0; - - // Returns true if |view| is currently under the cursor. Note that |view| is - // guaranteed to be a View returned from |CreateViewForNetwork()|. - virtual bool IsViewHovered(views::View* view) = 0; - - // Returns the type of network this list should use. - virtual chromeos::NetworkTypePattern GetNetworkTypePattern() const = 0; - - // Updates |view| with the information in |info|. Note that |view| is - // guaranteed to be a View returned from |CreateViewForNetwork()|. - virtual void UpdateViewForNetwork(views::View* view, - const NetworkInfo& info) = 0; - - // Creates a Label to be displayed in the list to present some information - // (e.g. unavailability of network etc.). - virtual views::Label* CreateInfoLabel() = 0; - - // Called when the user clicks on an entry representing a network in the list. - virtual void OnNetworkEntryClicked(views::View* sender) = 0; - - // Called when the user clicks on a "Join Other" button. - virtual void OnOtherWifiClicked() = 0; - - virtual void RelayoutScrollList() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_LIST_DELEGATE_H_
diff --git a/ash/system/network/network_list_md.cc b/ash/system/network/network_list_md.cc deleted file mode 100644 index 9eb0ea3b..0000000 --- a/ash/system/network/network_list_md.cc +++ /dev/null
@@ -1,653 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_list_md.h" - -#include <stddef.h> - -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_list_delegate.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "base/memory/ptr_util.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" -#include "chromeos/dbus/power_manager_client.h" -#include "chromeos/login/login_state.h" -#include "chromeos/network/managed_network_configuration_handler.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "chromeos/network/network_state_handler_observer.h" -#include "components/device_event_log/device_event_log.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/font.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/views/controls/button/toggle_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/painter.h" -#include "ui/views/view.h" - -using chromeos::LoginState; -using chromeos::NetworkHandler; -using chromeos::NetworkStateHandler; -using chromeos::ManagedNetworkConfigurationHandler; -using chromeos::NetworkTypePattern; - -namespace ash { - -namespace { - -bool IsProhibitedByPolicy(const chromeos::NetworkState* network) { - if (!NetworkTypePattern::WiFi().MatchesType(network->type())) - return false; - if (!LoginState::IsInitialized() || !LoginState::Get()->IsUserLoggedIn()) - return false; - ManagedNetworkConfigurationHandler* managed_configuration_handler = - NetworkHandler::Get()->managed_network_configuration_handler(); - const base::DictionaryValue* global_network_config = - managed_configuration_handler->GetGlobalConfigFromPolicy( - std::string() /* no username hash, device policy */); - bool policy_prohibites_unmanaged = false; - if (global_network_config) { - global_network_config->GetBooleanWithoutPathExpansion( - ::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect, - &policy_prohibites_unmanaged); - } - if (!policy_prohibites_unmanaged) - return false; - return !managed_configuration_handler->FindPolicyByGuidAndProfile( - network->guid(), network->profile_path()); -} - -} // namespace - -// A header row for sections in network detailed view which contains a title and -// a toggle button to turn on/off the section. Subclasses are given the -// opportunity to add extra buttons before the toggle button is added. -class NetworkListViewMd::SectionHeaderRowView : public views::View, - public views::ButtonListener { - public: - explicit SectionHeaderRowView(int title_id) - : title_id_(title_id), - container_(nullptr), - toggle_(nullptr), - style_( - new TrayPopupItemStyle(TrayPopupItemStyle::FontStyle::SUB_HEADER)) { - } - - ~SectionHeaderRowView() override {} - - void Init(bool enabled) { - InitializeLayout(); - AddExtraButtons(enabled); - AddToggleButton(enabled); - } - - virtual void SetEnabled(bool enabled) { toggle_->SetIsOn(enabled, true); } - - protected: - // This is called before the toggle button is added to give subclasses an - // opportunity to add more buttons before the toggle button. Subclasses can - // add buttons to container() using AddChildView(). - virtual void AddExtraButtons(bool enabled) {} - - // Called when |toggle_| is clicked and toggled. Subclasses can override to - // enabled/disable their respective technology, for example. - virtual void OnToggleToggled(bool is_on) = 0; - - TriView* container() const { return container_; } - TrayPopupItemStyle* style() const { return style_.get(); } - - int GetHeightForWidth(int w) const override { - // Make row height fixed avoiding layout manager adjustments. - return GetPreferredSize().height(); - } - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override { - DCHECK_EQ(toggle_, sender); - OnToggleToggled(toggle_->is_on()); - } - - private: - void InitializeLayout() { - // TODO(mohsen): Consider using TriView class and adding a utility function - // to TrayPopupUtils to simplify creation of the following layout. See - // https://crbug.com/614453. - TrayPopupUtils::ConfigureAsStickyHeader(this); - SetLayoutManager(new views::FillLayout); - container_ = TrayPopupUtils::CreateSubHeaderRowView(); - AddChildView(container_); - - views::Label* label = TrayPopupUtils::CreateDefaultLabel(); - style()->SetupLabel(label); - label->SetText(l10n_util::GetStringUTF16(title_id_)); - container_->AddView(TriView::Container::CENTER, label); - } - - void AddToggleButton(bool enabled) { - toggle_ = TrayPopupUtils::CreateToggleButton(this, title_id_); - toggle_->SetIsOn(enabled, false); - container_->AddView(TriView::Container::END, toggle_); - } - - // Resource ID for the string to use as the title of the section and for the - // accessible text on the section header toggle button. - const int title_id_; - - // View containing header row views, including title, toggle, and extra - // buttons. - TriView* container_; - - // ToggleButton to toggle section on or off. - views::ToggleButton* toggle_; - - // TrayPopupItemStyle used to configure labels and buttons. - std::unique_ptr<TrayPopupItemStyle> style_; - - DISALLOW_COPY_AND_ASSIGN(SectionHeaderRowView); -}; - -namespace { - -class CellularHeaderRowView : public NetworkListViewMd::SectionHeaderRowView { - public: - CellularHeaderRowView() - : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_MOBILE) {} - - ~CellularHeaderRowView() override {} - - const char* GetClassName() const override { return "CellularHeaderRowView"; } - - protected: - void OnToggleToggled(bool is_on) override { - NetworkStateHandler* handler = - NetworkHandler::Get()->network_state_handler(); - handler->SetTechnologyEnabled(NetworkTypePattern::Cellular(), is_on, - chromeos::network_handler::ErrorCallback()); - } - - private: - DISALLOW_COPY_AND_ASSIGN(CellularHeaderRowView); -}; - -class TetherHeaderRowView : public NetworkListViewMd::SectionHeaderRowView { - public: - TetherHeaderRowView() - : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_TETHER) {} - - ~TetherHeaderRowView() override {} - - const char* GetClassName() const override { return "TetherHeaderRowView"; } - - protected: - void OnToggleToggled(bool is_on) override { - // TODO (hansberry): Persist toggle to settings/preferences. - } - - private: - DISALLOW_COPY_AND_ASSIGN(TetherHeaderRowView); -}; - -class WifiHeaderRowView : public NetworkListViewMd::SectionHeaderRowView { - public: - explicit WifiHeaderRowView(NetworkListDelegate* network_list_delegate) - : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_WIFI), - network_list_delegate_(network_list_delegate), - join_(nullptr) {} - - ~WifiHeaderRowView() override {} - - void SetEnabled(bool enabled) override { - join_->SetEnabled(enabled); - SectionHeaderRowView::SetEnabled(enabled); - } - - const char* GetClassName() const override { return "WifiHeaderRowView"; } - - protected: - // SectionHeaderRowView: - void OnToggleToggled(bool is_on) override { - NetworkStateHandler* handler = - NetworkHandler::Get()->network_state_handler(); - handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), is_on, - chromeos::network_handler::ErrorCallback()); - } - - void AddExtraButtons(bool enabled) override { - const SkColor prominent_color = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor); - gfx::ImageSkia normal_image = network_icon::GetImageForNewWifiNetwork( - SkColorSetA(prominent_color, kJoinIconAlpha), - SkColorSetA(prominent_color, kJoinBadgeAlpha)); - gfx::ImageSkia disabled_image = network_icon::GetImageForNewWifiNetwork( - SkColorSetA(prominent_color, kDisabledJoinIconAlpha), - SkColorSetA(prominent_color, kDisabledJoinBadgeAlpha)); - join_ = new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - normal_image, disabled_image, - IDS_ASH_STATUS_TRAY_OTHER_WIFI); - join_->SetInkDropColor(prominent_color); - join_->SetEnabled(enabled); - container()->AddView(TriView::Container::END, join_); - } - - void ButtonPressed(views::Button* sender, const ui::Event& event) override { - if (sender == join_) { - network_list_delegate_->OnOtherWifiClicked(); - return; - } - SectionHeaderRowView::ButtonPressed(sender, event); - } - - private: - // Full opacity for badge. - static constexpr int kJoinBadgeAlpha = 0xFF; - - // .30 opacity for icon. - static constexpr int kJoinIconAlpha = 0x4D; - - // .38 opacity for disabled badge. - static constexpr int kDisabledJoinBadgeAlpha = 0x61; - - // .30 * .38 opacity for disabled icon. - static constexpr int kDisabledJoinIconAlpha = 0x1D; - - NetworkListDelegate* network_list_delegate_; - - // A button to invoke "Join Wi-Fi network" dialog. - SystemMenuButton* join_; - - DISALLOW_COPY_AND_ASSIGN(WifiHeaderRowView); -}; - -} // namespace - -// NetworkListViewMd: - -NetworkListViewMd::NetworkListViewMd(NetworkListDelegate* delegate) - : needs_relayout_(false), - delegate_(delegate), - no_wifi_networks_view_(nullptr), - no_cellular_networks_view_(nullptr), - cellular_header_view_(nullptr), - tether_header_view_(nullptr), - wifi_header_view_(nullptr), - cellular_separator_view_(nullptr), - tether_separator_view_(nullptr), - wifi_separator_view_(nullptr) { - CHECK(delegate_); -} - -NetworkListViewMd::~NetworkListViewMd() { - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); -} - -void NetworkListViewMd::Update() { - CHECK(container()); - - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - NetworkStateHandler::NetworkStateList network_list; - handler->GetVisibleNetworkList(&network_list); - UpdateNetworks(network_list); - - NetworkStateHandler::NetworkStateList tether_network_list; - handler->GetTetherNetworkList(0 /* no limit */, &tether_network_list); - for (const auto* tether_network : tether_network_list) { - network_list_.push_back( - base::MakeUnique<NetworkInfo>(tether_network->guid())); - } - - UpdateNetworkIcons(); - OrderNetworks(); - UpdateNetworkListInternal(); -} - -bool NetworkListViewMd::IsNetworkEntry(views::View* view, - std::string* guid) const { - std::map<views::View*, std::string>::const_iterator found = - network_map_.find(view); - if (found == network_map_.end()) - return false; - *guid = found->second; - return true; -} - -void NetworkListViewMd::UpdateNetworks( - const NetworkStateHandler::NetworkStateList& networks) { - SCOPED_NET_LOG_IF_SLOW(); - network_list_.clear(); - const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); - for (const auto* network : networks) { - if (pattern.MatchesType(network->type())) - network_list_.push_back(base::MakeUnique<NetworkInfo>(network->guid())); - } -} - -void NetworkListViewMd::OrderNetworks() { - struct CompareNetwork { - explicit CompareNetwork(NetworkStateHandler* handler) : handler_(handler) {} - - // Returns true if |network1| is less than (i.e. is ordered before) - // |network2|. - bool operator()(const std::unique_ptr<NetworkInfo>& network1, - const std::unique_ptr<NetworkInfo>& network2) { - const int order1 = - GetOrder(handler_->GetNetworkStateFromGuid(network1->guid)); - const int order2 = - GetOrder(handler_->GetNetworkStateFromGuid(network2->guid)); - if (order1 != order2) - return order1 < order2; - if (network1->connected != network2->connected) - return network1->connected; - if (network1->connecting != network2->connecting) - return network1->connecting; - if (network1->highlight != network2->highlight) - return network1->highlight; - return network1->guid.compare(network2->guid) < 0; - } - - private: - static int GetOrder(const chromeos::NetworkState* network) { - if (!network) - return 999; - if (network->Matches(NetworkTypePattern::Ethernet())) - return 0; - if (network->Matches(NetworkTypePattern::Cellular())) - return 1; - if (network->Matches(NetworkTypePattern::Mobile())) - return 2; - if (network->Matches(NetworkTypePattern::WiFi())) - return 3; - return 4; - } - - NetworkStateHandler* handler_; - }; - std::sort(network_list_.begin(), network_list_.end(), - CompareNetwork(NetworkHandler::Get()->network_state_handler())); -} - -void NetworkListViewMd::UpdateNetworkIcons() { - SCOPED_NET_LOG_IF_SLOW(); - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - // First, update state for all networks. - bool animating = false; - - for (auto& info : network_list_) { - const chromeos::NetworkState* network = - handler->GetNetworkStateFromGuid(info->guid); - if (!network) - continue; - bool prohibited_by_policy = IsProhibitedByPolicy(network); - info->label = network_icon::GetLabelForNetwork( - network, network_icon::ICON_TYPE_MENU_LIST); - info->image = - network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); - info->disable = - (network->activation_state() == shill::kActivationStateActivating) || - prohibited_by_policy; - info->connected = network->IsConnectedState(); - info->connecting = network->IsConnectingState(); - info->highlight = info->connected || info->connecting; - if (network->Matches(NetworkTypePattern::WiFi())) - info->type = NetworkInfo::Type::WIFI; - else if (network->Matches(NetworkTypePattern::Cellular())) - info->type = NetworkInfo::Type::CELLULAR; - else if (network->Matches(NetworkTypePattern::Tether())) - info->type = NetworkInfo::Type::TETHER; - if (prohibited_by_policy) { - info->tooltip = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED); - } - if (!animating && network->IsConnectingState()) - animating = true; - } - if (animating) - network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); - else - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); -} - -void NetworkListViewMd::UpdateNetworkListInternal() { - SCOPED_NET_LOG_IF_SLOW(); - // Get the updated list entries. - needs_relayout_ = false; - network_map_.clear(); - std::unique_ptr<std::set<std::string>> new_guids = UpdateNetworkListEntries(); - - // Remove old children. - std::set<std::string> remove_guids; - for (const auto& iter : network_guid_map_) { - if (new_guids->find(iter.first) == new_guids->end()) { - remove_guids.insert(iter.first); - network_map_.erase(iter.second); - delete iter.second; - needs_relayout_ = true; - } - } - - for (const auto& remove_iter : remove_guids) - network_guid_map_.erase(remove_iter); - - if (!needs_relayout_) - return; - - views::View* selected_view = nullptr; - for (const auto& iter : network_guid_map_) { - if (delegate_->IsViewHovered(iter.second)) { - selected_view = iter.second; - break; - } - } - container()->SizeToPreferredSize(); - delegate_->RelayoutScrollList(); - if (selected_view) - container()->ScrollRectToVisible(selected_view->bounds()); -} - -std::unique_ptr<std::set<std::string>> -NetworkListViewMd::UpdateNetworkListEntries() { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - // First add high-priority networks (not Wi-Fi nor cellular). - std::unique_ptr<std::set<std::string>> new_guids = - UpdateNetworkChildren(NetworkInfo::Type::UNKNOWN, 0); - - // Keep an index where the next child should be inserted. - int index = new_guids->size(); - - const NetworkTypePattern pattern = delegate_->GetNetworkTypePattern(); - if (pattern.MatchesPattern(NetworkTypePattern::Cellular())) { - if (handler->IsTechnologyAvailable(NetworkTypePattern::Cellular())) { - index = UpdateSectionHeaderRow( - NetworkTypePattern::Cellular(), - handler->IsTechnologyEnabled(NetworkTypePattern::Cellular()), index, - &cellular_header_view_, &cellular_separator_view_); - } - - // Cellular initializing. - int message_id = network_icon::GetCellularUninitializedMsg(); - if (!message_id && - handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) && - !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) { - message_id = IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS; - } - UpdateInfoLabel(message_id, index, &no_cellular_networks_view_); - if (message_id) - ++index; - - // Add cellular networks. - std::unique_ptr<std::set<std::string>> new_cellular_guids = - UpdateNetworkChildren(NetworkInfo::Type::CELLULAR, index); - index += new_cellular_guids->size(); - new_guids->insert(new_cellular_guids->begin(), new_cellular_guids->end()); - } - - // TODO (hansberry): Audit existing usage of NonVirtual and consider changing - // it to include Tether. See crbug.com/693647. - if (handler->IsTechnologyAvailable(NetworkTypePattern::Tether())) { - index = UpdateSectionHeaderRow( - NetworkTypePattern::Tether(), - handler->IsTechnologyEnabled(NetworkTypePattern::Tether()), index, - &tether_header_view_, &tether_separator_view_); - - // TODO (hansberry): Should a message similar to - // IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS be shown if Tether technology - // is enabled but no networks are around? - - // Add Tether networks. - std::unique_ptr<std::set<std::string>> new_tether_guids = - UpdateNetworkChildren(NetworkInfo::Type::TETHER, index); - index += new_tether_guids->size(); - new_guids->insert(new_tether_guids->begin(), new_tether_guids->end()); - } - - if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) { - index = UpdateSectionHeaderRow( - NetworkTypePattern::WiFi(), - handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()), index, - &wifi_header_view_, &wifi_separator_view_); - - // "Wifi Enabled / Disabled". - int message_id = 0; - if (network_list_.empty()) { - message_id = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()) - ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED - : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; - } - UpdateInfoLabel(message_id, index, &no_wifi_networks_view_); - if (message_id) - ++index; - - // Add Wi-Fi networks. - std::unique_ptr<std::set<std::string>> new_wifi_guids = - UpdateNetworkChildren(NetworkInfo::Type::WIFI, index); - index += new_wifi_guids->size(); - new_guids->insert(new_wifi_guids->begin(), new_wifi_guids->end()); - } - - // No networks or other messages (fallback). - if (index == 0) { - UpdateInfoLabel(IDS_ASH_STATUS_TRAY_NO_NETWORKS, index, - &no_wifi_networks_view_); - } - - return new_guids; -} - -std::unique_ptr<std::set<std::string>> NetworkListViewMd::UpdateNetworkChildren( - NetworkInfo::Type type, - int index) { - std::unique_ptr<std::set<std::string>> new_guids(new std::set<std::string>); - for (const auto& info : network_list_) { - if (info->type != type) - continue; - UpdateNetworkChild(index++, info.get()); - new_guids->insert(info->guid); - } - return new_guids; -} - -void NetworkListViewMd::UpdateNetworkChild(int index, const NetworkInfo* info) { - views::View* network_view = nullptr; - NetworkGuidMap::const_iterator found = network_guid_map_.find(info->guid); - if (found == network_guid_map_.end()) { - network_view = delegate_->CreateViewForNetwork(*info); - } else { - network_view = found->second; - network_view->RemoveAllChildViews(true); - delegate_->UpdateViewForNetwork(network_view, *info); - network_view->Layout(); - network_view->SchedulePaint(); - } - PlaceViewAtIndex(network_view, index); - if (info->disable) - network_view->SetEnabled(false); - network_map_[network_view] = info->guid; - network_guid_map_[info->guid] = network_view; -} - -void NetworkListViewMd::PlaceViewAtIndex(views::View* view, int index) { - if (view->parent() != container()) { - container()->AddChildViewAt(view, index); - } else { - if (container()->child_at(index) == view) - return; - container()->ReorderChildView(view, index); - } - needs_relayout_ = true; -} - -void NetworkListViewMd::UpdateInfoLabel(int message_id, - int insertion_index, - views::Label** label_ptr) { - views::Label* label = *label_ptr; - if (!message_id) { - if (label) { - needs_relayout_ = true; - delete label; - *label_ptr = nullptr; - } - return; - } - base::string16 text = - ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id); - if (!label) - label = delegate_->CreateInfoLabel(); - label->SetText(text); - PlaceViewAtIndex(label, insertion_index); - *label_ptr = label; -} - -int NetworkListViewMd::UpdateSectionHeaderRow( - NetworkTypePattern pattern, - bool enabled, - int child_index, - SectionHeaderRowView** view, - views::Separator** separator_view) { - if (!*view) { - if (pattern.Equals(NetworkTypePattern::Cellular())) - *view = new CellularHeaderRowView(); - else if (pattern.Equals(NetworkTypePattern::Tether())) - *view = new TetherHeaderRowView(); - else if (pattern.Equals(NetworkTypePattern::WiFi())) - *view = new WifiHeaderRowView(delegate_); - else - NOTREACHED(); - (*view)->Init(enabled); - } - // Show or hide a separator above the header. The separator should only be - // visible when the header row is not at the top of the list. - if (child_index > 0) { - if (!*separator_view) - *separator_view = TrayPopupUtils::CreateListSubHeaderSeparator(); - PlaceViewAtIndex(*separator_view, child_index++); - } else { - if (*separator_view) - delete *separator_view; - *separator_view = nullptr; - } - - (*view)->SetEnabled(enabled); - PlaceViewAtIndex(*view, child_index++); - return child_index; -} - -void NetworkListViewMd::NetworkIconChanged() { - Update(); -} - -} // namespace ash
diff --git a/ash/system/network/network_list_md.h b/ash/system/network/network_list_md.h deleted file mode 100644 index 3b4685a8..0000000 --- a/ash/system/network/network_list_md.h +++ /dev/null
@@ -1,132 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_LIST_MD_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_LIST_MD_H_ - -#include <map> -#include <memory> -#include <set> -#include <string> -#include <vector> - -#include "ash/system/network/network_icon_animation_observer.h" -#include "ash/system/network/network_info.h" -#include "ash/system/network/network_list_view_base.h" -#include "base/macros.h" -#include "chromeos/network/network_state_handler.h" -#include "chromeos/network/network_type_pattern.h" -#include "ui/gfx/image/image_skia.h" - -namespace views { -class Label; -class Separator; -class View; -} - -namespace ash { - -struct NetworkInfo; -class NetworkListDelegate; - -// A list of available networks of a given type. This class is used for all -// network types except VPNs. For VPNs, see the |VPNList| class. -class NetworkListViewMd : public NetworkListViewBase, - public network_icon::AnimationObserver { - public: - class SectionHeaderRowView; - - explicit NetworkListViewMd(NetworkListDelegate* delegate); - ~NetworkListViewMd() override; - - // NetworkListViewBase: - void Update() override; - bool IsNetworkEntry(views::View* view, std::string* guid) const override; - - private: - // Clears |network_list_| and adds to it |networks| that match |delegate_|'s - // network type pattern. - void UpdateNetworks( - const chromeos::NetworkStateHandler::NetworkStateList& networks); - - // Updates |network_list_| entries and sets |this| to observe network icon - // animations when any of the networks are in connecting state. - void UpdateNetworkIcons(); - - // Orders entries in |network_list_| such that higher priority network types - // are at the top of the list. - void OrderNetworks(); - - // Refreshes a list of child views, updates |network_map_| and - // |network_guid_map_| and performs layout making sure selected view if any is - // scrolled into view. - void UpdateNetworkListInternal(); - - // Adds new or updates existing child views including header row and messages. - // Returns a set of guids for the added network connections. - std::unique_ptr<std::set<std::string>> UpdateNetworkListEntries(); - - // Adds or updates child views representing the network connections when - // |is_wifi| is matching the attribute of a network connection starting at - // |child_index|. Returns a set of guids for the added network - // connections. - std::unique_ptr<std::set<std::string>> UpdateNetworkChildren( - NetworkInfo::Type type, - int child_index); - void UpdateNetworkChild(int index, const NetworkInfo* info); - - // Reorders children of |container()| as necessary placing |view| at |index|. - void PlaceViewAtIndex(views::View* view, int index); - - // Creates a Label with text specified by |message_id| and adds it to - // |container()| if necessary or updates the text and reorders the - // |container()| placing the label at |insertion_index|. When |message_id| is - // zero removes the |*label_ptr| from the |container()| and destroys it. - // |label_ptr| is an in / out parameter and is only modified if the Label is - // created or destroyed. - void UpdateInfoLabel(int message_id, - int insertion_index, - views::Label** label_ptr); - - // Creates a cellular/Wi-Fi header row |view| and adds it to |container()| if - // necessary and reorders the |container()| placing the |view| at - // |child_index|. Returns the index where the next child should be inserted, - // i.e., the index directly after the last inserted child. - int UpdateSectionHeaderRow(chromeos::NetworkTypePattern pattern, - bool enabled, - int child_index, - SectionHeaderRowView** view, - views::Separator** separator_view); - - // network_icon::AnimationObserver: - void NetworkIconChanged() override; - - bool needs_relayout_; - NetworkListDelegate* delegate_; - - views::Label* no_wifi_networks_view_; - views::Label* no_cellular_networks_view_; - SectionHeaderRowView* cellular_header_view_; - SectionHeaderRowView* tether_header_view_; - SectionHeaderRowView* wifi_header_view_; - views::Separator* cellular_separator_view_; - views::Separator* tether_separator_view_; - views::Separator* wifi_separator_view_; - - // An owned list of network info. - std::vector<std::unique_ptr<NetworkInfo>> network_list_; - - using NetworkMap = std::map<views::View*, std::string>; - NetworkMap network_map_; - - // A map of network guids to their view. - typedef std::map<std::string, views::View*> NetworkGuidMap; - NetworkGuidMap network_guid_map_; - - DISALLOW_COPY_AND_ASSIGN(NetworkListViewMd); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_LIST_MD_H_
diff --git a/ash/system/network/network_list_view_base.cc b/ash/system/network/network_list_view_base.cc deleted file mode 100644 index a20383b..0000000 --- a/ash/system/network/network_list_view_base.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_list_view_base.h" - -namespace ash { - -NetworkListViewBase::NetworkListViewBase() {} - -NetworkListViewBase::~NetworkListViewBase() {} - -} // namespace ash
diff --git a/ash/system/network/network_list_view_base.h b/ash/system/network/network_list_view_base.h deleted file mode 100644 index c5eee11..0000000 --- a/ash/system/network/network_list_view_base.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_LIST_VIEW_BASE_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_LIST_VIEW_BASE_H_ - -#include <string> - -#include "base/macros.h" - -namespace views { -class View; -} - -namespace ash { - -// Base class for a list of available networks (and, in the case of VPNs, the -// list of available VPN providers). -class NetworkListViewBase { - public: - NetworkListViewBase(); - virtual ~NetworkListViewBase(); - - void set_container(views::View* container) { container_ = container; } - - // Refreshes the network list. - virtual void Update() = 0; - - // Checks whether |view| represents a network in the list. If yes, sets - // |guid| to the network's guid and returns |true|. Otherwise, - // leaves |guid| unchanged and returns |false|. - virtual bool IsNetworkEntry(views::View* view, std::string* guid) const = 0; - - protected: - views::View* container() { return container_; } - - private: - // The container that holds the actual list entries. - views::View* container_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(NetworkListViewBase); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_LIST_VIEW_BASE_H_
diff --git a/ash/system/network/network_observer.h b/ash/system/network/network_observer.h deleted file mode 100644 index b548f71e..0000000 --- a/ash/system/network/network_observer.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_OBSERVER_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_OBSERVER_H_ - -namespace ash { - -class NetworkObserver { - public: - virtual ~NetworkObserver() {} - - // Called to request toggling Wi-Fi enable/disable, e.g. from an accelerator. - // NOTE: Toggling is asynchronous and subsequent calls to query the current - // state may return the old value. - virtual void RequestToggleWifi() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_OBSERVER_H_
diff --git a/ash/system/network/network_portal_detector_observer.h b/ash/system/network/network_portal_detector_observer.h deleted file mode 100644 index aa2b394..0000000 --- a/ash/system/network/network_portal_detector_observer.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_PORTAL_DETECTOR_OBSERVER_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_PORTAL_DETECTOR_OBSERVER_H_ - -#include <string> - -namespace ash { - -class NetworkPortalDetectorObserver { - public: - virtual ~NetworkPortalDetectorObserver() {} - - // Called when captive portal is detected for the network associated with - // |guid|. - virtual void OnCaptivePortalDetected(const std::string& guid) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_PORTAL_DETECTOR_OBSERVER_H_
diff --git a/ash/system/network/network_state_list_detailed_view.cc b/ash/system/network/network_state_list_detailed_view.cc deleted file mode 100644 index caf797c..0000000 --- a/ash/system/network/network_state_list_detailed_view.cc +++ /dev/null
@@ -1,758 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/network_state_list_detailed_view.h" - -#include <algorithm> -#include <vector> - -#include "ash/common/ash_constants.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/root_window_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_info.h" -#include "ash/system/network/network_list.h" -#include "ash/system/network/network_list_md.h" -#include "ash/system/network/network_list_view_base.h" -#include "ash/system/network/tray_network_state_observer.h" -#include "ash/system/network/vpn_list_view.h" -#include "ash/system/networking_config_delegate.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/throbber_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_popup_header_button.h" -#include "ash/system/tray/tri_view.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "chromeos/chromeos_switches.h" -#include "chromeos/login/login_state.h" -#include "chromeos/network/device_state.h" -#include "chromeos/network/managed_network_configuration_handler.h" -#include "chromeos/network/network_connect.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "third_party/cros_system_api/dbus/service_constants.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/text_constants.h" -#include "ui/views/bubble/bubble_dialog_delegate.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/layout/layout_manager.h" -#include "ui/views/painter.h" -#include "ui/views/widget/widget.h" - -using chromeos::DeviceState; -using chromeos::LoginState; -using chromeos::NetworkHandler; -using chromeos::NetworkState; -using chromeos::NetworkStateHandler; -using chromeos::NetworkTypePattern; - -namespace ash { -namespace tray { -namespace { - -bool UseMd() { - return MaterialDesignController::IsSystemTrayMenuMaterial(); -} - -// Delay between scan requests. -const int kRequestScanDelaySeconds = 10; - -// Create a label with the font size and color used in the network info bubble. -views::Label* CreateInfoBubbleLabel(const base::string16& text) { - views::Label* label = new views::Label(text); - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - label->SetFontList(rb.GetFontList(ui::ResourceBundle::SmallFont)); - label->SetEnabledColor(SkColorSetARGB(127, 0, 0, 0)); - return label; -} - -// Create a row of labels for the network info bubble. -views::View* CreateInfoBubbleLine(const base::string16& text_label, - const std::string& text_string) { - views::View* view = new views::View; - view->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 1)); - view->AddChildView(CreateInfoBubbleLabel(text_label)); - view->AddChildView(CreateInfoBubbleLabel(base::UTF8ToUTF16(": "))); - view->AddChildView(CreateInfoBubbleLabel(base::UTF8ToUTF16(text_string))); - return view; -} - -// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. -void SetupConnectedItemMd(HoverHighlightView* container, - const base::string16& text, - const gfx::ImageSkia& image) { - container->AddIconAndLabels( - image, text, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); - style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); - style.SetupLabel(container->sub_text_label()); -} - -// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. -void SetupConnectingItemMd(HoverHighlightView* container, - const base::string16& text, - const gfx::ImageSkia& image) { - container->AddIconAndLabels( - image, text, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); - ThrobberView* throbber = new ThrobberView; - throbber->Start(); - container->AddRightView(throbber); -} - -} // namespace - -//------------------------------------------------------------------------------ - -// A bubble which displays network info. -class NetworkStateListDetailedView::InfoBubble - : public views::BubbleDialogDelegateView { - public: - InfoBubble(views::View* anchor, - views::View* content, - NetworkStateListDetailedView* detailed_view) - : views::BubbleDialogDelegateView(anchor, views::BubbleBorder::TOP_RIGHT), - detailed_view_(detailed_view) { - set_can_activate(false); - SetLayoutManager(new views::FillLayout()); - AddChildView(content); - } - - ~InfoBubble() override { detailed_view_->OnInfoBubbleDestroyed(); } - - private: - // BubbleDialogDelegateView: - int GetDialogButtons() const override { return ui::DIALOG_BUTTON_NONE; } - - void OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, - views::Widget* widget) const override { - DCHECK(anchor_widget()); - // Place the bubble in the anchor widget's root window. - WmWindow::Get(anchor_widget()->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - widget, kShellWindowId_SettingBubbleContainer, params); - params->name = "NetworkStateListDetailedView::InfoBubble"; - } - - // Not owned. - NetworkStateListDetailedView* detailed_view_; - - DISALLOW_COPY_AND_ASSIGN(InfoBubble); -}; - -//------------------------------------------------------------------------------ - -const int kFadeIconMs = 500; - -// A throbber view that fades in/out when shown/hidden. -class ScanningThrobber : public ThrobberView { - public: - ScanningThrobber() { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetOpacity(1.0); - accessible_name_ = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_WIFI_SCANNING_MESSAGE); - } - ~ScanningThrobber() override {} - - // views::View - void SetVisible(bool visible) override { - layer()->GetAnimator()->StopAnimating(); // Stop any previous animation. - ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); - animation.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kFadeIconMs)); - layer()->SetOpacity(visible ? 1.0 : 0.0); - } - - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->SetName(accessible_name_); - node_data->role = ui::AX_ROLE_BUSY_INDICATOR; - } - - private: - base::string16 accessible_name_; - - DISALLOW_COPY_AND_ASSIGN(ScanningThrobber); -}; - -//------------------------------------------------------------------------------ - -// An image button showing the info icon similar to TrayPopupHeaderButton, -// but without the toggle properties, that fades in/out when shown/hidden. -class InfoIcon : public views::ImageButton { - public: - explicit InfoIcon(views::ButtonListener* listener) - : views::ImageButton(listener) { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - SetImage( - STATE_NORMAL, - bundle.GetImageNamed(IDR_AURA_UBER_TRAY_NETWORK_INFO).ToImageSkia()); - SetImage(STATE_HOVERED, - bundle.GetImageNamed(IDR_AURA_UBER_TRAY_NETWORK_INFO_HOVER) - .ToImageSkia()); - SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE); - SetAccessibleName( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_NETWORK_INFO)); - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetOpacity(1.0); - } - - ~InfoIcon() override {} - - // views::View - gfx::Size GetPreferredSize() const override { - return gfx::Size(kTrayPopupItemMinHeight, kTrayPopupItemMinHeight); - } - - void SetVisible(bool visible) override { - layer()->GetAnimator()->StopAnimating(); // Stop any previous animation. - ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); - animation.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kFadeIconMs)); - layer()->SetOpacity(visible ? 1.0 : 0.0); - } - - // views::CustomButton - void StateChanged(ButtonState old_state) override { - if (state() == STATE_HOVERED || state() == STATE_PRESSED) { - set_background(views::Background::CreateSolidBackground( - kTrayPopupHoverBackgroundColor)); - } else { - set_background(nullptr); - } - SchedulePaint(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(InfoIcon); -}; - -//------------------------------------------------------------------------------ - -// Special layout to overlap the scanning throbber and the info button. -class InfoThrobberLayout : public views::LayoutManager { - public: - InfoThrobberLayout() {} - ~InfoThrobberLayout() override {} - - // views::LayoutManager - void Layout(views::View* host) override { - gfx::Size max_size(GetMaxChildSize(host)); - // Center each child view within |max_size|. - for (int i = 0; i < host->child_count(); ++i) { - views::View* child = host->child_at(i); - if (!child->visible()) - continue; - gfx::Size child_size = child->GetPreferredSize(); - gfx::Point origin; - origin.set_x((max_size.width() - child_size.width()) / 2); - origin.set_y((max_size.height() - child_size.height()) / 2); - gfx::Rect bounds(origin, child_size); - bounds.Inset(-host->GetInsets()); - child->SetBoundsRect(bounds); - } - } - - gfx::Size GetPreferredSize(const views::View* host) const override { - gfx::Point origin; - gfx::Rect rect(origin, GetMaxChildSize(host)); - rect.Inset(-host->GetInsets()); - return rect.size(); - } - - private: - gfx::Size GetMaxChildSize(const views::View* host) const { - int width = 0, height = 0; - for (int i = 0; i < host->child_count(); ++i) { - const views::View* child = host->child_at(i); - if (!child->visible()) - continue; - gfx::Size child_size = child->GetPreferredSize(); - width = std::max(width, child_size.width()); - height = std::max(height, child_size.width()); - } - return gfx::Size(width, height); - } - - DISALLOW_COPY_AND_ASSIGN(InfoThrobberLayout); -}; - -//------------------------------------------------------------------------------ -// NetworkStateListDetailedView - -NetworkStateListDetailedView::NetworkStateListDetailedView( - SystemTrayItem* owner, - ListType list_type, - LoginStatus login) - : NetworkDetailedView(owner), - list_type_(list_type), - login_(login), - prev_wifi_scanning_state_(false), - info_icon_(nullptr), - info_button_md_(nullptr), - settings_button_md_(nullptr), - proxy_settings_button_md_(nullptr), - info_bubble_(nullptr), - scanning_throbber_(nullptr) { - if (list_type == LIST_TYPE_VPN) { - // Use a specialized class to list VPNs. - network_list_view_.reset(new VPNListView(this)); - } else { - // Use a common class to list any other network types. - // TODO(varkha): NetworkListViewMd is a temporary fork of NetworkListView. - // NetworkListView will go away when Material Design becomes default. - // See crbug.com/614453. - if (UseMd()) - network_list_view_.reset(new NetworkListViewMd(this)); - else - network_list_view_.reset(new NetworkListView(this)); - } -} - -NetworkStateListDetailedView::~NetworkStateListDetailedView() { - if (info_bubble_) - info_bubble_->GetWidget()->CloseNow(); -} - -void NetworkStateListDetailedView::Update() { - UpdateNetworkList(); - UpdateHeaderButtons(); - Layout(); -} - -// Overridden from NetworkDetailedView: - -void NetworkStateListDetailedView::Init() { - Reset(); - info_icon_ = nullptr; - info_button_md_ = nullptr; - settings_button_md_ = nullptr; - proxy_settings_button_md_ = nullptr; - scanning_throbber_ = nullptr; - - CreateScrollableList(); - if (!UseMd()) - CreateNetworkExtra(); - CreateTitleRow(list_type_ == ListType::LIST_TYPE_NETWORK - ? IDS_ASH_STATUS_TRAY_NETWORK - : IDS_ASH_STATUS_TRAY_VPN); - - network_list_view_->set_container(scroll_content()); - Update(); - - if (list_type_ != LIST_TYPE_VPN) - CallRequestScan(); -} - -NetworkDetailedView::DetailedViewType -NetworkStateListDetailedView::GetViewType() const { - return STATE_LIST_VIEW; -} - -void NetworkStateListDetailedView::HandleButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender == info_button_md_) { - ToggleInfoBubble(); - return; - } else if (sender == settings_button_md_) { - ShowSettings(); - } else if (sender == proxy_settings_button_md_) { - WmShell::Get()->system_tray_controller()->ShowProxySettings(); - } - - if (owner()->system_tray()) - owner()->system_tray()->CloseSystemBubble(); -} - -void NetworkStateListDetailedView::HandleViewClicked(views::View* view) { - // If the info bubble was visible, close it when some other item is clicked. - ResetInfoBubble(); - - if (login_ == LoginStatus::LOCKED) - return; - - std::string guid; - if (!network_list_view_->IsNetworkEntry(view, &guid)) - return; - - const NetworkState* network = - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - guid); - if (!network || network->IsConnectedState() || network->IsConnectingState()) { - WmShell::Get()->RecordUserMetricsAction( - list_type_ == LIST_TYPE_VPN - ? UMA_STATUS_AREA_SHOW_VPN_CONNECTION_DETAILS - : UMA_STATUS_AREA_SHOW_NETWORK_CONNECTION_DETAILS); - WmShell::Get()->system_tray_controller()->ShowNetworkSettings( - network ? network->guid() : std::string()); - } else { - WmShell::Get()->RecordUserMetricsAction( - list_type_ == LIST_TYPE_VPN - ? UMA_STATUS_AREA_CONNECT_TO_VPN - : UMA_STATUS_AREA_CONNECT_TO_CONFIGURED_NETWORK); - chromeos::NetworkConnect::Get()->ConnectToNetworkId(network->guid()); - } -} - -void NetworkStateListDetailedView::CreateExtraTitleRowButtons() { - if (login_ == LoginStatus::LOCKED) - return; - - DCHECK(!info_button_md_); - tri_view()->SetContainerVisible(TriView::Container::END, true); - - info_button_md_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuInfoIcon, - IDS_ASH_STATUS_TRAY_NETWORK_INFO); - tri_view()->AddView(TriView::Container::END, info_button_md_); - - if (login_ != LoginStatus::NOT_LOGGED_IN) { - DCHECK(!settings_button_md_); - settings_button_md_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, - IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS); - - // Allow the user to access settings only if user is logged in - // and showing settings is allowed. There are situations (supervised user - // creation flow) when session is started but UI flow continues within - // login UI, i.e., no browser window is yet avaialable. - if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings()) - settings_button_md_->SetEnabled(false); - - tri_view()->AddView(TriView::Container::END, settings_button_md_); - } else { - proxy_settings_button_md_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, - IDS_ASH_STATUS_TRAY_NETWORK_PROXY_SETTINGS); - tri_view()->AddView(TriView::Container::END, proxy_settings_button_md_); - } -} - -void NetworkStateListDetailedView::ShowSettings() { - WmShell::Get()->RecordUserMetricsAction( - list_type_ == LIST_TYPE_VPN ? UMA_STATUS_AREA_VPN_SETTINGS_OPENED - : UMA_STATUS_AREA_NETWORK_SETTINGS_OPENED); - WmShell::Get()->system_tray_controller()->ShowNetworkSettings(std::string()); -} - -void NetworkStateListDetailedView::CreateNetworkExtra() { - DCHECK(!UseMd()); -} - -void NetworkStateListDetailedView::SetScanningStateForThrobberView( - bool is_scanning) { - if (UseMd()) - return; - - // Hide the network info button if the device is scanning for Wi-Fi networks - // and display the WiFi scanning indicator. - info_icon_->SetVisible(!is_scanning); - scanning_throbber_->SetVisible(is_scanning); - // Set the element, network info button or the wifi scanning indicator, as - // focusable based on which one is active/visible. - // NOTE: As we do not want to lose focus from the network info throbber view, - // the order of below operation is important. - if (is_scanning) { - scanning_throbber_->SetFocusBehavior(FocusBehavior::ALWAYS); - info_icon_->SetFocusBehavior(FocusBehavior::NEVER); - } else { - info_icon_->SetFocusBehavior(FocusBehavior::ALWAYS); - scanning_throbber_->SetFocusBehavior(FocusBehavior::NEVER); - } - // If the Network Info view was in focus while this toggle operation was - // being performed then the focus should remain on this view. - if (info_icon_->HasFocus() && is_scanning) - scanning_throbber_->RequestFocus(); - else if (scanning_throbber_->HasFocus() && !is_scanning) - info_icon_->RequestFocus(); -} - -void NetworkStateListDetailedView::UpdateTechnologyButton( - TrayPopupHeaderButton* button, - const NetworkTypePattern& technology) { - NetworkStateHandler::TechnologyState state = - NetworkHandler::Get()->network_state_handler()->GetTechnologyState( - technology); - if (state == NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) { - button->SetVisible(false); - return; - } - button->SetVisible(true); - if (state == NetworkStateHandler::TECHNOLOGY_AVAILABLE) { - button->SetEnabled(true); - button->SetToggled(true); - } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLED) { - button->SetEnabled(true); - button->SetToggled(false); - } else if (state == NetworkStateHandler::TECHNOLOGY_ENABLING) { - button->SetEnabled(false); - button->SetToggled(false); - } else { // Initializing - button->SetEnabled(false); - button->SetToggled(true); - } -} - -void NetworkStateListDetailedView::UpdateNetworkList() { - network_list_view_->Update(); -} - -void NetworkStateListDetailedView::UpdateHeaderButtons() { - if (proxy_settings_button_md_) { - proxy_settings_button_md_->SetEnabled( - NetworkHandler::Get()->network_state_handler()->DefaultNetwork() != - nullptr); - } -} - -bool NetworkStateListDetailedView::OrderChild(views::View* view, int index) { - if (scroll_content()->child_at(index) != view) { - scroll_content()->ReorderChildView(view, index); - return true; - } - return false; -} - -void NetworkStateListDetailedView::CreateSettingsEntry() { - DCHECK(!UseMd()); -} - -void NetworkStateListDetailedView::ToggleInfoBubble() { - if (ResetInfoBubble()) - return; - - info_bubble_ = new InfoBubble(UseMd() ? info_button_md_ : info_icon_, - CreateNetworkInfoView(), this); - views::BubbleDialogDelegateView::CreateBubble(info_bubble_)->Show(); - info_bubble_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false); -} - -bool NetworkStateListDetailedView::ResetInfoBubble() { - if (!info_bubble_) - return false; - info_bubble_->GetWidget()->Close(); - info_bubble_ = nullptr; - return true; -} - -void NetworkStateListDetailedView::OnInfoBubbleDestroyed() { - info_bubble_ = nullptr; -} - -views::View* NetworkStateListDetailedView::CreateNetworkInfoView() { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - - std::string ip_address, ipv6_address; - const NetworkState* network = handler->DefaultNetwork(); - if (network) { - const DeviceState* device = handler->GetDeviceState(network->device_path()); - if (device) { - ip_address = device->GetIpAddressByType(shill::kTypeIPv4); - ipv6_address = device->GetIpAddressByType(shill::kTypeIPv6); - } - } - - views::View* container = new views::View; - container->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); - container->SetBorder(views::CreateEmptyBorder(0, 5, 0, 5)); - - std::string ethernet_address, wifi_address, vpn_address; - if (list_type_ != LIST_TYPE_VPN) { - ethernet_address = handler->FormattedHardwareAddressForType( - NetworkTypePattern::Ethernet()); - wifi_address = - handler->FormattedHardwareAddressForType(NetworkTypePattern::WiFi()); - } else { - vpn_address = - handler->FormattedHardwareAddressForType(NetworkTypePattern::VPN()); - } - - if (!ip_address.empty()) { - container->AddChildView(CreateInfoBubbleLine( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_IP), ip_address)); - } - if (!ipv6_address.empty()) { - container->AddChildView(CreateInfoBubbleLine( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_IPV6), ipv6_address)); - } - if (!ethernet_address.empty()) { - container->AddChildView(CreateInfoBubbleLine( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_ETHERNET), - ethernet_address)); - } - if (!wifi_address.empty()) { - container->AddChildView(CreateInfoBubbleLine( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_WIFI), wifi_address)); - } - if (!vpn_address.empty()) { - container->AddChildView(CreateInfoBubbleLine( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_VPN), vpn_address)); - } - - // Avoid an empty bubble in the unlikely event that there is no network - // information at all. - if (!container->has_children()) { - container->AddChildView(CreateInfoBubbleLabel( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_NO_NETWORKS))); - } - - return container; -} - -const gfx::ImageSkia* -NetworkStateListDetailedView::GetControlledByExtensionIcon() { - // Lazily load the icon from the resource bundle. - if (controlled_by_extension_icon_.IsEmpty()) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - controlled_by_extension_icon_ = - rb.GetImageNamed(IDR_AURA_UBER_TRAY_NETWORK_CONTROLLED); - } - DCHECK(!controlled_by_extension_icon_.IsEmpty()); - return controlled_by_extension_icon_.ToImageSkia(); -} - -views::View* NetworkStateListDetailedView::CreateControlledByExtensionView( - const NetworkInfo& info) { - NetworkingConfigDelegate* networking_config_delegate = - WmShell::Get()->system_tray_delegate()->GetNetworkingConfigDelegate(); - if (!networking_config_delegate) - return nullptr; - std::unique_ptr<const NetworkingConfigDelegate::ExtensionInfo> - extension_info = - networking_config_delegate->LookUpExtensionForNetwork(info.guid); - if (!extension_info) - return nullptr; - - // Get the tooltip text. - base::string16 tooltip_text = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_EXTENSION_CONTROLLED_WIFI, - base::UTF8ToUTF16(extension_info->extension_name)); - - views::ImageView* controlled_icon = - new FixedSizedImageView(kTrayPopupDetailsIconWidth, 0); - - controlled_icon->SetImage(GetControlledByExtensionIcon()); - controlled_icon->SetTooltipText(tooltip_text); - return controlled_icon; -} - -void NetworkStateListDetailedView::CallRequestScan() { - VLOG(1) << "Requesting Network Scan."; - NetworkHandler::Get()->network_state_handler()->RequestScan(); - // Periodically request a scan while this UI is open. - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::Bind(&NetworkStateListDetailedView::CallRequestScan, AsWeakPtr()), - base::TimeDelta::FromSeconds(kRequestScanDelaySeconds)); -} - -void NetworkStateListDetailedView::ToggleMobile() { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()); - chromeos::NetworkConnect::Get()->SetTechnologyEnabled( - NetworkTypePattern::Mobile(), !enabled); -} - -views::View* NetworkStateListDetailedView::CreateViewForNetwork( - const NetworkInfo& info) { - HoverHighlightView* container = new HoverHighlightView(this); - if (info.connected) - SetupConnectedItemMd(container, info.label, info.image); - else if (info.connecting) - SetupConnectingItemMd(container, info.label, info.image); - else - container->AddIconAndLabel(info.image, info.label, info.highlight); - container->set_tooltip(info.tooltip); - if (!UseMd()) { - container->SetBorder( - views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); - } - views::View* controlled_icon = CreateControlledByExtensionView(info); - if (controlled_icon) - container->AddChildView(controlled_icon); - return container; -} - -bool NetworkStateListDetailedView::IsViewHovered(views::View* view) { - return static_cast<HoverHighlightView*>(view)->hover(); -} - -NetworkTypePattern NetworkStateListDetailedView::GetNetworkTypePattern() const { - return list_type_ == LIST_TYPE_VPN ? NetworkTypePattern::VPN() - : NetworkTypePattern::NonVirtual(); -} - -void NetworkStateListDetailedView::UpdateViewForNetwork( - views::View* view, - const NetworkInfo& info) { - HoverHighlightView* container = static_cast<HoverHighlightView*>(view); - DCHECK(!container->has_children()); - if (info.connected) - SetupConnectedItemMd(container, info.label, info.image); - else if (info.connecting) - SetupConnectingItemMd(container, info.label, info.image); - else - container->AddIconAndLabel(info.image, info.label, info.highlight); - views::View* controlled_icon = CreateControlledByExtensionView(info); - container->set_tooltip(info.tooltip); - if (controlled_icon) - view->AddChildView(controlled_icon); -} - -views::Label* NetworkStateListDetailedView::CreateInfoLabel() { - views::Label* label = new views::Label(); - label->SetBorder(views::CreateEmptyBorder(kTrayPopupPaddingBetweenItems, - kTrayPopupPaddingHorizontal, - kTrayPopupPaddingBetweenItems, 0)); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - label->SetEnabledColor(SkColorSetARGB(192, 0, 0, 0)); - return label; -} - -void NetworkStateListDetailedView::OnNetworkEntryClicked(views::View* sender) { - HandleViewClicked(sender); -} - -void NetworkStateListDetailedView::OnOtherWifiClicked() { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_NETWORK_JOIN_OTHER_CLICKED); - WmShell::Get()->system_tray_controller()->ShowNetworkCreate(shill::kTypeWifi); -} - -void NetworkStateListDetailedView::RelayoutScrollList() { - scroller()->Layout(); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/network/network_state_list_detailed_view.h b/ash/system/network/network_state_list_detailed_view.h deleted file mode 100644 index 7533f7f..0000000 --- a/ash/system/network/network_state_list_detailed_view.h +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_NETWORK_STATE_LIST_DETAILED_VIEW_H_ -#define ASH_SYSTEM_NETWORK_NETWORK_STATE_LIST_DETAILED_VIEW_H_ - -#include <memory> -#include <string> - -#include "ash/common/login_status.h" -#include "ash/system/network/network_detailed_view.h" -#include "ash/system/network/network_list_delegate.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "ui/gfx/image/image.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/custom_button.h" - -namespace chromeos { -class NetworkTypePattern; -} - -namespace ash { -class NetworkListViewBase; -} - -namespace views { -class BubbleDialogDelegateView; -class ImageButton; -} - -namespace ash { -class SystemTrayItem; -class ThrobberView; -class TrayPopupHeaderButton; - -namespace tray { - -class NetworkStateListDetailedView - : public NetworkDetailedView, - public NetworkListDelegate, - public base::SupportsWeakPtr<NetworkStateListDetailedView> { - public: - enum ListType { LIST_TYPE_NETWORK, LIST_TYPE_VPN }; - - NetworkStateListDetailedView(SystemTrayItem* owner, - ListType list_type, - LoginStatus login); - ~NetworkStateListDetailedView() override; - - // Overridden from NetworkDetailedView: - void Init() override; - DetailedViewType GetViewType() const override; - void Update() override; - - private: - class InfoBubble; - - // TrayDetailsView: - void HandleViewClicked(views::View* view) override; - void HandleButtonPressed(views::Button* sender, - const ui::Event& event) override; - void CreateExtraTitleRowButtons() override; - - // Launches the WebUI settings in a browser and closes the system menu. - void ShowSettings(); - - // Create UI components. - void CreateHeaderEntry(); - void CreateNetworkExtra(); - - // Update UI components. - void UpdateTechnologyButton(TrayPopupHeaderButton* button, - const chromeos::NetworkTypePattern& technology); - void UpdateNetworkList(); - void UpdateHeaderButtons(); - - bool OrderChild(views::View* view, int index); - - // Adds a settings entry when logged in, and an entry for changing proxy - // settings otherwise. - void CreateSettingsEntry(); - - // Sets the visibility and focusability of Network Info Button and - // WiFi scanning indicator. This will hide Network info button and display - // the scanning indicator when |is_scanning| is true. - void SetScanningStateForThrobberView(bool is_scanning); - - // Create and manage the network info bubble. - void ToggleInfoBubble(); - bool ResetInfoBubble(); - void OnInfoBubbleDestroyed(); - views::View* CreateNetworkInfoView(); - const gfx::ImageSkia* GetControlledByExtensionIcon(); - - // Creates the view of an extra icon appearing next to the network name - // indicating that the network is controlled by an extension. If no extension - // is registered for this network, returns |nullptr|. - views::View* CreateControlledByExtensionView(const NetworkInfo& info); - - // Periodically request a network scan. - void CallRequestScan(); - - // Handle toggile mobile action - void ToggleMobile(); - - // NetworkListDelegate: - views::View* CreateViewForNetwork(const NetworkInfo& info) override; - bool IsViewHovered(views::View* view) override; - chromeos::NetworkTypePattern GetNetworkTypePattern() const override; - void UpdateViewForNetwork(views::View* view, - const NetworkInfo& info) override; - views::Label* CreateInfoLabel() override; - void OnNetworkEntryClicked(views::View* sender) override; - void OnOtherWifiClicked() override; - void RelayoutScrollList() override; - - // Type of list (all networks or vpn) - ListType list_type_; - - // Track login state. - LoginStatus login_; - - // Tracks the WiFi scanning state to help detect if the state has changed. Use - // NetworkHandler::GetScanningByType() if you require the current wifi - // scanning state. - bool prev_wifi_scanning_state_; - - // Not used for material design. - views::ImageButton* info_icon_; - - // Only used in material design. - views::CustomButton* info_button_md_; - views::CustomButton* settings_button_md_; - views::CustomButton* proxy_settings_button_md_; - - // A small bubble for displaying network info. - views::BubbleDialogDelegateView* info_bubble_; - - // WiFi scanning throbber. - ThrobberView* scanning_throbber_; - - gfx::Image controlled_by_extension_icon_; - - std::unique_ptr<NetworkListViewBase> network_list_view_; - - DISALLOW_COPY_AND_ASSIGN(NetworkStateListDetailedView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_NETWORK_STATE_LIST_DETAILED_VIEW_H_
diff --git a/ash/system/network/sms_observer.cc b/ash/system/network/sms_observer.cc deleted file mode 100644 index 622bc59e..0000000 --- a/ash/system/network/sms_observer.cc +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/sms_observer.h" - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "base/memory/ptr_util.h" -#include "base/strings/utf_string_conversions.h" -#include "chromeos/network/network_event_log.h" -#include "chromeos/network/network_handler.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/message_center/message_center.h" - -using chromeos::NetworkHandler; - -namespace ash { - -namespace { - -// Send the |message| to notification center to display to users. Note that each -// notification will be assigned with different |message_id| as notification id. -void ShowNotification(const base::DictionaryValue* message, - const std::string& message_text, - const std::string& message_number, - int message_id) { - message_center::MessageCenter* message_center = - message_center::MessageCenter::Get(); - if (!message_center) - return; - - const char kNotificationId[] = "chrome://network/sms"; - std::unique_ptr<message_center::Notification> notification; - - notification = base::MakeUnique<message_center::Notification>( - message_center::NOTIFICATION_TYPE_SIMPLE, - kNotificationId + std::to_string(message_id), - base::ASCIIToUTF16(message_number), base::ASCIIToUTF16(message_text), - gfx::Image(gfx::CreateVectorIcon( - ash::kSystemMenuSmsIcon, ash::kMenuIconSize, ash::kMenuIconColor)), - base::string16(), GURL(), - message_center::NotifierId(message_center::NotifierId::APPLICATION, - ash::system_notifier::kNotifierSms), - message_center::RichNotificationData(), nullptr); - message_center->AddNotification(std::move(notification)); -} - -} // namespace - -SmsObserver::SmsObserver() { - // TODO(armansito): SMS could be a special case for cellular that requires a - // user (perhaps the owner) to be logged in. If that is the case, then an - // additional check should be done before subscribing for SMS notifications. - if (NetworkHandler::IsInitialized()) - NetworkHandler::Get()->network_sms_handler()->AddObserver(this); -} - -SmsObserver::~SmsObserver() { - if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_sms_handler()->RemoveObserver(this); - } -} - -void SmsObserver::MessageReceived(const base::DictionaryValue& message) { - std::string message_text; - if (!message.GetStringWithoutPathExpansion( - chromeos::NetworkSmsHandler::kTextKey, &message_text)) { - NET_LOG(ERROR) << "SMS message contains no content."; - return; - } - // TODO(armansito): A message might be due to a special "Message Waiting" - // state that the message is in. Once SMS handling moves to shill, such - // messages should be filtered there so that this check becomes unnecessary. - if (message_text.empty()) { - NET_LOG(DEBUG) << "SMS has empty content text. Ignoring."; - return; - } - std::string message_number; - if (!message.GetStringWithoutPathExpansion( - chromeos::NetworkSmsHandler::kNumberKey, &message_number)) { - NET_LOG(DEBUG) << "SMS contains no number. Ignoring."; - return; - } - - NET_LOG(DEBUG) << "Received SMS from: " << message_number - << " with text: " << message_text; - message_id_++; - ShowNotification(&message, message_text, message_number, message_id_); -} - -} // namespace ash
diff --git a/ash/system/network/sms_observer.h b/ash/system/network/sms_observer.h deleted file mode 100644 index b304005..0000000 --- a/ash/system/network/sms_observer.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_SMS_OBSERVER_H_ -#define ASH_SYSTEM_NETWORK_SMS_OBSERVER_H_ - -#include "chromeos/network/network_sms_handler.h" - -namespace base { -class DictionaryValue; -} - -namespace ash { - -// SmsObserver is called when a new sms message is received. Then it shows the -// sms message to the user in the notification center. -class SmsObserver : public chromeos::NetworkSmsHandler::Observer { - public: - SmsObserver(); - ~SmsObserver() override; - - // chromeos::NetworkSmsHandler::Observer: - void MessageReceived(const base::DictionaryValue& message) override; - - private: - // Used to create notification identifier. - uint32_t message_id_ = 0; - - DISALLOW_COPY_AND_ASSIGN(SmsObserver); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_SMS_OBSERVER_H_
diff --git a/ash/system/network/sms_observer_unittest.cc b/ash/system/network/sms_observer_unittest.cc deleted file mode 100644 index a22172d..0000000 --- a/ash/system/network/sms_observer_unittest.cc +++ /dev/null
@@ -1,136 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/sms_observer.h" - -#include "ash/public/interfaces/vpn_list.mojom.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "base/macros.h" -#include "base/strings/utf_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_list.h" - -using message_center::MessageCenter; - -namespace ash { - -namespace { - -std::unique_ptr<base::DictionaryValue> CreateMessage( - const char* kDefaultMessage = "FakeSMSClient: Test Message.", - const char* kDefaultNumber = "000-000-0000", - const char* kDefaultTimestamp = "Fri Jun 8 13:26:04 EDT 2016") { - std::unique_ptr<base::DictionaryValue> sms = - base::MakeUnique<base::DictionaryValue>(); - if (kDefaultNumber) - sms->SetString("number", kDefaultNumber); - if (kDefaultMessage) - sms->SetString("text", kDefaultMessage); - if (kDefaultTimestamp) - sms->SetString("timestamp", kDefaultMessage); - return sms; -} - -} // namespace - -class SmsObserverTest : public test::AshTestBase { - public: - SmsObserverTest() {} - ~SmsObserverTest() override {} - - SmsObserver* GetSmsObserver() { - return Shell::GetInstance()->sms_observer_.get(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(SmsObserverTest); -}; - -// Verify if notification is received after receiving a sms message with -// number and content. -TEST_F(SmsObserverTest, SendTextMessage) { - SmsObserver* sms_observer = GetSmsObserver(); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); - - std::unique_ptr<base::DictionaryValue> sms(CreateMessage()); - sms_observer->MessageReceived(*sms); - - const message_center::NotificationList::Notifications notifications = - MessageCenter::Get()->GetVisibleNotifications(); - EXPECT_EQ(1u, notifications.size()); - - EXPECT_EQ(base::ASCIIToUTF16("000-000-0000"), - (*notifications.begin())->title()); - EXPECT_EQ(base::ASCIIToUTF16("FakeSMSClient: Test Message."), - (*notifications.begin())->message()); - MessageCenter::Get()->RemoveAllNotifications(false /* by_user */, - MessageCenter::RemoveType::ALL); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); -} - -// Verify if no notification is received if phone number is missing in sms -// message. -TEST_F(SmsObserverTest, TextMessageMissingNumber) { - SmsObserver* sms_observer = GetSmsObserver(); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); - - std::unique_ptr<base::DictionaryValue> sms( - CreateMessage("FakeSMSClient: Test Message.", nullptr)); - sms_observer->MessageReceived(*sms); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); -} - -// Verify if no notification is received if text body is empty in sms message. -TEST_F(SmsObserverTest, TextMessageEmptyText) { - SmsObserver* sms_observer = GetSmsObserver(); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); - - std::unique_ptr<base::DictionaryValue> sms(CreateMessage("")); - sms_observer->MessageReceived(*sms); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); -} - -// Verify if no notification is received if the text is missing in sms message. -TEST_F(SmsObserverTest, TextMessageMissingText) { - SmsObserver* sms_observer = GetSmsObserver(); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); - std::unique_ptr<base::DictionaryValue> sms(CreateMessage(nullptr)); - sms_observer->MessageReceived(*sms); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); -} - -// Verify if 2 notification received after receiving 2 sms messages from the -// same number. -TEST_F(SmsObserverTest, MultipleTextMessages) { - SmsObserver* sms_observer = GetSmsObserver(); - EXPECT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size()); - - std::unique_ptr<base::DictionaryValue> sms(CreateMessage("first message")); - sms_observer->MessageReceived(*sms); - std::unique_ptr<base::DictionaryValue> sms2(CreateMessage("second message")); - sms_observer->MessageReceived(*sms2); - const message_center::NotificationList::Notifications notifications = - MessageCenter::Get()->GetVisibleNotifications(); - EXPECT_EQ(2u, notifications.size()); - - for (message_center::Notification* iter : notifications) { - if (iter->id().find("chrome://network/sms1") != std::string::npos) { - EXPECT_EQ(base::ASCIIToUTF16("000-000-0000"), iter->title()); - EXPECT_EQ(base::ASCIIToUTF16("first message"), iter->message()); - } else if (iter->id().find("chrome://network/sms2") != std::string::npos) { - EXPECT_EQ(base::ASCIIToUTF16("000-000-0000"), iter->title()); - EXPECT_EQ(base::ASCIIToUTF16("second message"), iter->message()); - } else { - ASSERT_TRUE(false); - } - } -} - -} // namespace ash
diff --git a/ash/system/network/tray_network.cc b/ash/system/network/tray_network.cc deleted file mode 100644 index e04d0590..0000000 --- a/ash/system/network/tray_network.cc +++ /dev/null
@@ -1,341 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/tray_network.h" - -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_icon_animation_observer.h" -#include "ash/system/network/network_state_list_detailed_view.h" -#include "ash/system/network/tray_network_state_observer.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_more.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_utils.h" -#include "base/command_line.h" -#include "base/strings/utf_string_conversions.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "third_party/cros_system_api/dbus/service_constants.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/link.h" -#include "ui/views/controls/link_listener.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/widget/widget.h" - -using chromeos::NetworkHandler; -using chromeos::NetworkState; -using chromeos::NetworkStateHandler; -using chromeos::NetworkTypePattern; - -namespace ash { -namespace tray { - -namespace { - -// Returns the connected, non-virtual (aka VPN), network. -const NetworkState* GetConnectedNetwork() { - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - return handler->ConnectedNetworkByType(NetworkTypePattern::NonVirtual()); -} - -} // namespace - -class NetworkTrayView : public TrayItemView, - public network_icon::AnimationObserver { - public: - explicit NetworkTrayView(TrayNetwork* network_tray) - : TrayItemView(network_tray) { - CreateImageView(); - UpdateNetworkStateHandlerIcon(); - } - - ~NetworkTrayView() override { - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - } - - const char* GetClassName() const override { return "NetworkTrayView"; } - - void UpdateNetworkStateHandlerIcon() { - gfx::ImageSkia image; - base::string16 name; - bool animating = false; - network_icon::GetDefaultNetworkImageAndLabel(network_icon::ICON_TYPE_TRAY, - &image, &name, &animating); - bool show_in_tray = !image.isNull(); - UpdateIcon(show_in_tray, image); - if (animating) - network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); - else - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - // Update accessibility. - const NetworkState* connected_network = GetConnectedNetwork(); - if (connected_network) { - UpdateConnectionStatus(base::UTF8ToUTF16(connected_network->name()), - true); - } else { - UpdateConnectionStatus(base::string16(), false); - } - } - - // views::View: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->SetName(connection_status_string_); - node_data->role = ui::AX_ROLE_BUTTON; - } - - // network_icon::AnimationObserver: - void NetworkIconChanged() override { UpdateNetworkStateHandlerIcon(); } - - private: - // Updates connection status and notifies accessibility event when necessary. - void UpdateConnectionStatus(const base::string16& network_name, - bool connected) { - base::string16 new_connection_status_string; - if (connected) { - new_connection_status_string = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NETWORK_CONNECTED, network_name); - } - if (new_connection_status_string != connection_status_string_) { - connection_status_string_ = new_connection_status_string; - if (!connection_status_string_.empty()) - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); - } - } - - void UpdateIcon(bool tray_icon_visible, const gfx::ImageSkia& image) { - image_view()->SetImage(image); - SetVisible(tray_icon_visible); - SchedulePaint(); - } - - base::string16 connection_status_string_; - - DISALLOW_COPY_AND_ASSIGN(NetworkTrayView); -}; - -class NetworkDefaultView : public TrayItemMore, - public network_icon::AnimationObserver { - public: - explicit NetworkDefaultView(TrayNetwork* network_tray) - : TrayItemMore(network_tray) { - Update(); - } - - ~NetworkDefaultView() override { - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - } - - void Update() { - gfx::ImageSkia image; - base::string16 label; - bool animating = false; - // TODO(bruthig): Update the image to use the proper color. See - // https://crbug.com/632027. - network_icon::GetDefaultNetworkImageAndLabel( - network_icon::ICON_TYPE_DEFAULT_VIEW, &image, &label, &animating); - if (animating) - network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); - else - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - SetImage(image); - SetLabel(label); - SetAccessibleName(label); - UpdateStyle(); - } - - // network_icon::AnimationObserver - void NetworkIconChanged() override { Update(); } - - protected: - // TrayItemMore: - std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const override { - std::unique_ptr<TrayPopupItemStyle> style = - TrayItemMore::HandleCreateStyle(); - style->set_color_style(GetConnectedNetwork() != nullptr - ? TrayPopupItemStyle::ColorStyle::ACTIVE - : TrayPopupItemStyle::ColorStyle::INACTIVE); - return style; - } - - private: - DISALLOW_COPY_AND_ASSIGN(NetworkDefaultView); -}; - -class NetworkWifiDetailedView : public NetworkDetailedView { - public: - explicit NetworkWifiDetailedView(SystemTrayItem* owner) - : NetworkDetailedView(owner) { - SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, - kTrayPopupPaddingHorizontal, 10, - kTrayPopupPaddingBetweenItems)); - image_view_ = new views::ImageView; - AddChildView(image_view_); - - label_view_ = new views::Label(); - label_view_->SetMultiLine(true); - label_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - AddChildView(label_view_); - - Update(); - } - - ~NetworkWifiDetailedView() override {} - - // Overridden from NetworkDetailedView: - - void Init() override {} - - NetworkDetailedView::DetailedViewType GetViewType() const override { - return NetworkDetailedView::WIFI_VIEW; - } - - void Layout() override { - // Center both views vertically. - views::View::Layout(); - image_view_->SetY((height() - image_view_->GetPreferredSize().height()) / - 2); - label_view_->SetY((height() - label_view_->GetPreferredSize().height()) / - 2); - } - - void Update() override { - bool wifi_enabled = - NetworkHandler::Get()->network_state_handler()->IsTechnologyEnabled( - NetworkTypePattern::WiFi()); - const int image_id = wifi_enabled ? IDR_AURA_UBER_TRAY_WIFI_ENABLED - : IDR_AURA_UBER_TRAY_WIFI_DISABLED; - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - image_view_->SetImage(bundle.GetImageNamed(image_id).ToImageSkia()); - - const int string_id = wifi_enabled - ? IDS_ASH_STATUS_TRAY_NETWORK_WIFI_ENABLED - : IDS_ASH_STATUS_TRAY_NETWORK_WIFI_DISABLED; - label_view_->SetText(bundle.GetLocalizedString(string_id)); - label_view_->SizeToFit( - kTrayPopupMinWidth - kTrayPopupPaddingHorizontal * 2 - - kTrayPopupPaddingBetweenItems - kTrayPopupDetailsIconWidth); - } - - private: - views::ImageView* image_view_; - views::Label* label_view_; - - DISALLOW_COPY_AND_ASSIGN(NetworkWifiDetailedView); -}; - -} // namespace tray - -TrayNetwork::TrayNetwork(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_NETWORK), - tray_(NULL), - default_(NULL), - detailed_(NULL), - request_wifi_view_(false) { - network_state_observer_.reset(new TrayNetworkStateObserver(this)); - SystemTrayNotifier* notifier = WmShell::Get()->system_tray_notifier(); - notifier->AddNetworkObserver(this); - notifier->AddNetworkPortalDetectorObserver(this); -} - -TrayNetwork::~TrayNetwork() { - SystemTrayNotifier* notifier = WmShell::Get()->system_tray_notifier(); - notifier->RemoveNetworkObserver(this); - notifier->RemoveNetworkPortalDetectorObserver(this); -} - -views::View* TrayNetwork::CreateTrayView(LoginStatus status) { - CHECK(tray_ == NULL); - if (!chromeos::NetworkHandler::IsInitialized()) - return NULL; - tray_ = new tray::NetworkTrayView(this); - return tray_; -} - -views::View* TrayNetwork::CreateDefaultView(LoginStatus status) { - CHECK(default_ == NULL); - if (!chromeos::NetworkHandler::IsInitialized()) - return NULL; - CHECK(tray_ != NULL); - default_ = new tray::NetworkDefaultView(this); - default_->SetEnabled(status != LoginStatus::LOCKED); - return default_; -} - -views::View* TrayNetwork::CreateDetailedView(LoginStatus status) { - CHECK(detailed_ == NULL); - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DETAILED_NETWORK_VIEW); - if (!chromeos::NetworkHandler::IsInitialized()) - return NULL; - if (request_wifi_view_) { - detailed_ = new tray::NetworkWifiDetailedView(this); - request_wifi_view_ = false; - } else { - detailed_ = new tray::NetworkStateListDetailedView( - this, tray::NetworkStateListDetailedView::LIST_TYPE_NETWORK, status); - detailed_->Init(); - } - return detailed_; -} - -void TrayNetwork::DestroyTrayView() { - tray_ = NULL; -} - -void TrayNetwork::DestroyDefaultView() { - default_ = NULL; -} - -void TrayNetwork::DestroyDetailedView() { - detailed_ = NULL; -} - -void TrayNetwork::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayNetwork::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - if (tray_) - SetTrayImageItemBorder(tray_, alignment); -} - -void TrayNetwork::RequestToggleWifi() { - // This will always be triggered by a user action (e.g. keyboard shortcut) - if (!detailed_ || - detailed_->GetViewType() == tray::NetworkDetailedView::WIFI_VIEW) { - request_wifi_view_ = true; - PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); - } - NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); - bool enabled = handler->IsTechnologyEnabled(NetworkTypePattern::WiFi()); - WmShell::Get()->RecordUserMetricsAction( - enabled ? UMA_STATUS_AREA_DISABLE_WIFI : UMA_STATUS_AREA_ENABLE_WIFI); - handler->SetTechnologyEnabled(NetworkTypePattern::WiFi(), !enabled, - chromeos::network_handler::ErrorCallback()); -} - -void TrayNetwork::OnCaptivePortalDetected(const std::string& /* guid */) { - NetworkStateChanged(); -} - -void TrayNetwork::NetworkStateChanged() { - if (tray_) - tray_->UpdateNetworkStateHandlerIcon(); - if (default_) - default_->Update(); - if (detailed_) - detailed_->Update(); -} - -} // namespace ash
diff --git a/ash/system/network/tray_network.h b/ash/system/network/tray_network.h deleted file mode 100644 index 2d7927b..0000000 --- a/ash/system/network/tray_network.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_TRAY_NETWORK_H_ -#define ASH_SYSTEM_NETWORK_TRAY_NETWORK_H_ - -#include <memory> -#include <set> - -#include "ash/system/network/network_observer.h" -#include "ash/system/network/network_portal_detector_observer.h" -#include "ash/system/network/tray_network_state_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" -#include "base/time/time.h" - -namespace ash { -namespace tray { -class NetworkDefaultView; -class NetworkDetailedView; -class NetworkTrayView; -} - -class TrayNetwork : public SystemTrayItem, - public NetworkObserver, - public NetworkPortalDetectorObserver, - public TrayNetworkStateObserver::Delegate { - public: - explicit TrayNetwork(SystemTray* system_tray); - ~TrayNetwork() override; - - tray::NetworkDetailedView* detailed() { return detailed_; } - - // SystemTrayItem - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // NetworkObserver - void RequestToggleWifi() override; - - // NetworkPortalDetectorObserver - void OnCaptivePortalDetected(const std::string& guid) override; - - // TrayNetworkStateObserver::Delegate - void NetworkStateChanged() override; - - private: - tray::NetworkTrayView* tray_; - tray::NetworkDefaultView* default_; - tray::NetworkDetailedView* detailed_; - bool request_wifi_view_; - std::unique_ptr<TrayNetworkStateObserver> network_state_observer_; - - DISALLOW_COPY_AND_ASSIGN(TrayNetwork); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_TRAY_NETWORK_H_
diff --git a/ash/system/network/tray_network_state_observer.cc b/ash/system/network/tray_network_state_observer.cc deleted file mode 100644 index 60e05c4..0000000 --- a/ash/system/network/tray_network_state_observer.cc +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/tray_network_state_observer.h" - -#include <set> -#include <string> - -#include "ash/system/network/network_icon.h" -#include "ash/system/tray/system_tray.h" -#include "base/location.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "third_party/cros_system_api/dbus/service_constants.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" - -using chromeos::NetworkHandler; - -namespace { - -const int kUpdateFrequencyMs = 1000; - -} // namespace - -namespace ash { - -TrayNetworkStateObserver::TrayNetworkStateObserver(Delegate* delegate) - : delegate_(delegate), - purge_icons_(false), - update_frequency_(kUpdateFrequencyMs) { - if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() != - ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION) { - update_frequency_ = 0; // Send updates immediately for tests. - } - if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_state_handler()->AddObserver(this, - FROM_HERE); - } -} - -TrayNetworkStateObserver::~TrayNetworkStateObserver() { - if (NetworkHandler::IsInitialized()) { - NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, - FROM_HERE); - } -} - -void TrayNetworkStateObserver::NetworkListChanged() { - purge_icons_ = true; - SignalUpdate(); -} - -void TrayNetworkStateObserver::DeviceListChanged() { - SignalUpdate(); -} - -// Any change to the Default (primary connected) network, including Strength -// changes, should trigger a NetworkStateChanged update. -void TrayNetworkStateObserver::DefaultNetworkChanged( - const chromeos::NetworkState* network) { - SignalUpdate(); -} - -// Any change to the Connection State should trigger a NetworkStateChanged -// update. This is important when both a VPN and a physical network are -// connected. -void TrayNetworkStateObserver::NetworkConnectionStateChanged( - const chromeos::NetworkState* network) { - SignalUpdate(); -} - -// This tracks Strength and other property changes for all networks. It will -// be called in addition to NetworkConnectionStateChanged for connection state -// changes. -void TrayNetworkStateObserver::NetworkPropertiesUpdated( - const chromeos::NetworkState* network) { - SignalUpdate(); -} - -void TrayNetworkStateObserver::SignalUpdate() { - if (timer_.IsRunning()) - return; - timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(update_frequency_), - this, &TrayNetworkStateObserver::SendNetworkStateChanged); -} - -void TrayNetworkStateObserver::SendNetworkStateChanged() { - delegate_->NetworkStateChanged(); - if (purge_icons_) { - network_icon::PurgeNetworkIconCache(); - purge_icons_ = false; - } -} - -} // namespace ash
diff --git a/ash/system/network/tray_network_state_observer.h b/ash/system/network/tray_network_state_observer.h deleted file mode 100644 index 9e6e8ed..0000000 --- a/ash/system/network/tray_network_state_observer.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_TRAY_NETWORK_STATE_OBSERVER_H_ -#define ASH_SYSTEM_NETWORK_TRAY_NETWORK_STATE_OBSERVER_H_ - -#include "base/macros.h" -#include "base/timer/timer.h" -#include "chromeos/network/network_state_handler_observer.h" - -namespace ash { - -class TrayNetworkStateObserver : public chromeos::NetworkStateHandlerObserver { - public: - class Delegate { - public: - // Called when any interesting network changes occur. The frequency of this - // event is limited to kUpdateFrequencyMs. - virtual void NetworkStateChanged() = 0; - - protected: - virtual ~Delegate() {} - }; - - explicit TrayNetworkStateObserver(Delegate* delegate); - - ~TrayNetworkStateObserver() override; - - // NetworkStateHandlerObserver overrides. - void NetworkListChanged() override; - void DeviceListChanged() override; - void DefaultNetworkChanged(const chromeos::NetworkState* network) override; - void NetworkConnectionStateChanged( - const chromeos::NetworkState* network) override; - void NetworkPropertiesUpdated(const chromeos::NetworkState* network) override; - - private: - void SignalUpdate(); - void SendNetworkStateChanged(); - - // Unowned Delegate pointer (must outlive this instance). - Delegate* delegate_; - - // Set to true when we should purge stale icons in the cache. - bool purge_icons_; - - // Frequency at which to push NetworkStateChanged updates. This avoids - // unnecessarily frequent UI updates (which can be expensive). We set this - // to 0 for tests to eliminate timing variance. - int update_frequency_; - - // Timer used to limit the frequency of NetworkStateChanged updates. - base::OneShotTimer timer_; - - DISALLOW_COPY_AND_ASSIGN(TrayNetworkStateObserver); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_TRAY_NETWORK_STATE_OBSERVER_H_
diff --git a/ash/system/network/tray_vpn.cc b/ash/system/network/tray_vpn.cc deleted file mode 100644 index bff5b0b..0000000 --- a/ash/system/network/tray_vpn.cc +++ /dev/null
@@ -1,206 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/tray_vpn.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_icon_animation_observer.h" -#include "ash/system/network/network_state_list_detailed_view.h" -#include "ash/system/network/vpn_list.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_more.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_state_handler.h" -#include "third_party/cros_system_api/dbus/service_constants.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" - -using chromeos::NetworkHandler; -using chromeos::NetworkState; -using chromeos::NetworkStateHandler; -using chromeos::NetworkTypePattern; - -namespace ash { -namespace tray { - -class VpnDefaultView : public TrayItemMore, - public network_icon::AnimationObserver { - public: - explicit VpnDefaultView(SystemTrayItem* owner) : TrayItemMore(owner) {} - - ~VpnDefaultView() override { - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - } - - static bool ShouldShow() { - // Show the VPN entry in the ash tray bubble if at least one third-party VPN - // provider is installed. - if (WmShell::Get()->vpn_list()->HaveThirdPartyVPNProviders()) - return true; - - // Also show the VPN entry if at least one VPN network is configured. - NetworkStateHandler* const handler = - NetworkHandler::Get()->network_state_handler(); - if (handler->FirstNetworkByType(NetworkTypePattern::VPN())) - return true; - return false; - } - - void Update() { - gfx::ImageSkia image; - base::string16 label; - bool animating = false; - GetNetworkStateHandlerImageAndLabel(&image, &label, &animating); - if (animating) - network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); - else - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - SetImage(image); - SetLabel(label); - SetAccessibleName(label); - } - - // network_icon::AnimationObserver - void NetworkIconChanged() override { Update(); } - - protected: - // TrayItemMore: - std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const override { - std::unique_ptr<TrayPopupItemStyle> style = - TrayItemMore::HandleCreateStyle(); - style->set_color_style( - !IsVpnEnabled() - ? TrayPopupItemStyle::ColorStyle::DISABLED - : IsVpnConnected() ? TrayPopupItemStyle::ColorStyle::ACTIVE - : TrayPopupItemStyle::ColorStyle::INACTIVE); - return style; - } - - void UpdateStyle() override { - TrayItemMore::UpdateStyle(); - Update(); - } - - private: - bool IsVpnEnabled() const { - NetworkStateHandler* handler = - NetworkHandler::Get()->network_state_handler(); - return handler->FirstNetworkByType(NetworkTypePattern::VPN()); - } - - bool IsVpnConnected() const { - NetworkStateHandler* handler = - NetworkHandler::Get()->network_state_handler(); - const NetworkState* vpn = - handler->FirstNetworkByType(NetworkTypePattern::VPN()); - return IsVpnEnabled() && - (vpn->IsConnectedState() || vpn->IsConnectingState()); - } - - void GetNetworkStateHandlerImageAndLabel(gfx::ImageSkia* image, - base::string16* label, - bool* animating) { - NetworkStateHandler* handler = - NetworkHandler::Get()->network_state_handler(); - const NetworkState* vpn = - handler->FirstNetworkByType(NetworkTypePattern::VPN()); - *image = gfx::CreateVectorIcon( - kNetworkVpnIcon, TrayPopupItemStyle::GetIconColor( - vpn && vpn->IsConnectedState() - ? TrayPopupItemStyle::ColorStyle::ACTIVE - : TrayPopupItemStyle::ColorStyle::INACTIVE)); - if (!IsVpnConnected()) { - if (label) { - *label = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECTED); - } - *animating = false; - return; - } - *animating = vpn->IsConnectingState(); - if (label) { - *label = network_icon::GetLabelForNetwork( - vpn, network_icon::ICON_TYPE_DEFAULT_VIEW); - } - } - - DISALLOW_COPY_AND_ASSIGN(VpnDefaultView); -}; - -} // namespace tray - -TrayVPN::TrayVPN(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_VPN), - default_(nullptr), - detailed_(nullptr) { - network_state_observer_.reset(new TrayNetworkStateObserver(this)); -} - -TrayVPN::~TrayVPN() {} - -views::View* TrayVPN::CreateTrayView(LoginStatus status) { - return NULL; -} - -views::View* TrayVPN::CreateDefaultView(LoginStatus status) { - CHECK(default_ == NULL); - if (!chromeos::NetworkHandler::IsInitialized()) - return NULL; - if (status == LoginStatus::NOT_LOGGED_IN) - return NULL; - if (!tray::VpnDefaultView::ShouldShow()) - return NULL; - - const bool is_in_secondary_login_screen = - WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); - - default_ = new tray::VpnDefaultView(this); - default_->SetEnabled(status != LoginStatus::LOCKED && - !is_in_secondary_login_screen); - - return default_; -} - -views::View* TrayVPN::CreateDetailedView(LoginStatus status) { - CHECK(detailed_ == NULL); - if (!chromeos::NetworkHandler::IsInitialized()) - return NULL; - - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_DETAILED_VPN_VIEW); - detailed_ = new tray::NetworkStateListDetailedView( - this, tray::NetworkStateListDetailedView::LIST_TYPE_VPN, status); - detailed_->Init(); - return detailed_; -} - -void TrayVPN::DestroyTrayView() {} - -void TrayVPN::DestroyDefaultView() { - default_ = NULL; -} - -void TrayVPN::DestroyDetailedView() { - detailed_ = NULL; -} - -void TrayVPN::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayVPN::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {} - -void TrayVPN::NetworkStateChanged() { - if (default_) - default_->Update(); - if (detailed_) - detailed_->Update(); -} - -} // namespace ash
diff --git a/ash/system/network/tray_vpn.h b/ash/system/network/tray_vpn.h deleted file mode 100644 index 93d361d..0000000 --- a/ash/system/network/tray_vpn.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_TRAY_VPN_H_ -#define ASH_SYSTEM_NETWORK_TRAY_VPN_H_ - -#include <memory> - -#include "ash/system/network/tray_network_state_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { -class TrayNetworkStateObserver; - -namespace tray { -class NetworkDetailedView; -class VpnDefaultView; -} - -class TrayVPN : public SystemTrayItem, - public TrayNetworkStateObserver::Delegate { - public: - explicit TrayVPN(SystemTray* system_tray); - ~TrayVPN() override; - - // SystemTrayItem - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // TrayNetworkStateObserver::Delegate - void NetworkStateChanged() override; - - private: - tray::VpnDefaultView* default_; - tray::NetworkDetailedView* detailed_; - std::unique_ptr<TrayNetworkStateObserver> network_state_observer_; - - DISALLOW_COPY_AND_ASSIGN(TrayVPN); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_TRAY_VPN_H_
diff --git a/ash/system/network/vpn_list.cc b/ash/system/network/vpn_list.cc deleted file mode 100644 index f8d5150..0000000 --- a/ash/system/network/vpn_list.cc +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/vpn_list.h" - -#include <utility> - -#include "base/logging.h" - -namespace ash { - -VPNProvider::VPNProvider() : third_party(false) {} - -VPNProvider::VPNProvider(const std::string& extension_id, - const std::string& third_party_provider_name) - : third_party(true), - extension_id(extension_id), - third_party_provider_name(third_party_provider_name) { - DCHECK(!extension_id.empty()); - DCHECK(!third_party_provider_name.empty()); -} - -bool VPNProvider::operator==(const VPNProvider& other) const { - return third_party == other.third_party && - extension_id == other.extension_id && - third_party_provider_name == other.third_party_provider_name; -} - -VpnList::Observer::~Observer() {} - -VpnList::VpnList() { - AddBuiltInProvider(); -} - -VpnList::~VpnList() {} - -bool VpnList::HaveThirdPartyVPNProviders() const { - for (const VPNProvider& provider : vpn_providers_) { - if (provider.third_party) - return true; - } - return false; -} - -void VpnList::AddObserver(Observer* observer) { - observer_list_.AddObserver(observer); -} - -void VpnList::RemoveObserver(Observer* observer) { - observer_list_.RemoveObserver(observer); -} - -void VpnList::BindRequest(mojom::VpnListRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void VpnList::SetThirdPartyVpnProviders( - std::vector<mojom::ThirdPartyVpnProviderPtr> providers) { - vpn_providers_.clear(); - vpn_providers_.reserve(providers.size() + 1); - // Add the OpenVPN provider. - AddBuiltInProvider(); - // Append the extension-backed providers. - for (const auto& provider : providers) { - vpn_providers_.push_back( - VPNProvider(provider->extension_id, provider->name)); - } - NotifyObservers(); -} - -void VpnList::NotifyObservers() { - for (auto& observer : observer_list_) - observer.OnVPNProvidersChanged(); -} - -void VpnList::AddBuiltInProvider() { - // The VPNProvider() constructor generates the built-in provider and has no - // extension ID. - vpn_providers_.push_back(VPNProvider()); -} - -} // namespace ash
diff --git a/ash/system/network/vpn_list.h b/ash/system/network/vpn_list.h deleted file mode 100644 index 8c2a2fa..0000000 --- a/ash/system/network/vpn_list.h +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_VPN_LIST_H_ -#define ASH_SYSTEM_NETWORK_VPN_LIST_H_ - -#include <string> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/public/interfaces/vpn_list.mojom.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "mojo/public/cpp/bindings/binding_set.h" - -namespace ash { - -// Describes a VPN provider. -struct ASH_EXPORT VPNProvider { - // Constructs the built-in VPN provider. - VPNProvider(); - - // Constructs a third-party VPN provider. - VPNProvider(const std::string& extension_id, - const std::string& third_party_provider_name); - - bool operator==(const VPNProvider& other) const; - - // Whether this key represents a built-in or third-party VPN provider. - bool third_party; - - // ID of the extension that implements this provider. Used for third-party - // VPN providers only. - std::string extension_id; - - // Human-readable name if |third_party| is true, otherwise empty. - std::string third_party_provider_name; -}; - -// This delegate provides UI code in ash, e.g. |VPNListView|, with access to the -// list of VPN providers enabled in the primary user's profile. The delegate -// furthermore allows the UI code to request that a VPN provider show its "add -// network" dialog. -class ASH_EXPORT VpnList : public mojom::VpnList { - public: - // An observer that is notified whenever the list of VPN providers enabled in - // the primary user's profile changes. - class Observer { - public: - virtual void OnVPNProvidersChanged() = 0; - - protected: - virtual ~Observer(); - - private: - DISALLOW_ASSIGN(Observer); - }; - - VpnList(); - ~VpnList() override; - - const std::vector<VPNProvider>& vpn_providers() { return vpn_providers_; } - - // Returns |true| if at least one third-party VPN provider is enabled in the - // primary user's profile, in addition to the built-in OpenVPN/L2TP provider. - bool HaveThirdPartyVPNProviders() const; - - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - - // Binds the mojom::VpnList interface to this object. - void BindRequest(mojom::VpnListRequest request); - - // mojom::VpnList: - void SetThirdPartyVpnProviders( - std::vector<mojom::ThirdPartyVpnProviderPtr> providers) override; - - private: - // Notify observers that the list of VPN providers enabled in the primary - // user's profile has changed. - void NotifyObservers(); - - // Adds the built-in OpenVPN/L2TP provider to |vpn_providers_|. - void AddBuiltInProvider(); - - // Bindings for the mojom::VpnList interface. - mojo::BindingSet<mojom::VpnList> bindings_; - - // Cache of VPN providers, including the built-in OpenVPN/L2TP provider and - // other providers added by extensions in the primary user's profile. - std::vector<VPNProvider> vpn_providers_; - - base::ObserverList<Observer> observer_list_; - - DISALLOW_COPY_AND_ASSIGN(VpnList); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_VPN_LIST_H_
diff --git a/ash/system/network/vpn_list_unittest.cc b/ash/system/network/vpn_list_unittest.cc deleted file mode 100644 index f5c501e..0000000 --- a/ash/system/network/vpn_list_unittest.cc +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/vpn_list.h" - -#include <algorithm> -#include <vector> - -#include "ash/public/interfaces/vpn_list.mojom.h" -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ash::mojom::ThirdPartyVpnProvider; -using ash::mojom::ThirdPartyVpnProviderPtr; - -namespace ash { - -namespace { - -class TestVpnListObserver : public VpnList::Observer { - public: - TestVpnListObserver() {} - ~TestVpnListObserver() override {} - - // VpnList::Observer: - void OnVPNProvidersChanged() override { change_count_++; } - - int change_count_ = 0; -}; - -} // namespace - -using VpnListTest = testing::Test; - -TEST_F(VpnListTest, BuiltInProvider) { - VpnList vpn_list; - - // The VPN list should only contain the built-in provider. - ASSERT_EQ(1u, vpn_list.vpn_providers().size()); - VPNProvider provider = vpn_list.vpn_providers()[0]; - EXPECT_FALSE(provider.third_party); - EXPECT_TRUE(provider.extension_id.empty()); -} - -TEST_F(VpnListTest, ThirdPartyProviders) { - VpnList vpn_list; - - // The VPN list should only contain the built-in provider. - EXPECT_EQ(1u, vpn_list.vpn_providers().size()); - - // Add some third party (extension-backed) providers. - std::vector<ThirdPartyVpnProviderPtr> third_party_providers; - ThirdPartyVpnProviderPtr third_party1 = ThirdPartyVpnProvider::New(); - third_party1->name = "name1"; - third_party1->extension_id = "extension_id1"; - third_party_providers.push_back(std::move(third_party1)); - - ThirdPartyVpnProviderPtr third_party2 = ThirdPartyVpnProvider::New(); - third_party2->name = "name2"; - third_party2->extension_id = "extension_id2"; - third_party_providers.push_back(std::move(third_party2)); - - vpn_list.SetThirdPartyVpnProviders(std::move(third_party_providers)); - - // Mojo types will be converted to internal ash types. - VPNProvider provider1("extension_id1", "name1"); - VPNProvider provider2("extension_id2", "name2"); - - // List contains the extension-backed providers. Order doesn't matter. - std::vector<VPNProvider> providers = vpn_list.vpn_providers(); - EXPECT_EQ(3u, providers.size()); - EXPECT_EQ(1u, std::count(providers.begin(), providers.end(), provider1)); - EXPECT_EQ(1u, std::count(providers.begin(), providers.end(), provider2)); -} - -TEST_F(VpnListTest, Observers) { - VpnList vpn_list; - - // Observers are not notified when they are added. - TestVpnListObserver observer; - vpn_list.AddObserver(&observer); - EXPECT_EQ(0, observer.change_count_); - - // Add a third party (extension-backed) provider. - std::vector<ThirdPartyVpnProviderPtr> third_party_providers; - ThirdPartyVpnProviderPtr third_party1 = ThirdPartyVpnProvider::New(); - third_party1->name = "name1"; - third_party1->extension_id = "extension_id1"; - third_party_providers.push_back(std::move(third_party1)); - vpn_list.SetThirdPartyVpnProviders(std::move(third_party_providers)); - - // Observer was notified. - EXPECT_EQ(1, observer.change_count_); - - vpn_list.RemoveObserver(&observer); -} - -} // namespace ash
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc deleted file mode 100644 index 7e52300..0000000 --- a/ash/system/network/vpn_list_view.cc +++ /dev/null
@@ -1,440 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/network/vpn_list_view.h" - -#include <memory> -#include <utility> -#include <vector> - -#include "ash/common/ash_view_ids.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" -#include "ash/system/network/network_icon_animation_observer.h" -#include "ash/system/network/network_list_delegate.h" -#include "ash/system/network/vpn_list.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/throbber_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "chromeos/network/network_connection_handler.h" -#include "chromeos/network/network_handler.h" -#include "chromeos/network/network_state.h" -#include "chromeos/network/network_type_pattern.h" -#include "third_party/cros_system_api/dbus/service_constants.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/text_constants.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/view.h" - -namespace ash { - -namespace { - -bool UseMd() { - return MaterialDesignController::IsSystemTrayMenuMaterial(); -} - -// Indicates whether |network| belongs to this VPN provider. -bool VpnProviderMatchesNetwork(const VPNProvider& provider, - const chromeos::NetworkState& network) { - if (network.type() != shill::kTypeVPN) - return false; - const bool network_uses_third_party_provider = - network.vpn_provider_type() == shill::kProviderThirdPartyVpn; - if (!provider.third_party) - return !network_uses_third_party_provider; - return network_uses_third_party_provider && - network.third_party_vpn_provider_extension_id() == - provider.extension_id; -} - -// The base class of all list entries, a |HoverHighlightView| with no border. -class VPNListEntryBase : public HoverHighlightView { - public: - // When the user clicks the entry, the |parent|'s OnViewClicked() will be - // invoked. - explicit VPNListEntryBase(VPNListView* parent); - - private: - DISALLOW_COPY_AND_ASSIGN(VPNListEntryBase); -}; - -// A list entry that represents a VPN provider. -class VPNListProviderEntry : public VPNListEntryBase { - public: - VPNListProviderEntry(VPNListView* parent, const std::string& name) - : VPNListEntryBase(parent) { - views::Label* const label = AddLabel( - base::UTF8ToUTF16(name), gfx::ALIGN_LEFT, false /* highlight */); - label->SetBorder(views::CreateEmptyBorder(5, 0, 5, 0)); - } - - private: - DISALLOW_COPY_AND_ASSIGN(VPNListProviderEntry); -}; - -// A list entry that represents a VPN provider with Material Design. -class VPNListProviderEntryMd : public views::ButtonListener, - public views::View { - public: - VPNListProviderEntryMd(ViewClickListener* parent, - bool top_item, - const std::string& name, - int button_accessible_name_id) - : parent_(parent) { - TrayPopupUtils::ConfigureAsStickyHeader(this); - SetLayoutManager(new views::FillLayout); - TriView* tri_view = TrayPopupUtils::CreateSubHeaderRowView(); - AddChildView(tri_view); - - views::Label* label = TrayPopupUtils::CreateDefaultLabel(); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SUB_HEADER); - style.SetupLabel(label); - label->SetText(base::ASCIIToUTF16(name)); - tri_view->AddView(TriView::Container::CENTER, label); - - const SkColor image_color = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor); - gfx::ImageSkia icon = - gfx::CreateVectorIcon(kSystemMenuAddConnectionIcon, image_color); - SystemMenuButton* add_vpn_button = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, icon, - icon, button_accessible_name_id); - add_vpn_button->SetInkDropColor(image_color); - add_vpn_button->SetEnabled(true); - tri_view->AddView(TriView::Container::END, add_vpn_button); - } - - protected: - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override { - parent_->OnViewClicked(this); - } - - private: - // Our parent to handle events. - ViewClickListener* parent_; - - DISALLOW_COPY_AND_ASSIGN(VPNListProviderEntryMd); -}; - -// A list entry that represents a network. If the network is currently -// connecting, the icon shown by this list entry will be animated. If the -// network is currently connected, a disconnect button will be shown next to its -// name. -class VPNListNetworkEntry : public VPNListEntryBase, - public network_icon::AnimationObserver { - public: - VPNListNetworkEntry(VPNListView* parent, - const chromeos::NetworkState* network); - ~VPNListNetworkEntry() override; - - // network_icon::AnimationObserver: - void NetworkIconChanged() override; - - private: - void UpdateFromNetworkState(const chromeos::NetworkState* network); - void SetupConnectedItemMd(const base::string16& text, - const gfx::ImageSkia& image); - void SetupConnectingItemMd(const base::string16& text, - const gfx::ImageSkia& image); - - const std::string guid_; - - views::LabelButton* disconnect_button_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(VPNListNetworkEntry); -}; - -VPNListEntryBase::VPNListEntryBase(VPNListView* parent) - : HoverHighlightView(parent) { - if (!UseMd()) - SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); -} - -VPNListNetworkEntry::VPNListNetworkEntry(VPNListView* parent, - const chromeos::NetworkState* network) - : VPNListEntryBase(parent), guid_(network->guid()) { - UpdateFromNetworkState(network); -} - -VPNListNetworkEntry::~VPNListNetworkEntry() { - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); -} - -void VPNListNetworkEntry::NetworkIconChanged() { - UpdateFromNetworkState(chromeos::NetworkHandler::Get() - ->network_state_handler() - ->GetNetworkStateFromGuid(guid_)); -} - -void VPNListNetworkEntry::UpdateFromNetworkState( - const chromeos::NetworkState* network) { - if (network && network->IsConnectingState()) - network_icon::NetworkIconAnimation::GetInstance()->AddObserver(this); - else - network_icon::NetworkIconAnimation::GetInstance()->RemoveObserver(this); - - if (!network) { - // This is a transient state where the network has been removed already but - // the network list in the UI has not been updated yet. - return; - } - RemoveAllChildViews(true); - disconnect_button_ = nullptr; - - gfx::ImageSkia image = - network_icon::GetImageForNetwork(network, network_icon::ICON_TYPE_LIST); - base::string16 label = network_icon::GetLabelForNetwork( - network, UseMd() ? network_icon::ICON_TYPE_MENU_LIST - : network_icon::ICON_TYPE_LIST); - if (network->IsConnectedState()) - SetupConnectedItemMd(label, image); - else if (network->IsConnectingState()) - SetupConnectingItemMd(label, image); - else - AddIconAndLabel(image, label, false); - - if (network->IsConnectedState()) { - disconnect_button_ = TrayPopupUtils::CreateTrayPopupButton( - this, l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_DISCONNECT)); - tri_view()->AddView(TriView::Container::END, disconnect_button_); - tri_view()->SetContainerVisible(TriView::Container::END, true); - tri_view()->SetContainerBorder( - TriView::Container::END, - views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); - } - Layout(); -} - -// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. -void VPNListNetworkEntry::SetupConnectedItemMd(const base::string16& text, - const gfx::ImageSkia& image) { - AddIconAndLabels( - image, text, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::CAPTION); - style.set_color_style(TrayPopupItemStyle::ColorStyle::CONNECTED); - style.SetupLabel(sub_text_label()); -} - -// TODO(varkha): Consolidate with a similar method in tray_bluetooth.cc. -void VPNListNetworkEntry::SetupConnectingItemMd(const base::string16& text, - const gfx::ImageSkia& image) { - AddIconAndLabels( - image, text, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING)); - ThrobberView* throbber = new ThrobberView; - throbber->Start(); - AddRightView(throbber); -} - -} // namespace - -VPNListView::VPNListView(NetworkListDelegate* delegate) : delegate_(delegate) { - WmShell::Get()->vpn_list()->AddObserver(this); -} - -VPNListView::~VPNListView() { - WmShell::Get()->vpn_list()->RemoveObserver(this); -} - -void VPNListView::Update() { - // Before updating the list, determine whether the user was hovering over one - // of the VPN provider or network entries. - std::unique_ptr<VPNProvider> hovered_provider; - std::string hovered_network_guid; - for (const std::pair<const views::View* const, VPNProvider>& provider : - provider_view_map_) { - if (static_cast<const HoverHighlightView*>(provider.first)->hover()) { - hovered_provider.reset(new VPNProvider(provider.second)); - break; - } - } - if (!hovered_provider) { - for (const std::pair<const views::View*, std::string>& entry : - network_view_guid_map_) { - if (static_cast<const HoverHighlightView*>(entry.first)->hover()) { - hovered_network_guid = entry.second; - break; - } - } - } - - // Clear the list. - container()->RemoveAllChildViews(true); - provider_view_map_.clear(); - network_view_guid_map_.clear(); - list_empty_ = true; - if (!UseMd()) { - container()->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); - } - - // Get the list of available VPN networks, in shill's priority order. - chromeos::NetworkStateHandler::NetworkStateList networks; - chromeos::NetworkHandler::Get() - ->network_state_handler() - ->GetVisibleNetworkListByType(chromeos::NetworkTypePattern::VPN(), - &networks); - - // Show all VPN providers and all networks that are currently disconnected. - AddProvidersAndNetworks(networks); - - // Determine whether one of the new list entries corresponds to the entry that - // the user was previously hovering over. If such an entry is found, the list - // will be scrolled to ensure the entry is visible. - const views::View* scroll_to_show_view = nullptr; - if (hovered_provider) { - for (const std::pair<const views::View* const, VPNProvider>& provider : - provider_view_map_) { - if (provider.second == *hovered_provider) { - scroll_to_show_view = provider.first; - break; - } - } - } else if (!hovered_network_guid.empty()) { - for (const std::pair<const views::View*, std::string>& entry : - network_view_guid_map_) { - if (entry.second == hovered_network_guid) { - scroll_to_show_view = entry.first; - break; - } - } - } - - // Layout the updated list. - container()->SizeToPreferredSize(); - delegate_->RelayoutScrollList(); - - if (scroll_to_show_view) { - // Scroll the list so that |scroll_to_show_view| is in view. - container()->ScrollRectToVisible(scroll_to_show_view->bounds()); - } -} - -bool VPNListView::IsNetworkEntry(views::View* view, std::string* guid) const { - const auto& entry = network_view_guid_map_.find(view); - if (entry == network_view_guid_map_.end()) - return false; - *guid = entry->second; - return true; -} - -void VPNListView::OnVPNProvidersChanged() { - Update(); -} - -void VPNListView::OnViewClicked(views::View* sender) { - const auto& provider_iter = provider_view_map_.find(sender); - if (provider_iter != provider_view_map_.end()) { - // If the user clicks on a provider entry, request that the "add network" - // dialog for this provider be shown. - const VPNProvider& provider = provider_iter->second; - WmShell* shell = WmShell::Get(); - if (provider.third_party) { - shell->RecordUserMetricsAction( - UMA_STATUS_AREA_VPN_ADD_THIRD_PARTY_CLICKED); - shell->system_tray_controller()->ShowThirdPartyVpnCreate( - provider.extension_id); - } else { - shell->RecordUserMetricsAction(UMA_STATUS_AREA_VPN_ADD_BUILT_IN_CLICKED); - shell->system_tray_controller()->ShowNetworkCreate(shill::kTypeVPN); - } - return; - } - - // If the user clicked on a network entry, let the |delegate_| trigger a - // connection attempt (if the network is currently disconnected) or show a - // configuration dialog (if the network is currently connected or connecting). - delegate_->OnNetworkEntryClicked(sender); -} - -void VPNListView::AddNetwork(const chromeos::NetworkState* network) { - views::View* entry(new VPNListNetworkEntry(this, network)); - container()->AddChildView(entry); - network_view_guid_map_[entry] = network->guid(); - list_empty_ = false; -} - -void VPNListView::AddProviderAndNetworks( - const VPNProvider& vpn_provider, - const chromeos::NetworkStateHandler::NetworkStateList& networks) { - // Add a visual separator, unless this is the topmost entry in the list. - if (!list_empty_) - container()->AddChildView(TrayPopupUtils::CreateListSubHeaderSeparator()); - std::string vpn_name = - vpn_provider.third_party - ? vpn_provider.third_party_provider_name - : l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_VPN_BUILT_IN_PROVIDER); - - // Add a list entry for the VPN provider. - views::View* provider_view = nullptr; - if (UseMd()) { - provider_view = new VPNListProviderEntryMd( - this, list_empty_, vpn_name, IDS_ASH_STATUS_TRAY_ADD_CONNECTION); - } else { - provider_view = new VPNListProviderEntry(this, vpn_name); - } - container()->AddChildView(provider_view); - provider_view_map_[provider_view] = vpn_provider; - list_empty_ = false; - // Add the networks belonging to this provider, in the priority order returned - // by shill. - for (const chromeos::NetworkState* const& network : networks) { - if (VpnProviderMatchesNetwork(vpn_provider, *network)) - AddNetwork(network); - } -} - -void VPNListView::AddProvidersAndNetworks( - const chromeos::NetworkStateHandler::NetworkStateList& networks) { - // Get the list of VPN providers enabled in the primary user's profile. - std::vector<VPNProvider> providers = - WmShell::Get()->vpn_list()->vpn_providers(); - - // Add providers with at least one configured network along with their - // networks. Providers are added in the order of their highest priority - // network. - for (const chromeos::NetworkState* const& network : networks) { - for (auto provider = providers.begin(); provider != providers.end(); - ++provider) { - if (!VpnProviderMatchesNetwork(*provider, *network)) - continue; - AddProviderAndNetworks(*provider, networks); - providers.erase(provider); - break; - } - } - - // Add providers without any configured networks, in the order that the - // providers were returned by the extensions system. - for (const VPNProvider& provider : providers) - AddProviderAndNetworks(provider, networks); -} - -} // namespace ash
diff --git a/ash/system/network/vpn_list_view.h b/ash/system/network/vpn_list_view.h deleted file mode 100644 index 2f59d00..0000000 --- a/ash/system/network/vpn_list_view.h +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORK_VPN_LIST_VIEW_H_ -#define ASH_SYSTEM_NETWORK_VPN_LIST_VIEW_H_ - -#include <map> -#include <string> - -#include "ash/system/network/network_list_view_base.h" -#include "ash/system/network/vpn_list.h" -#include "ash/system/tray/view_click_listener.h" -#include "base/macros.h" -#include "chromeos/network/network_state_handler.h" - -namespace chromeos { -class NetworkState; -} - -namespace ash { -class NetworkListDelegate; -} - -namespace views { -class View; -} - -namespace ash { - -// A list of VPN providers and networks that shows VPN providers and networks in -// a hierarchical layout, allowing the user to see at a glance which provider a -// network belongs to. The only exception is the currently connected or -// connecting network, which is detached from its provider and moved to the top. -// If there is a connected network, a disconnect button is shown next to its -// name. -// -// Disconnected networks are arranged in shill's priority order within each -// provider and the providers are arranged in the order of their highest -// priority network. Clicking on a disconnected network triggers a connection -// attempt. Clicking on the currently connected or connecting network shows its -// configuration dialog. Clicking on a provider shows the provider's "add -// network" dialog. -class VPNListView : public NetworkListViewBase, - public VpnList::Observer, - public ViewClickListener { - public: - explicit VPNListView(NetworkListDelegate* delegate); - ~VPNListView() override; - - // NetworkListViewBase: - void Update() override; - bool IsNetworkEntry(views::View* view, std::string* guid) const override; - - // VpnList::Observer: - void OnVPNProvidersChanged() override; - - // ViewClickListener: - void OnViewClicked(views::View* sender) override; - - private: - // Adds a network to the list. - void AddNetwork(const chromeos::NetworkState* network); - - // Adds the VPN provider identified by |vpn_provider| to the list, along with - // any networks that belong to this provider. - void AddProviderAndNetworks( - const VPNProvider& vpn_provider, - const chromeos::NetworkStateHandler::NetworkStateList& networks); - - // Adds all available VPN providers and networks to the list. - void AddProvidersAndNetworks( - const chromeos::NetworkStateHandler::NetworkStateList& networks); - - NetworkListDelegate* const delegate_; - - // A mapping from each VPN provider's list entry to the provider. - std::map<const views::View* const, VPNProvider> provider_view_map_; - - // A mapping from each network's list entry to the network's guid. - std::map<const views::View* const, std::string> network_view_guid_map_; - - // Whether the list is currently empty (i.e., the next entry added will become - // the topmost entry). - bool list_empty_ = true; - - DISALLOW_COPY_AND_ASSIGN(VPNListView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORK_VPN_LIST_VIEW_H_
diff --git a/ash/system/networking_config_delegate.cc b/ash/system/networking_config_delegate.cc deleted file mode 100644 index 4c514cf..0000000 --- a/ash/system/networking_config_delegate.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/networking_config_delegate.h" - -namespace ash { - -NetworkingConfigDelegate::ExtensionInfo::ExtensionInfo(const std::string& id, - const std::string& name) - : extension_id(id), extension_name(name) {} - -NetworkingConfigDelegate::ExtensionInfo::~ExtensionInfo() {} - -} // namespace ash
diff --git a/ash/system/networking_config_delegate.h b/ash/system/networking_config_delegate.h deleted file mode 100644 index b040e70..0000000 --- a/ash/system/networking_config_delegate.h +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_ -#define ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_ - -#include <memory> -#include <string> - -#include "ash/ash_export.h" -#include "base/macros.h" - -namespace ash { - -// This delegate allows the UI code in ash, e.g. |NetworkStateListDetailedView|, -// to access the |NetworkingConfigService| in order to determine whether the -// configuration of a network identified by its |guid| is controlled by -// an extension. -// TODO(crbug.com/651157): Eliminate this delegate. Information about extension -// controlled networks should be provided by a mojo service that caches data at -// the NetworkState level. -class NetworkingConfigDelegate { - public: - // A struct that provides information about the extension controlling the - // configuration of a network. - struct ASH_EXPORT ExtensionInfo { - ExtensionInfo(const std::string& id, const std::string& name); - ~ExtensionInfo(); - std::string extension_id; - std::string extension_name; - }; - - virtual ~NetworkingConfigDelegate() {} - - // Returns information about the extension registered to control configuration - // of the network |guid|. Returns null if no extension is registered. - virtual std::unique_ptr<const ExtensionInfo> LookUpExtensionForNetwork( - const std::string& guid) = 0; - - private: - DISALLOW_ASSIGN(NetworkingConfigDelegate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_NETWORKING_CONFIG_DELEGATE_H_
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc deleted file mode 100644 index 91ef413..0000000 --- a/ash/system/overview/overview_button_tray.cc +++ /dev/null
@@ -1,128 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/overview/overview_button_tray.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/border.h" -#include "ui/views/controls/image_view.h" - -namespace ash { - -OverviewButtonTray::OverviewButtonTray(WmShelf* wm_shelf) - : TrayBackgroundView(wm_shelf), icon_(new views::ImageView()) { - SetInkDropMode(InkDropMode::ON); - SetContentsBackground(false); - - icon_->SetImage(CreateVectorIcon(kShelfOverviewIcon, kShelfIconColor)); - SetIconBorderForShelfAlignment(); - tray_container()->AddChildView(icon_); - - // Since OverviewButtonTray is located on the rightmost position of a - // horizontal shelf, no separator is required. - set_separator_visibility(false); - - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->GetSessionStateDelegate()->AddSessionStateObserver(this); -} - -OverviewButtonTray::~OverviewButtonTray() { - WmShell::Get()->RemoveShellObserver(this); - WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); -} - -void OverviewButtonTray::UpdateAfterLoginStatusChange(LoginStatus status) { - UpdateIconVisibility(); -} - -bool OverviewButtonTray::PerformAction(const ui::Event& event) { - WindowSelectorController* controller = - WmShell::Get()->window_selector_controller(); - // Toggling overview mode will fail if there is no window to show. - bool performed = controller->ToggleOverview(); - WmShell::Get()->RecordUserMetricsAction(UMA_TRAY_OVERVIEW); - return performed; -} - -void OverviewButtonTray::SessionStateChanged( - session_manager::SessionState state) { - UpdateIconVisibility(); -} - -void OverviewButtonTray::OnMaximizeModeStarted() { - UpdateIconVisibility(); -} - -void OverviewButtonTray::OnMaximizeModeEnded() { - UpdateIconVisibility(); -} - -void OverviewButtonTray::OnOverviewModeStarting() { - SetIsActive(true); -} - -void OverviewButtonTray::OnOverviewModeEnded() { - SetIsActive(false); -} - -void OverviewButtonTray::ClickedOutsideBubble() {} - -base::string16 OverviewButtonTray::GetAccessibleNameForTray() { - return l10n_util::GetStringUTF16(IDS_ASH_OVERVIEW_BUTTON_ACCESSIBLE_NAME); -} - -void OverviewButtonTray::HideBubbleWithView( - const views::TrayBubbleView* bubble_view) { - // This class has no bubbles to hide. -} - -void OverviewButtonTray::SetShelfAlignment(ShelfAlignment alignment) { - if (alignment == shelf_alignment()) - return; - - TrayBackgroundView::SetShelfAlignment(alignment); - SetIconBorderForShelfAlignment(); -} - -void OverviewButtonTray::SetIconBorderForShelfAlignment() { - // Pad button size to align with other controls in the system tray. - const gfx::ImageSkia& image = icon_->GetImage(); - const int vertical_padding = (kTrayItemSize - image.height()) / 2; - const int horizontal_padding = (kTrayItemSize - image.width()) / 2; - icon_->SetBorder(views::CreateEmptyBorder( - gfx::Insets(vertical_padding, horizontal_padding))); -} - -void OverviewButtonTray::UpdateIconVisibility() { - // The visibility of the OverviewButtonTray has diverged from - // WindowSelectorController::CanSelect. The visibility of the button should - // not change during transient times in which CanSelect is false. Such as when - // a modal dialog is present. - WmShell* shell = WmShell::Get(); - SessionStateDelegate* session_state_delegate = - shell->GetSessionStateDelegate(); - - SetVisible( - shell->maximize_mode_controller()->IsMaximizeModeWindowManagerEnabled() && - session_state_delegate->IsActiveUserSessionStarted() && - !session_state_delegate->IsScreenLocked() && - session_state_delegate->GetSessionState() == - session_manager::SessionState::ACTIVE && - shell->system_tray_delegate()->GetUserLoginStatus() != - LoginStatus::KIOSK_APP && - shell->system_tray_delegate()->GetUserLoginStatus() != - LoginStatus::ARC_KIOSK_APP); -} - -} // namespace ash
diff --git a/ash/system/overview/overview_button_tray.h b/ash/system/overview/overview_button_tray.h deleted file mode 100644 index f5db6be..0000000 --- a/ash/system/overview/overview_button_tray.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_ -#define ASH_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_ - -#include "ash/ash_export.h" -#include "ash/common/session/session_state_observer.h" -#include "ash/common/shell_observer.h" -#include "ash/system/tray/tray_background_view.h" -#include "base/macros.h" - -namespace views { -class ImageView; -} - -namespace ash { - -// Status area tray for showing a toggle for Overview Mode. Overview Mode -// is equivalent to WindowSelectorController being in selection mode. -// This hosts a ShellObserver that listens for the activation of Maximize Mode -// This tray will only be visible while in this state. This tray does not -// provide any bubble view windows. -class ASH_EXPORT OverviewButtonTray : public TrayBackgroundView, - public SessionStateObserver, - public ShellObserver { - public: - explicit OverviewButtonTray(WmShelf* wm_shelf); - ~OverviewButtonTray() override; - - // Updates the tray's visibility based on the LoginStatus and the current - // state of MaximizeMode - virtual void UpdateAfterLoginStatusChange(LoginStatus status); - - // ActionableView: - bool PerformAction(const ui::Event& event) override; - - // SessionStateObserver: - void SessionStateChanged(session_manager::SessionState state) override; - - // ShellObserver: - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - void OnOverviewModeStarting() override; - void OnOverviewModeEnded() override; - - // TrayBackgroundView: - void ClickedOutsideBubble() override; - base::string16 GetAccessibleNameForTray() override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void SetShelfAlignment(ShelfAlignment alignment) override; - - private: - friend class OverviewButtonTrayTest; - - // Creates a new border for the icon. The padding is determined based on the - // alignment of the shelf. - void SetIconBorderForShelfAlignment(); - - // Sets the icon to visible if maximize mode is enabled and - // WindowSelectorController::CanSelect. - void UpdateIconVisibility(); - - // Weak pointer, will be parented by TrayContainer for its lifetime. - views::ImageView* icon_; - - DISALLOW_COPY_AND_ASSIGN(OverviewButtonTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc index 4783129..9aaf224c 100644 --- a/ash/system/overview/overview_button_tray_unittest.cc +++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -2,20 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/overview/overview_button_tray.h" +#include "ash/common/system/overview/overview_button_tray.h" #include "ash/common/login_status.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shelf_types.h" #include "ash/root_window_controller.h" #include "ash/rotator/screen_rotation_animator.h" -#include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test/status_area_widget_test_helper.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/overview/window_selector_controller.h" #include "base/command_line.h" #include "base/test/user_action_tester.h" #include "base/time/time.h"
diff --git a/ash/system/palette/common_palette_tool.cc b/ash/system/palette/common_palette_tool.cc deleted file mode 100644 index 6495006..0000000 --- a/ash/system/palette/common_palette_tool.cc +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/common_palette_tool.h" - -#include "ash/resources/grit/ash_resources.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/system/palette/palette_ids.h" -#include "ash/system/palette/palette_tool_manager.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/view_click_listener.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" - -namespace ash { -namespace { - -void AddHistogramTimes(PaletteToolId id, base::TimeDelta duration) { - if (id == PaletteToolId::LASER_POINTER) { - UMA_HISTOGRAM_CUSTOM_TIMES("Ash.Shelf.Palette.InLaserPointerMode", duration, - base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromHours(1), 50); - } else if (id == PaletteToolId::MAGNIFY) { - UMA_HISTOGRAM_CUSTOM_TIMES("Ash.Shelf.Palette.InMagnifyMode", duration, - base::TimeDelta::FromMilliseconds(100), - base::TimeDelta::FromHours(1), 50); - } -} - -} // namespace - -CommonPaletteTool::CommonPaletteTool(Delegate* delegate) - : PaletteTool(delegate) {} - -CommonPaletteTool::~CommonPaletteTool() {} - -void CommonPaletteTool::OnViewDestroyed() { - highlight_view_ = nullptr; -} - -void CommonPaletteTool::OnEnable() { - PaletteTool::OnEnable(); - start_time_ = base::TimeTicks::Now(); - - if (highlight_view_) { - highlight_view_->SetRightViewVisible(true); - highlight_view_->SetAccessiblityState( - HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); - } -} - -void CommonPaletteTool::OnDisable() { - PaletteTool::OnDisable(); - AddHistogramTimes(GetToolId(), base::TimeTicks::Now() - start_time_); - - if (highlight_view_) { - highlight_view_->SetRightViewVisible(false); - highlight_view_->SetAccessiblityState( - HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); - } -} - -void CommonPaletteTool::OnViewClicked(views::View* sender) { - delegate()->RecordPaletteOptionsUsage( - PaletteToolIdToPaletteTrayOptions(GetToolId())); - if (enabled()) { - delegate()->DisableTool(GetToolId()); - delegate()->RecordPaletteModeCancellation( - PaletteToolIdToPaletteModeCancelType(GetToolId(), - false /*is_switched*/)); - } else { - delegate()->EnableTool(GetToolId()); - } -} - -views::View* CommonPaletteTool::CreateDefaultView(const base::string16& name) { - gfx::ImageSkia icon = - CreateVectorIcon(GetPaletteIcon(), kMenuIconSize, gfx::kChromeIconGrey); - gfx::ImageSkia check = CreateVectorIcon(gfx::VectorIconId::CHECK_CIRCLE, - kMenuIconSize, gfx::kGoogleGreen700); - - highlight_view_ = new HoverHighlightView(this); - highlight_view_->SetBorder(views::CreateEmptyBorder(0, 0, 0, 0)); - const int interior_button_padding = (kMenuButtonSize - kMenuIconSize) / 2; - highlight_view_->AddIconAndLabelCustomSize(icon, name, false, kMenuIconSize, - interior_button_padding, - kTrayPopupPaddingHorizontal); - highlight_view_->AddRightIcon(check, kMenuIconSize); - highlight_view_->set_custom_height(kMenuButtonSize); - - if (enabled()) { - highlight_view_->SetAccessiblityState( - HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); - } else { - highlight_view_->SetRightViewVisible(false); - highlight_view_->SetAccessiblityState( - HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); - } - - return highlight_view_; -} - -} // namespace ash
diff --git a/ash/system/palette/common_palette_tool.h b/ash/system/palette/common_palette_tool.h deleted file mode 100644 index 91526d6..0000000 --- a/ash/system/palette/common_palette_tool.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_COMMON_PALETTE_TOOL_H_ -#define ASH_SYSTEM_PALETTE_COMMON_PALETTE_TOOL_H_ - -#include "ash/system/palette/palette_tool.h" -#include "ash/system/tray/view_click_listener.h" -#include "base/strings/string16.h" -#include "base/time/time.h" - -namespace gfx { -struct VectorIcon; -} - -namespace ash { - -class HoverHighlightView; - -// A PaletteTool implementation with a standard view support. -class CommonPaletteTool : public PaletteTool, public ash::ViewClickListener { - protected: - explicit CommonPaletteTool(Delegate* delegate); - ~CommonPaletteTool() override; - - // PaletteTool: - void OnViewDestroyed() override; - void OnEnable() override; - void OnDisable() override; - - // ViewClickListener: - void OnViewClicked(views::View* sender) override; - - // Returns the icon used in the palette tray on the left-most edge of the - // tool. - virtual const gfx::VectorIcon& GetPaletteIcon() const = 0; - - // Creates a default view implementation to be returned by CreateView. - views::View* CreateDefaultView(const base::string16& name); - - private: - HoverHighlightView* highlight_view_ = nullptr; - - // start_time_ is initialized when the tool becomes active. - // Used for recording UMA metrics. - base::TimeTicks start_time_; - - DISALLOW_COPY_AND_ASSIGN(CommonPaletteTool); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_COMMON_PALETTE_TOOL_H_
diff --git a/ash/system/palette/mock_palette_tool_delegate.cc b/ash/system/palette/mock_palette_tool_delegate.cc deleted file mode 100644 index bada5ff4..0000000 --- a/ash/system/palette/mock_palette_tool_delegate.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/mock_palette_tool_delegate.h" - -namespace ash { - -MockPaletteToolDelegate::MockPaletteToolDelegate() {} - -MockPaletteToolDelegate::~MockPaletteToolDelegate() {} - -} // namespace ash
diff --git a/ash/system/palette/mock_palette_tool_delegate.h b/ash/system/palette/mock_palette_tool_delegate.h deleted file mode 100644 index 8e8bc64..0000000 --- a/ash/system/palette/mock_palette_tool_delegate.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_MOCK_PALETTE_TOOL_DELEGATE_H_ -#define ASH_SYSTEM_PALETTE_MOCK_PALETTE_TOOL_DELEGATE_H_ - -#include "ash/system/palette/palette_tool.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace ash { - -// Mock PaletteTool::Delegate class. -class MockPaletteToolDelegate : public PaletteTool::Delegate { - public: - MockPaletteToolDelegate(); - ~MockPaletteToolDelegate() override; - - MOCK_METHOD1(EnableTool, void(PaletteToolId tool_id)); - MOCK_METHOD1(DisableTool, void(PaletteToolId tool_id)); - MOCK_METHOD0(HidePalette, void()); - MOCK_METHOD0(HidePaletteImmediately, void()); - MOCK_METHOD0(GetWindow, WmWindow*()); - MOCK_METHOD1(RecordPaletteOptionsUsage, void(PaletteTrayOptions option)); - MOCK_METHOD1(RecordPaletteModeCancellation, void(PaletteModeCancelType type)); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_MOCK_PALETTE_TOOL_DELEGATE_H_
diff --git a/ash/system/palette/palette_ids.cc b/ash/system/palette/palette_ids.cc deleted file mode 100644 index 1e2338f4..0000000 --- a/ash/system/palette/palette_ids.cc +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/palette_ids.h" -#include "base/logging.h" - -namespace ash { - -std::string PaletteToolIdToString(PaletteToolId tool_id) { - switch (tool_id) { - case PaletteToolId::NONE: - return "NONE"; - case PaletteToolId::CREATE_NOTE: - return "CREATE_NOTE"; - case PaletteToolId::CAPTURE_REGION: - return "CAPTURE_REGION"; - case PaletteToolId::CAPTURE_SCREEN: - return "CAPTURE_SCREEN"; - case PaletteToolId::LASER_POINTER: - return "LASER_POINTER"; - case PaletteToolId::MAGNIFY: - return "MAGNIFY"; - } - - NOTREACHED(); - return std::string(); -} - -std::string PaletteGroupToString(PaletteGroup group) { - switch (group) { - case PaletteGroup::ACTION: - return "ACTION"; - case PaletteGroup::MODE: - return "MODE"; - } - - NOTREACHED(); - return std::string(); -} - -PaletteTrayOptions PaletteToolIdToPaletteTrayOptions(PaletteToolId tool_id) { - switch (tool_id) { - case PaletteToolId::NONE: - return PALETTE_OPTIONS_COUNT; - case PaletteToolId::CREATE_NOTE: - return PALETTE_NEW_NOTE; - case PaletteToolId::CAPTURE_REGION: - return PALETTE_CAPTURE_REGION; - case PaletteToolId::CAPTURE_SCREEN: - return PALETTE_CAPTURE_SCREEN; - case PaletteToolId::LASER_POINTER: - return PALETTE_LASER_POINTER; - case PaletteToolId::MAGNIFY: - return PALETTE_MAGNIFY; - } - - NOTREACHED(); - return PALETTE_OPTIONS_COUNT; -} - -PaletteModeCancelType PaletteToolIdToPaletteModeCancelType( - PaletteToolId tool_id, - bool is_switched) { - PaletteModeCancelType type = PALETTE_MODE_CANCEL_TYPE_COUNT; - if (tool_id == PaletteToolId::LASER_POINTER) { - return is_switched ? PALETTE_MODE_LASER_POINTER_SWITCHED - : PALETTE_MODE_LASER_POINTER_CANCELLED; - } else if (tool_id == PaletteToolId::MAGNIFY) { - return is_switched ? PALETTE_MODE_MAGNIFY_SWITCHED - : PALETTE_MODE_MAGNIFY_CANCELLED; - } - return type; -} - -} // namespace ash
diff --git a/ash/system/palette/palette_ids.h b/ash/system/palette/palette_ids.h deleted file mode 100644 index d3369a26..0000000 --- a/ash/system/palette/palette_ids.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_PALETTE_IDS_H_ -#define ASH_SYSTEM_PALETTE_PALETTE_IDS_H_ - -#include <string> - -#include "ash/ash_export.h" - -namespace ash { - -// Palette tools are grouped into different categories. Each tool corresponds to -// exactly one group, and at most one tool can be active per group. Actions are -// actions the user wants to do, such as take a screenshot, and modes generally -// change OS behavior, like showing a laser pointer instead of a cursor. A mode -// is active until the user completes the action or disables it. -enum class PaletteGroup { ACTION, MODE }; - -enum class PaletteToolId { - NONE, - CREATE_NOTE, - CAPTURE_REGION, - CAPTURE_SCREEN, - LASER_POINTER, - MAGNIFY, -}; - -// Usage of each pen palette option. This enum is used to back an UMA histogram -// and should be treated as append-only. -enum PaletteTrayOptions { - PALETTE_CLOSED_NO_ACTION = 0, - PALETTE_SETTINGS_BUTTON, - PALETTE_HELP_BUTTON, - PALETTE_CAPTURE_REGION, - PALETTE_CAPTURE_SCREEN, - PALETTE_NEW_NOTE, - PALETTE_MAGNIFY, - PALETTE_LASER_POINTER, - PALETTE_OPTIONS_COUNT -}; - -// Type of palette mode cancellation. This enum is used to back an UMA histogram -// and should be treated as append-only. -enum PaletteModeCancelType { - PALETTE_MODE_LASER_POINTER_CANCELLED = 0, - PALETTE_MODE_LASER_POINTER_SWITCHED, - PALETTE_MODE_MAGNIFY_CANCELLED, - PALETTE_MODE_MAGNIFY_SWITCHED, - PALETTE_MODE_CANCEL_TYPE_COUNT -}; - -// Helper functions that convert PaletteToolIds and PaletteGroups to strings. -ASH_EXPORT std::string PaletteToolIdToString(PaletteToolId tool_id); -ASH_EXPORT std::string PaletteGroupToString(PaletteGroup group); - -// Helper functions that convert PaletteToolIds to PaletteTrayOptions. -ASH_EXPORT PaletteTrayOptions -PaletteToolIdToPaletteTrayOptions(PaletteToolId tool_id); - -// Helper functions that convert PaletteToolIds to PaletteModeCancelType. -ASH_EXPORT PaletteModeCancelType -PaletteToolIdToPaletteModeCancelType(PaletteToolId tool_id, bool is_switched); - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_PALETTE_IDS_H_
diff --git a/ash/system/palette/palette_tool.cc b/ash/system/palette/palette_tool.cc deleted file mode 100644 index 74b88a0..0000000 --- a/ash/system/palette/palette_tool.cc +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/palette_tool.h" - -#include "ash/system/palette/palette_tool_manager.h" -#include "ash/system/palette/palette_utils.h" -#include "ash/system/palette/tools/capture_region_mode.h" -#include "ash/system/palette/tools/capture_screen_action.h" -#include "ash/system/palette/tools/create_note_action.h" -#include "ash/system/palette/tools/laser_pointer_mode.h" -#include "ash/system/palette/tools/magnifier_mode.h" -#include "base/memory/ptr_util.h" -#include "ui/gfx/paint_vector_icon.h" - -namespace ash { - -// static -void PaletteTool::RegisterToolInstances(PaletteToolManager* tool_manager) { - tool_manager->AddTool(base::MakeUnique<CaptureRegionMode>(tool_manager)); - tool_manager->AddTool(base::MakeUnique<CaptureScreenAction>(tool_manager)); - tool_manager->AddTool(base::MakeUnique<CreateNoteAction>(tool_manager)); - tool_manager->AddTool(base::MakeUnique<LaserPointerMode>(tool_manager)); - tool_manager->AddTool(base::MakeUnique<MagnifierMode>(tool_manager)); -} - -PaletteTool::PaletteTool(Delegate* delegate) : delegate_(delegate) {} - -PaletteTool::~PaletteTool() {} - -void PaletteTool::OnEnable() { - enabled_ = true; -} - -void PaletteTool::OnDisable() { - enabled_ = false; -} - -const gfx::VectorIcon& PaletteTool::GetActiveTrayIcon() const { - return gfx::kNoneIcon; -} - -} // namespace ash
diff --git a/ash/system/palette/palette_tool.h b/ash/system/palette/palette_tool.h deleted file mode 100644 index c1f1311e..0000000 --- a/ash/system/palette/palette_tool.h +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_PALETTE_TOOL_H_ -#define ASH_SYSTEM_PALETTE_PALETTE_TOOL_H_ - -#include <map> -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/system/palette/palette_ids.h" -#include "base/callback.h" -#include "base/macros.h" -#include "ui/gfx/vector_icon_types.h" - -namespace gfx { -struct VectorIcon; -} - -namespace views { -class View; -} - -namespace ash { - -class WmWindow; - -enum class PaletteGroup; -enum class PaletteToolId; -class PaletteToolManager; - -// A PaletteTool is a generalized action inside of the palette menu in the -// shelf. Only one tool per group is active at any given time. When the tool is -// active, it should be showing some specializied UI. The tool is no longer -// active if it completes its action, if the user selects another tool with the -// same group, or if the user just cancels the action from the palette. -class ASH_EXPORT PaletteTool { - public: - class Delegate { - public: - Delegate() {} - virtual ~Delegate() {} - - // Enable or disable a specific tool. - virtual void EnableTool(PaletteToolId tool_id) = 0; - virtual void DisableTool(PaletteToolId tool_id) = 0; - - // Hide the entire palette. This should not change any tool state. - virtual void HidePalette() = 0; - - // Hide the entire palette without showing a hide animation. - virtual void HidePaletteImmediately() = 0; - - // Returns the root window. - virtual WmWindow* GetWindow() = 0; - - // Record usage of each pen palette option. - virtual void RecordPaletteOptionsUsage(PaletteTrayOptions option) = 0; - - // Record mode cancellation of pen palette. - virtual void RecordPaletteModeCancellation(PaletteModeCancelType type) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Delegate); - }; - - // Adds all available PaletteTool instances to the tool_manager. - static void RegisterToolInstances(PaletteToolManager* tool_manager); - - // |delegate| must outlive this tool instance. - explicit PaletteTool(Delegate* delegate); - virtual ~PaletteTool(); - - // The group this tool belongs to. Only one tool per group can be active at - // any given time. - virtual PaletteGroup GetGroup() const = 0; - - // The unique identifier for this tool. This should be the only tool that ever - // has this ID. - virtual PaletteToolId GetToolId() const = 0; - - // Called when the user activates the tool. Only one tool per group can be - // active at any given time. - virtual void OnEnable(); - - // Disable the tool, either because this tool called DisableSelf(), the - // user cancelled the tool, or the user activated another tool within the - // same group. - virtual void OnDisable(); - - // Create a view that will be used in the palette, or nullptr if this tool - // should not be displayed. The view is owned by the caller. OnViewDestroyed - // is called when the view has been deallocated by its owner. - virtual views::View* CreateView() = 0; - virtual void OnViewDestroyed() = 0; - - // Returns an icon to use in the tray if this tool is active. Only one tool - // (per-group) should ever have an active icon at any given time. - virtual const gfx::VectorIcon& GetActiveTrayIcon() const; - - protected: - // Enables/disables the tool. - bool enabled() const { return enabled_; } - - Delegate* delegate() { return delegate_; } - - private: - bool enabled_ = false; - - // Unowned pointer to the delegate. The delegate should outlive this instance. - Delegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(PaletteTool); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_PALETTE_TOOL_H_
diff --git a/ash/system/palette/palette_tool_manager.cc b/ash/system/palette/palette_tool_manager.cc deleted file mode 100644 index 88670a1..0000000 --- a/ash/system/palette/palette_tool_manager.cc +++ /dev/null
@@ -1,153 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/palette_tool_manager.h" - -#include <algorithm> - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/palette/palette_tool.h" -#include "base/bind.h" -#include "base/metrics/histogram_macros.h" - -namespace ash { - -PaletteToolManager::PaletteToolManager(Delegate* delegate) - : delegate_(delegate) { - DCHECK(delegate_); -} - -PaletteToolManager::~PaletteToolManager() {} - -void PaletteToolManager::AddTool(std::unique_ptr<PaletteTool> tool) { - // The same PaletteToolId cannot be registered twice. - DCHECK_EQ(0, std::count_if(tools_.begin(), tools_.end(), - [&tool](const std::unique_ptr<PaletteTool>& t) { - return t->GetToolId() == tool->GetToolId(); - })); - - tools_.emplace_back(std::move(tool)); -} - -void PaletteToolManager::ActivateTool(PaletteToolId tool_id) { - PaletteTool* new_tool = FindToolById(tool_id); - DCHECK(new_tool); - - PaletteTool* previous_tool = active_tools_[new_tool->GetGroup()]; - - if (new_tool == previous_tool) - return; - - if (previous_tool) { - previous_tool->OnDisable(); - RecordPaletteModeCancellation(PaletteToolIdToPaletteModeCancelType( - previous_tool->GetToolId(), true /*is_switched*/)); - } - - active_tools_[new_tool->GetGroup()] = new_tool; - new_tool->OnEnable(); - - delegate_->OnActiveToolChanged(); -} - -void PaletteToolManager::DeactivateTool(PaletteToolId tool_id) { - PaletteTool* tool = FindToolById(tool_id); - DCHECK(tool); - - active_tools_[tool->GetGroup()] = nullptr; - tool->OnDisable(); - - delegate_->OnActiveToolChanged(); -} - -bool PaletteToolManager::IsToolActive(PaletteToolId tool_id) { - PaletteTool* tool = FindToolById(tool_id); - DCHECK(tool); - - return active_tools_[tool->GetGroup()] == tool; -} - -PaletteToolId PaletteToolManager::GetActiveTool(PaletteGroup group) { - PaletteTool* active_tool = active_tools_[group]; - return active_tool ? active_tool->GetToolId() : PaletteToolId::NONE; -} - -const gfx::VectorIcon& PaletteToolManager::GetActiveTrayIcon( - PaletteToolId tool_id) const { - PaletteTool* tool = FindToolById(tool_id); - if (!tool) - return kPaletteTrayIconDefaultIcon; - - return tool->GetActiveTrayIcon(); -} - -std::vector<PaletteToolView> PaletteToolManager::CreateViews() { - std::vector<PaletteToolView> views; - views.reserve(tools_.size()); - - for (size_t i = 0; i < tools_.size(); ++i) { - views::View* tool_view = tools_[i]->CreateView(); - if (!tool_view) - continue; - - PaletteToolView view; - view.group = tools_[i]->GetGroup(); - view.tool_id = tools_[i]->GetToolId(); - view.view = tool_view; - views.push_back(view); - } - - return views; -} - -void PaletteToolManager::NotifyViewsDestroyed() { - for (std::unique_ptr<PaletteTool>& tool : tools_) - tool->OnViewDestroyed(); -} - -void PaletteToolManager::DisableActiveTool(PaletteGroup group) { - PaletteToolId tool_id = GetActiveTool(group); - if (tool_id != PaletteToolId::NONE) - DeactivateTool(tool_id); -} - -void PaletteToolManager::EnableTool(PaletteToolId tool_id) { - ActivateTool(tool_id); -} - -void PaletteToolManager::DisableTool(PaletteToolId tool_id) { - DeactivateTool(tool_id); -} - -void PaletteToolManager::HidePalette() { - delegate_->HidePalette(); -} - -void PaletteToolManager::HidePaletteImmediately() { - delegate_->HidePaletteImmediately(); -} - -WmWindow* PaletteToolManager::GetWindow() { - return delegate_->GetWindow(); -} - -void PaletteToolManager::RecordPaletteOptionsUsage(PaletteTrayOptions option) { - return delegate_->RecordPaletteOptionsUsage(option); -} - -void PaletteToolManager::RecordPaletteModeCancellation( - PaletteModeCancelType type) { - return delegate_->RecordPaletteModeCancellation(type); -} - -PaletteTool* PaletteToolManager::FindToolById(PaletteToolId tool_id) const { - for (const std::unique_ptr<PaletteTool>& tool : tools_) { - if (tool->GetToolId() == tool_id) - return tool.get(); - } - - return nullptr; -} - -} // namespace ash
diff --git a/ash/system/palette/palette_tool_manager.h b/ash/system/palette/palette_tool_manager.h deleted file mode 100644 index a78451b9..0000000 --- a/ash/system/palette/palette_tool_manager.h +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_PALETTE_TOOL_MANAGER_H_ -#define ASH_SYSTEM_PALETTE_PALETTE_TOOL_MANAGER_H_ - -#include <map> -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/system/palette/palette_ids.h" -#include "ash/system/palette/palette_tool.h" -#include "base/callback.h" -#include "base/macros.h" - -namespace views { -class View; -} - -namespace ash { - -class PaletteTool; -enum class PaletteGroup; -enum class PaletteToolId; -class WmWindow; - -struct ASH_EXPORT PaletteToolView { - PaletteGroup group; - PaletteToolId tool_id; - views::View* view; -}; - -class ASH_EXPORT PaletteToolManager : public PaletteTool::Delegate { - public: - class Delegate { - public: - Delegate() {} - virtual ~Delegate() {} - - // Hide the palette (if shown). - virtual void HidePalette() = 0; - - // Hide the palette immediately, ie, do not display a hide animation. - virtual void HidePaletteImmediately() = 0; - - // Called when the active tool has changed. - virtual void OnActiveToolChanged() = 0; - - // Return the window associated with this palette. - virtual WmWindow* GetWindow() = 0; - - // Record usage of each pen palette option. - virtual void RecordPaletteOptionsUsage(ash::PaletteTrayOptions option) = 0; - - // Record mode cancellation of pen palette. - virtual void RecordPaletteModeCancellation(PaletteModeCancelType type) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(Delegate); - }; - - // Creates the tool manager. - PaletteToolManager(Delegate* delegate); - ~PaletteToolManager() override; - - // Adds the given |tool| to the tool manager. The tool is assumed to be in a - // deactivated state. This class takes ownership over |tool|. - void AddTool(std::unique_ptr<PaletteTool> tool); - - // Activates tool_id and deactivates any other active tool in the same - // group as tool_id. - void ActivateTool(PaletteToolId tool_id); - - // Deactivates the given tool. - void DeactivateTool(PaletteToolId tool_id); - - // Returns true if the given tool is active. - bool IsToolActive(PaletteToolId tool_id); - - // Returns the active tool for the given group. - PaletteToolId GetActiveTool(PaletteGroup group); - - // Fetch the active tray icon for the given tool. Returns - // gfx::VectorIconId::VECTOR_ICON_NONE if not available. - const gfx::VectorIcon& GetActiveTrayIcon(PaletteToolId tool_id) const; - - // Create views for all of the registered tools. - std::vector<PaletteToolView> CreateViews(); - - // Called when the views returned by CreateViews have been destroyed. This - // should clear any (now) stale references. - void NotifyViewsDestroyed(); - - // Helper method to disable any active tool in the given |group|. - void DisableActiveTool(PaletteGroup group); - - private: - // PaleteTool::Delegate overrides. - void EnableTool(PaletteToolId tool_id) override; - void DisableTool(PaletteToolId tool_id) override; - void HidePalette() override; - void HidePaletteImmediately() override; - WmWindow* GetWindow() override; - void RecordPaletteOptionsUsage(ash::PaletteTrayOptions option) override; - void RecordPaletteModeCancellation(PaletteModeCancelType type) override; - - PaletteTool* FindToolById(PaletteToolId tool_id) const; - - // Unowned pointer to the delegate to provide external functionality. - Delegate* delegate_; - - // Unowned pointer to the active tool / group. - std::map<PaletteGroup, PaletteTool*> active_tools_; - - // Owned list of all tools. - std::vector<std::unique_ptr<PaletteTool>> tools_; - - DISALLOW_COPY_AND_ASSIGN(PaletteToolManager); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_PALETTE_TOOL_MANAGER_H_
diff --git a/ash/system/palette/palette_tool_manager_unittest.cc b/ash/system/palette/palette_tool_manager_unittest.cc deleted file mode 100644 index e8eef463..0000000 --- a/ash/system/palette/palette_tool_manager_unittest.cc +++ /dev/null
@@ -1,137 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/palette_tool.h" -#include "ash/system/palette/palette_tool_manager.h" -#include "base/bind.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -using namespace ash; - -namespace { - -// A simple tool instance that exposes some additional data for testing. -class TestTool : public PaletteTool { - public: - TestTool(Delegate* delegate, PaletteGroup group, PaletteToolId tool_id) - : PaletteTool(delegate), group_(group), tool_id_(tool_id) {} - - // PaletteTool: - PaletteGroup GetGroup() const override { return group_; } - PaletteToolId GetToolId() const override { return tool_id_; } - - // Shadows the parent declaration since PaletteTool::enabled is not virtual. - bool enabled() const { return PaletteTool::enabled(); } - - private: - // PaletteTool: - views::View* CreateView() override { - NOTREACHED(); - return nullptr; - } - void OnViewDestroyed() override { FAIL(); } - - PaletteGroup group_; - PaletteToolId tool_id_; - - DISALLOW_COPY_AND_ASSIGN(TestTool); -}; - -// Base class for tool manager unittests. -class PaletteToolManagerTest : public ::testing::Test, - public PaletteToolManager::Delegate, - public PaletteTool::Delegate { - public: - PaletteToolManagerTest() - : palette_tool_manager_(new PaletteToolManager(this)) {} - ~PaletteToolManagerTest() override {} - - protected: - // PaletteToolManager::Delegate: - void HidePalette() override {} - void HidePaletteImmediately() override {} - void OnActiveToolChanged() override { ++tool_changed_count_; } - WmWindow* GetWindow() override { - NOTREACHED(); - return nullptr; - } - void RecordPaletteOptionsUsage(PaletteTrayOptions option) override {} - void RecordPaletteModeCancellation(PaletteModeCancelType type) override {} - - // PaletteTool::Delegate: - void EnableTool(PaletteToolId tool_id) override {} - void DisableTool(PaletteToolId tool_id) override {} - - // Helper method for returning an unowned pointer to the constructed tool - // while also adding it to the PaletteToolManager. - TestTool* BuildTool(PaletteGroup group, PaletteToolId tool_id) { - auto* tool = new TestTool(this, group, tool_id); - palette_tool_manager_->AddTool(base::WrapUnique(tool)); - return tool; - } - - int tool_changed_count_ = 0; - std::unique_ptr<PaletteToolManager> palette_tool_manager_; - - private: - DISALLOW_COPY_AND_ASSIGN(PaletteToolManagerTest); -}; - -} // namespace - -// Verifies that tools can be enabled/disabled and that enabling a tool disables -// only active tools in the same group. -TEST_F(PaletteToolManagerTest, MultipleToolsActivateDeactivate) { - // Register actions/modes. - TestTool* action_1 = - BuildTool(PaletteGroup::ACTION, PaletteToolId::CREATE_NOTE); - TestTool* action_2 = - BuildTool(PaletteGroup::ACTION, PaletteToolId::CAPTURE_REGION); - TestTool* mode_1 = BuildTool(PaletteGroup::MODE, PaletteToolId::MAGNIFY); - TestTool* mode_2 = - BuildTool(PaletteGroup::MODE, PaletteToolId::LASER_POINTER); - - // Enable mode 1. - EXPECT_EQ(0, tool_changed_count_); - palette_tool_manager_->ActivateTool(mode_1->GetToolId()); - EXPECT_FALSE(action_1->enabled()); - EXPECT_FALSE(action_2->enabled()); - EXPECT_TRUE(mode_1->enabled()); - EXPECT_FALSE(mode_2->enabled()); - - // Turn a single action on/off. Enabling/disabling the tool does not change - // any other group's state. - palette_tool_manager_->ActivateTool(action_1->GetToolId()); - EXPECT_TRUE(action_1->enabled()); - EXPECT_FALSE(action_2->enabled()); - EXPECT_TRUE(mode_1->enabled()); - EXPECT_FALSE(mode_2->enabled()); - palette_tool_manager_->DeactivateTool(action_1->GetToolId()); - EXPECT_FALSE(action_1->enabled()); - EXPECT_FALSE(action_2->enabled()); - EXPECT_TRUE(mode_1->enabled()); - EXPECT_FALSE(mode_2->enabled()); - - // Activating a tool on will deactivate any other active tools in the same - // group. - palette_tool_manager_->ActivateTool(action_1->GetToolId()); - EXPECT_TRUE(action_1->enabled()); - EXPECT_FALSE(action_2->enabled()); - palette_tool_manager_->ActivateTool(action_2->GetToolId()); - EXPECT_FALSE(action_1->enabled()); - EXPECT_TRUE(action_2->enabled()); - palette_tool_manager_->DeactivateTool(action_2->GetToolId()); - - // Activating an already active tool will not do anything. - palette_tool_manager_->ActivateTool(action_1->GetToolId()); - EXPECT_TRUE(action_1->enabled()); - EXPECT_FALSE(action_2->enabled()); - palette_tool_manager_->ActivateTool(action_1->GetToolId()); - EXPECT_TRUE(action_1->enabled()); - EXPECT_FALSE(action_2->enabled()); - palette_tool_manager_->DeactivateTool(action_1->GetToolId()); -}
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc deleted file mode 100644 index 2d176f6..0000000 --- a/ash/system/palette/palette_tray.cc +++ /dev/null
@@ -1,437 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/palette_tray.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/palette/palette_tool_manager.h" -#include "ash/system/palette/palette_utils.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_bubble_wrapper.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_header_button.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "base/metrics/histogram_macros.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/events/devices/input_device_manager.h" -#include "ui/events/devices/stylus_state.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -namespace { - -// Padding for tray icon (dp; the button that shows the palette menu). -constexpr int kTrayIconMainAxisInset = 8; -constexpr int kTrayIconCrossAxisInset = 0; - -// Width of the palette itself (dp). -constexpr int kPaletteWidth = 332; - -// Padding at the top/bottom of the palette (dp). -constexpr int kPalettePaddingOnTop = 4; -constexpr int kPalettePaddingOnBottom = 2; - -// Margins between the title view and the edges around it (dp). -constexpr int kPaddingBetweenTitleAndLeftEdge = 12; -constexpr int kPaddingBetweenTitleAndSeparator = 3; - -// Color of the separator. -const SkColor kPaletteSeparatorColor = SkColorSetARGB(0x1E, 0x00, 0x00, 0x00); - -// Returns true if we are in a user session that can show the stylus tools. -bool IsInUserSession() { - SessionStateDelegate* session_state_delegate = - WmShell::Get()->GetSessionStateDelegate(); - return !session_state_delegate->IsUserSessionBlocked() && - session_state_delegate->GetSessionState() == - session_manager::SessionState::ACTIVE && - WmShell::Get()->system_tray_delegate()->GetUserLoginStatus() != - LoginStatus::KIOSK_APP; -} - -class TitleView : public views::View, public views::ButtonListener { - public: - explicit TitleView(PaletteTray* palette_tray) : palette_tray_(palette_tray) { - // TODO(tdanderson|jdufault): Use TriView to handle the layout of the title. - // See crbug.com/614453. - auto* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - SetLayoutManager(box_layout); - - auto* title_label = - new views::Label(l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_TITLE)); - title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - AddChildView(title_label); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); - style.SetupLabel(title_label); - box_layout->SetFlexForView(title_label, 1); - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - help_button_ = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); - settings_button_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, - IDS_ASH_PALETTE_SETTINGS); - } else { - gfx::ImageSkia help_icon = - gfx::CreateVectorIcon(kSystemMenuHelpIcon, kMenuIconColor); - gfx::ImageSkia settings_icon = - gfx::CreateVectorIcon(kSystemMenuSettingsIcon, kMenuIconColor); - - auto* help_button = new ash::TrayPopupHeaderButton( - this, help_icon, IDS_ASH_STATUS_TRAY_HELP); - help_button->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HELP)); - help_button_ = help_button; - - auto* settings_button = new ash::TrayPopupHeaderButton( - this, settings_icon, IDS_ASH_STATUS_TRAY_SETTINGS); - settings_button->SetTooltipText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SETTINGS)); - settings_button_ = settings_button; - } - - AddChildView(help_button_); - AddChildView(settings_button_); - } - - ~TitleView() override {} - - private: - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override { - if (sender == settings_button_) { - palette_tray_->RecordPaletteOptionsUsage( - PaletteTrayOptions::PALETTE_SETTINGS_BUTTON); - WmShell::Get()->system_tray_controller()->ShowPaletteSettings(); - palette_tray_->HidePalette(); - } else if (sender == help_button_) { - palette_tray_->RecordPaletteOptionsUsage( - PaletteTrayOptions::PALETTE_HELP_BUTTON); - WmShell::Get()->system_tray_controller()->ShowPaletteHelp(); - palette_tray_->HidePalette(); - } else { - NOTREACHED(); - } - } - - // Unowned pointers to button views so we can determine which button was - // clicked. - views::View* settings_button_; - views::View* help_button_; - PaletteTray* palette_tray_; - - DISALLOW_COPY_AND_ASSIGN(TitleView); -}; - -} // namespace - -PaletteTray::PaletteTray(WmShelf* wm_shelf) - : TrayBackgroundView(wm_shelf), - palette_tool_manager_(new PaletteToolManager(this)), - weak_factory_(this) { - PaletteTool::RegisterToolInstances(palette_tool_manager_.get()); - - if (MaterialDesignController::IsShelfMaterial()) { - SetInkDropMode(InkDropMode::ON); - SetContentsBackground(false); - } else { - SetContentsBackground(true); - } - - SetLayoutManager(new views::FillLayout()); - icon_ = new views::ImageView(); - UpdateTrayIcon(); - - tray_container()->SetMargin(kTrayIconMainAxisInset, kTrayIconCrossAxisInset); - tray_container()->AddChildView(icon_); - - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->GetSessionStateDelegate()->AddSessionStateObserver(this); - ui::InputDeviceManager::GetInstance()->AddObserver(this); -} - -PaletteTray::~PaletteTray() { - if (bubble_) - bubble_->bubble_view()->reset_delegate(); - - ui::InputDeviceManager::GetInstance()->RemoveObserver(this); - WmShell::Get()->RemoveShellObserver(this); - WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); -} - -bool PaletteTray::PerformAction(const ui::Event& event) { - if (bubble_) { - if (num_actions_in_bubble_ == 0) - RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION); - HidePalette(); - return true; - } - - return ShowPalette(); -} - -bool PaletteTray::ShowPalette() { - if (bubble_) - return false; - - DCHECK(tray_container()); - - views::TrayBubbleView::InitParams init_params(GetAnchorAlignment(), - kPaletteWidth, kPaletteWidth); - init_params.can_activate = true; - init_params.close_on_deactivate = true; - - DCHECK(tray_container()); - - // The views::TrayBubbleView ctor will cause a shelf auto hide update check. - // Make sure to block auto hiding before that check happens. - should_block_shelf_auto_hide_ = true; - - // TODO(tdanderson): Refactor into common row layout code. - // TODO(tdanderson|jdufault): Add material design ripple effects to the menu - // rows. - - // Create and customize bubble view. - views::TrayBubbleView* bubble_view = - views::TrayBubbleView::Create(GetBubbleAnchor(), this, &init_params); - bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets()); - bubble_view->set_margins( - gfx::Insets(kPalettePaddingOnTop, 0, kPalettePaddingOnBottom, 0)); - - // Add title. - auto* title_view = new TitleView(this); - title_view->SetBorder(views::CreateEmptyBorder( - gfx::Insets(0, kPaddingBetweenTitleAndLeftEdge, 0, 0))); - bubble_view->AddChildView(title_view); - - // Add horizontal separator. - views::Separator* separator = new views::Separator(); - separator->SetColor(kPaletteSeparatorColor); - separator->SetBorder(views::CreateEmptyBorder(gfx::Insets( - kPaddingBetweenTitleAndSeparator, 0, kMenuSeparatorVerticalPadding, 0))); - bubble_view->AddChildView(separator); - - // Add palette tools. - // TODO(tdanderson|jdufault): Use SystemMenuButton to get the material design - // ripples. - std::vector<PaletteToolView> views = palette_tool_manager_->CreateViews(); - for (const PaletteToolView& view : views) - bubble_view->AddChildView(view.view); - - // Show the bubble. - bubble_.reset(new ash::TrayBubbleWrapper(this, bubble_view)); - SetIsActive(true); - return true; -} - -bool PaletteTray::ContainsPointInScreen(const gfx::Point& point) { - if (icon_ && icon_->GetBoundsInScreen().Contains(point)) - return true; - - return bubble_ && bubble_->bubble_view()->GetBoundsInScreen().Contains(point); -} - -void PaletteTray::SessionStateChanged(session_manager::SessionState state) { - UpdateIconVisibility(); -} - -void PaletteTray::OnLockStateChanged(bool locked) { - UpdateIconVisibility(); - - // The user can eject the stylus during the lock screen transition, which will - // open the palette. Make sure to close it if that happens. - if (locked) - HidePalette(); -} - -void PaletteTray::ClickedOutsideBubble() { - if (num_actions_in_bubble_ == 0) - RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION); - HidePalette(); -} - -base::string16 PaletteTray::GetAccessibleNameForTray() { - return l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_TITLE); -} - -void PaletteTray::HideBubbleWithView(const views::TrayBubbleView* bubble_view) { - if (bubble_->bubble_view() == bubble_view) - HidePalette(); -} - -void PaletteTray::OnTouchscreenDeviceConfigurationChanged() { - UpdateIconVisibility(); -} - -void PaletteTray::OnStylusStateChanged(ui::StylusState stylus_state) { - PaletteDelegate* palette_delegate = WmShell::Get()->palette_delegate(); - - // Don't do anything if the palette should not be shown or if the user has - // disabled it all-together. - if (!IsInUserSession() || !palette_delegate->ShouldShowPalette()) - return; - - // Auto show/hide the palette if allowed by the user. - if (palette_delegate->ShouldAutoOpenPalette()) { - if (stylus_state == ui::StylusState::REMOVED && !bubble_) { - is_bubble_auto_opened_ = true; - ShowPalette(); - } else if (stylus_state == ui::StylusState::INSERTED && bubble_) { - HidePalette(); - } - } - - // Disable any active modes if the stylus has been inserted. - if (stylus_state == ui::StylusState::INSERTED) - palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); -} - -void PaletteTray::BubbleViewDestroyed() { - palette_tool_manager_->NotifyViewsDestroyed(); - SetIsActive(false); -} - -void PaletteTray::OnMouseEnteredView() {} - -void PaletteTray::OnMouseExitedView() {} - -base::string16 PaletteTray::GetAccessibleNameForBubble() { - return GetAccessibleNameForTray(); -} - -void PaletteTray::OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const { - // Place the bubble in the same root window as |anchor_widget|. - WmWindow::Get(anchor_widget->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - bubble_widget, kShellWindowId_SettingBubbleContainer, params); -} - -void PaletteTray::HideBubble(const views::TrayBubbleView* bubble_view) { - HideBubbleWithView(bubble_view); -} - -void PaletteTray::HidePalette() { - should_block_shelf_auto_hide_ = false; - is_bubble_auto_opened_ = false; - num_actions_in_bubble_ = 0; - bubble_.reset(); - - shelf()->UpdateAutoHideState(); -} - -void PaletteTray::HidePaletteImmediately() { - if (bubble_) - bubble_->bubble_widget()->SetVisibilityChangedAnimationsEnabled(false); - HidePalette(); -} - -void PaletteTray::RecordPaletteOptionsUsage(PaletteTrayOptions option) { - DCHECK_NE(option, PaletteTrayOptions::PALETTE_OPTIONS_COUNT); - - if (is_bubble_auto_opened_) { - UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Usage.AutoOpened", option, - PaletteTrayOptions::PALETTE_OPTIONS_COUNT); - } else { - UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Usage", option, - PaletteTrayOptions::PALETTE_OPTIONS_COUNT); - } -} - -void PaletteTray::RecordPaletteModeCancellation(PaletteModeCancelType type) { - if (type == PaletteModeCancelType::PALETTE_MODE_CANCEL_TYPE_COUNT) - return; - - UMA_HISTOGRAM_ENUMERATION( - "Ash.Shelf.Palette.ModeCancellation", type, - PaletteModeCancelType::PALETTE_MODE_CANCEL_TYPE_COUNT); -} - -bool PaletteTray::ShouldBlockShelfAutoHide() const { - return should_block_shelf_auto_hide_; -} - -void PaletteTray::OnActiveToolChanged() { - ++num_actions_in_bubble_; - UpdateTrayIcon(); -} - -WmWindow* PaletteTray::GetWindow() { - return shelf()->GetWindow(); -} - -void PaletteTray::SetShelfAlignment(ShelfAlignment alignment) { - if (alignment == shelf_alignment()) - return; - - TrayBackgroundView::SetShelfAlignment(alignment); -} - -void PaletteTray::AnchorUpdated() { - if (bubble_) - bubble_->bubble_view()->UpdateBubble(); -} - -void PaletteTray::Initialize() { - PaletteDelegate* delegate = WmShell::Get()->palette_delegate(); - // |delegate| can be null in tests. - if (!delegate) - return; - - // OnPaletteEnabledPrefChanged will get called with the initial pref value, - // which will take care of showing the palette. - palette_enabled_subscription_ = delegate->AddPaletteEnableListener(base::Bind( - &PaletteTray::OnPaletteEnabledPrefChanged, weak_factory_.GetWeakPtr())); -} - -void PaletteTray::UpdateTrayIcon() { - icon_->SetImage(CreateVectorIcon( - palette_tool_manager_->GetActiveTrayIcon( - palette_tool_manager_->GetActiveTool(ash::PaletteGroup::MODE)), - kTrayIconSize, kShelfIconColor)); -} - -void PaletteTray::OnPaletteEnabledPrefChanged(bool enabled) { - is_palette_enabled_ = enabled; - - if (!enabled) { - SetVisible(false); - palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); - } else { - UpdateIconVisibility(); - } -} - -void PaletteTray::UpdateIconVisibility() { - SetVisible(is_palette_enabled_ && palette_utils::HasStylusInput() && - IsInUserSession()); -} - -} // namespace ash
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h deleted file mode 100644 index f3b22fb..0000000 --- a/ash/system/palette/palette_tray.h +++ /dev/null
@@ -1,144 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_PALETTE_TRAY_H_ -#define ASH_SYSTEM_PALETTE_PALETTE_TRAY_H_ - -#include <map> -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/palette_delegate.h" -#include "ash/common/session/session_state_observer.h" -#include "ash/common/shell_observer.h" -#include "ash/system/palette/palette_tool_manager.h" -#include "ash/system/tray/tray_background_view.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "ui/events/devices/input_device_event_observer.h" - -namespace gfx { -class Point; -} - -namespace views { -class ImageView; -class Widget; -} - -namespace ash { - -class TrayBubbleWrapper; -class PaletteToolManager; - -// The PaletteTray shows the palette in the bottom area of the screen. This -// class also controls the lifetime for all of the tools available in the -// palette. -class ASH_EXPORT PaletteTray : public TrayBackgroundView, - public SessionStateObserver, - public ShellObserver, - public PaletteToolManager::Delegate, - public ui::InputDeviceEventObserver, - public views::TrayBubbleView::Delegate { - public: - explicit PaletteTray(WmShelf* wm_shelf); - ~PaletteTray() override; - - // ActionableView: - bool PerformAction(const ui::Event& event) override; - - // SessionStateObserver: - void SessionStateChanged(session_manager::SessionState state) override; - - // ShellObserver: - void OnLockStateChanged(bool locked) override; - - // TrayBackgroundView: - void ClickedOutsideBubble() override; - base::string16 GetAccessibleNameForTray() override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void SetShelfAlignment(ShelfAlignment alignment) override; - void AnchorUpdated() override; - void Initialize() override; - - // PaletteToolManager::Delegate: - void HidePalette() override; - void HidePaletteImmediately() override; - void RecordPaletteOptionsUsage(PaletteTrayOptions option) override; - void RecordPaletteModeCancellation(PaletteModeCancelType type) override; - - // Returns true if the shelf should not autohide. - bool ShouldBlockShelfAutoHide() const; - - // Opens up the palette if it is not already open. Returns true if the palette - // was opened. - bool ShowPalette(); - - // Returns true if the palette tray contains the given point. This is useful - // for determining if an event should be propagated through to the palette. - bool ContainsPointInScreen(const gfx::Point& point); - - private: - // ui::InputDeviceObserver: - void OnTouchscreenDeviceConfigurationChanged() override; - void OnStylusStateChanged(ui::StylusState stylus_state) override; - - // views::TrayBubbleView::Delegate: - void BubbleViewDestroyed() override; - void OnMouseEnteredView() override; - void OnMouseExitedView() override; - base::string16 GetAccessibleNameForBubble() override; - void OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const override; - void HideBubble(const views::TrayBubbleView* bubble_view) override; - - // PaletteToolManager::Delegate: - void OnActiveToolChanged() override; - WmWindow* GetWindow() override; - - // Updates the tray icon from the palette tool manager. - void UpdateTrayIcon(); - - // Sets the icon to visible if the palette can be used. - void UpdateIconVisibility(); - - // Called when the palette enabled pref has changed. - void OnPaletteEnabledPrefChanged(bool enabled); - - std::unique_ptr<PaletteToolManager> palette_tool_manager_; - std::unique_ptr<TrayBubbleWrapper> bubble_; - - // Manages the callback OnPaletteEnabledPrefChanged callback registered to - // the PaletteDelegate instance. - std::unique_ptr<PaletteDelegate::EnableListenerSubscription> - palette_enabled_subscription_; - - // Weak pointer, will be parented by TrayContainer for its lifetime. - views::ImageView* icon_; - - // The shelf auto-hide state is checked during the tray constructor, so we - // have to use a helper variable instead of just checking if we have a tray - // instance. - bool should_block_shelf_auto_hide_ = false; - - // Cached palette enabled/disabled pref value. - bool is_palette_enabled_ = true; - - // Used to indicate whether the palette bubble is automatically opened by a - // stylus eject event. - bool is_bubble_auto_opened_ = false; - - // Number of actions in pen palette bubble. - int num_actions_in_bubble_ = 0; - - base::WeakPtrFactory<PaletteTray> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PaletteTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_PALETTE_TRAY_H_
diff --git a/ash/system/palette/palette_utils.cc b/ash/system/palette/palette_utils.cc deleted file mode 100644 index 20320fa1..0000000 --- a/ash/system/palette/palette_utils.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/palette_utils.h" - -#include "ash/common/ash_switches.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/palette/palette_tray.h" -#include "ash/system/status_area_widget.h" -#include "base/command_line.h" -#include "ui/events/devices/input_device_manager.h" -#include "ui/events/devices/touchscreen_device.h" -#include "ui/gfx/geometry/point.h" - -namespace ash { -namespace palette_utils { - -bool HasStylusInput() { - // Allow the user to force-enable by passing a switch. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshForceEnablePalette)) { - return true; - } - - for (const ui::TouchscreenDevice& device : - ui::InputDeviceManager::GetInstance()->GetTouchscreenDevices()) { - if (device.is_stylus && - device.type == ui::InputDeviceType::INPUT_DEVICE_INTERNAL) { - return true; - } - } - - return false; -} - -bool IsPaletteEnabledOnEveryDisplay() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshEnablePaletteOnAllDisplays); -} - -bool PaletteContainsPointInScreen(const gfx::Point& point) { - for (WmWindow* window : WmShell::Get()->GetAllRootWindows()) { - PaletteTray* palette_tray = - WmShelf::ForWindow(window)->GetStatusAreaWidget()->palette_tray(); - if (palette_tray && palette_tray->ContainsPointInScreen(point)) - return true; - } - - return false; -} - -} // namespace palette_utils -} // namespace ash
diff --git a/ash/system/palette/palette_utils.h b/ash/system/palette/palette_utils.h deleted file mode 100644 index 1137f90..0000000 --- a/ash/system/palette/palette_utils.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_PALETTE_UTILS_H_ -#define ASH_SYSTEM_PALETTE_PALETTE_UTILS_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Point; -} - -namespace ash { -namespace palette_utils { - -// Returns true if there is a stylus input device on the internal display. This -// will return false even if there is a stylus input device until hardware -// probing is complete (see ui::InputDeviceEventObserver). -ASH_EXPORT bool HasStylusInput(); - -// Returns true if the palette should be shown on every display. -ASH_EXPORT bool IsPaletteEnabledOnEveryDisplay(); - -// Returns true if either the palette icon or the palette widget contain the -// given point (in screen space). -ASH_EXPORT bool PaletteContainsPointInScreen(const gfx::Point& point); - -} // namespace palette_utils -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_PALETTE_UTILS_H_
diff --git a/ash/system/palette/tools/capture_region_mode.cc b/ash/system/palette/tools/capture_region_mode.cc deleted file mode 100644 index d0b6ac3..0000000 --- a/ash/system/palette/tools/capture_region_mode.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/tools/capture_region_mode.h" - -#include "ash/accelerators/accelerator_controller.h" -#include "ash/common/palette_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/palette/palette_ids.h" -#include "ash/system/toast/toast_data.h" -#include "ash/system/toast/toast_manager.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -namespace { - -const char kToastId[] = "palette_capture_region"; -const int kToastDurationMs = 2500; - -} // namespace - -CaptureRegionMode::CaptureRegionMode(Delegate* delegate) - : CommonPaletteTool(delegate), weak_factory_(this) {} - -CaptureRegionMode::~CaptureRegionMode() {} - -PaletteGroup CaptureRegionMode::GetGroup() const { - return PaletteGroup::MODE; -} - -PaletteToolId CaptureRegionMode::GetToolId() const { - return PaletteToolId::CAPTURE_REGION; -} - -const gfx::VectorIcon& CaptureRegionMode::GetActiveTrayIcon() const { - return kPaletteTrayIconCaptureRegionIcon; -} - -void CaptureRegionMode::OnEnable() { - CommonPaletteTool::OnEnable(); - - ToastData toast(kToastId, l10n_util::GetStringUTF16( - IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_TOAST), - kToastDurationMs, base::Optional<base::string16>()); - ash::WmShell::Get()->toast_manager()->Show(toast); - - WmShell::Get()->palette_delegate()->TakePartialScreenshot(base::Bind( - &CaptureRegionMode::OnScreenshotDone, weak_factory_.GetWeakPtr())); - delegate()->HidePalette(); -} - -void CaptureRegionMode::OnDisable() { - CommonPaletteTool::OnDisable(); - - // If the user manually cancelled the action we need to make sure to cancel - // the screenshot session as well. - WmShell::Get()->palette_delegate()->CancelPartialScreenshot(); -} - -views::View* CaptureRegionMode::CreateView() { - return CreateDefaultView( - l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_ACTION)); -} - -const gfx::VectorIcon& CaptureRegionMode::GetPaletteIcon() const { - return kPaletteActionCaptureRegionIcon; -} - -void CaptureRegionMode::OnScreenshotDone() { - // The screenshot finished, so disable the tool. - delegate()->DisableTool(GetToolId()); -} - -} // namespace ash
diff --git a/ash/system/palette/tools/capture_region_mode.h b/ash/system/palette/tools/capture_region_mode.h deleted file mode 100644 index ee6f497..0000000 --- a/ash/system/palette/tools/capture_region_mode.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_TOOLS_CAPTURE_REGION_MODE_H_ -#define ASH_SYSTEM_PALETTE_TOOLS_CAPTURE_REGION_MODE_H_ - -#include "ash/ash_export.h" -#include "ash/system/palette/common_palette_tool.h" -#include "base/memory/weak_ptr.h" - -namespace ash { - -class ASH_EXPORT CaptureRegionMode : public CommonPaletteTool { - public: - explicit CaptureRegionMode(Delegate* delegate); - ~CaptureRegionMode() override; - - private: - // PaletteTool: - PaletteGroup GetGroup() const override; - PaletteToolId GetToolId() const override; - const gfx::VectorIcon& GetActiveTrayIcon() const override; - void OnEnable() override; - void OnDisable() override; - views::View* CreateView() override; - - // CommonPaletteTool: - const gfx::VectorIcon& GetPaletteIcon() const override; - - void OnScreenshotDone(); - - base::WeakPtrFactory<CaptureRegionMode> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(CaptureRegionMode); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_TOOLS_CAPTURE_REGION_MODE_H_
diff --git a/ash/system/palette/tools/capture_screen_action.cc b/ash/system/palette/tools/capture_screen_action.cc deleted file mode 100644 index 45deba4b..0000000 --- a/ash/system/palette/tools/capture_screen_action.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/tools/capture_screen_action.h" - -#include "ash/common/palette_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/palette/palette_ids.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -CaptureScreenAction::CaptureScreenAction(Delegate* delegate) - : CommonPaletteTool(delegate) {} - -CaptureScreenAction::~CaptureScreenAction() {} - -PaletteGroup CaptureScreenAction::GetGroup() const { - return PaletteGroup::ACTION; -} - -PaletteToolId CaptureScreenAction::GetToolId() const { - return PaletteToolId::CAPTURE_SCREEN; -} - -void CaptureScreenAction::OnEnable() { - CommonPaletteTool::OnEnable(); - - delegate()->DisableTool(GetToolId()); - delegate()->HidePaletteImmediately(); - WmShell::Get()->palette_delegate()->TakeScreenshot(); -} - -views::View* CaptureScreenAction::CreateView() { - return CreateDefaultView( - l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_CAPTURE_SCREEN_ACTION)); -} - -const gfx::VectorIcon& CaptureScreenAction::GetPaletteIcon() const { - return kPaletteActionCaptureScreenIcon; -} - -} // namespace ash
diff --git a/ash/system/palette/tools/capture_screen_action.h b/ash/system/palette/tools/capture_screen_action.h deleted file mode 100644 index 6c06286..0000000 --- a/ash/system/palette/tools/capture_screen_action.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_TOOLS_CAPTURE_SCREEN_ACTION_H_ -#define ASH_SYSTEM_PALETTE_TOOLS_CAPTURE_SCREEN_ACTION_H_ - -#include "ash/ash_export.h" -#include "ash/system/palette/common_palette_tool.h" - -namespace ash { - -class ASH_EXPORT CaptureScreenAction : public CommonPaletteTool { - public: - explicit CaptureScreenAction(Delegate* delegate); - ~CaptureScreenAction() override; - - private: - // PaletteTool overrides. - PaletteGroup GetGroup() const override; - PaletteToolId GetToolId() const override; - void OnEnable() override; - views::View* CreateView() override; - - // CommonPaletteTool overrides. - const gfx::VectorIcon& GetPaletteIcon() const override; - - DISALLOW_COPY_AND_ASSIGN(CaptureScreenAction); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_TOOLS_CAPTURE_SCREEN_ACTION_H_
diff --git a/ash/system/palette/tools/create_note_action.cc b/ash/system/palette/tools/create_note_action.cc deleted file mode 100644 index 66dcfd4..0000000 --- a/ash/system/palette/tools/create_note_action.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/tools/create_note_action.h" - -#include "ash/common/palette_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/palette/palette_ids.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -CreateNoteAction::CreateNoteAction(Delegate* delegate) - : CommonPaletteTool(delegate) {} - -CreateNoteAction::~CreateNoteAction() {} - -PaletteGroup CreateNoteAction::GetGroup() const { - return PaletteGroup::ACTION; -} - -PaletteToolId CreateNoteAction::GetToolId() const { - return PaletteToolId::CREATE_NOTE; -} - -void CreateNoteAction::OnEnable() { - CommonPaletteTool::OnEnable(); - - WmShell::Get()->palette_delegate()->CreateNote(); - - delegate()->DisableTool(GetToolId()); - delegate()->HidePalette(); -} - -views::View* CreateNoteAction::CreateView() { - if (!WmShell::Get()->palette_delegate()->HasNoteApp()) - return nullptr; - - return CreateDefaultView( - l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_CREATE_NOTE_ACTION)); -} - -const gfx::VectorIcon& CreateNoteAction::GetPaletteIcon() const { - return kPaletteActionCreateNoteIcon; -} - -} // namespace ash
diff --git a/ash/system/palette/tools/create_note_action.h b/ash/system/palette/tools/create_note_action.h deleted file mode 100644 index 2b4e564..0000000 --- a/ash/system/palette/tools/create_note_action.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_TOOLS_CREATE_NOTE_ACTION_H_ -#define ASH_SYSTEM_PALETTE_TOOLS_CREATE_NOTE_ACTION_H_ - -#include "ash/ash_export.h" -#include "ash/system/palette/common_palette_tool.h" -#include "base/macros.h" - -namespace ash { - -// A button in the ash palette that launches the selected note-taking app when -// clicked. This action dynamically hides itself if it is not available. -class ASH_EXPORT CreateNoteAction : public CommonPaletteTool { - public: - explicit CreateNoteAction(Delegate* delegate); - ~CreateNoteAction() override; - - private: - // PaletteTool overrides. - PaletteGroup GetGroup() const override; - PaletteToolId GetToolId() const override; - void OnEnable() override; - views::View* CreateView() override; - - // CommonPaletteTool overrides. - const gfx::VectorIcon& GetPaletteIcon() const override; - - DISALLOW_COPY_AND_ASSIGN(CreateNoteAction); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_TOOLS_CREATE_NOTE_ACTION_H_
diff --git a/ash/system/palette/tools/create_note_unittest.cc b/ash/system/palette/tools/create_note_unittest.cc deleted file mode 100644 index a3f04dd..0000000 --- a/ash/system/palette/tools/create_note_unittest.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/common/wm_shell.h" -#include "ash/system/palette/mock_palette_tool_delegate.h" -#include "ash/system/palette/palette_ids.h" -#include "ash/system/palette/palette_tool.h" -#include "ash/system/palette/tools/create_note_action.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/test_palette_delegate.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "ui/views/view.h" - -namespace ash { - -namespace { - -// Base class for all create note ash tests. -class CreateNoteTest : public test::AshTestBase { - public: - CreateNoteTest() {} - ~CreateNoteTest() override {} - - void SetUp() override { - test::AshTestBase::SetUp(); - - WmShell::Get()->SetPaletteDelegateForTesting( - base::MakeUnique<TestPaletteDelegate>()); - - palette_tool_delegate_ = base::MakeUnique<MockPaletteToolDelegate>(); - tool_ = base::MakeUnique<CreateNoteAction>(palette_tool_delegate_.get()); - } - - TestPaletteDelegate* test_palette_delegate() { - return static_cast<TestPaletteDelegate*>( - WmShell::Get()->palette_delegate()); - } - - protected: - std::unique_ptr<MockPaletteToolDelegate> palette_tool_delegate_; - std::unique_ptr<PaletteTool> tool_; - - private: - DISALLOW_COPY_AND_ASSIGN(CreateNoteTest); -}; - -} // namespace - -// The note tool is only visible when there is a note-taking app available. -TEST_F(CreateNoteTest, ViewOnlyCreatedWhenNoteAppIsAvailable) { - test_palette_delegate()->set_has_note_app(false); - EXPECT_FALSE(tool_->CreateView()); - tool_->OnViewDestroyed(); - - test_palette_delegate()->set_has_note_app(true); - std::unique_ptr<views::View> view = base::WrapUnique(tool_->CreateView()); - EXPECT_TRUE(view); - tool_->OnViewDestroyed(); -} - -// Activating the note tool both creates a note via the delegate and also -// disables the tool and hides the palette. -TEST_F(CreateNoteTest, EnablingToolCreatesNewNoteAndDisablesTool) { - test_palette_delegate()->set_has_note_app(true); - std::unique_ptr<views::View> view = base::WrapUnique(tool_->CreateView()); - - EXPECT_CALL(*palette_tool_delegate_.get(), - DisableTool(PaletteToolId::CREATE_NOTE)); - EXPECT_CALL(*palette_tool_delegate_.get(), HidePalette()); - - tool_->OnEnable(); - EXPECT_EQ(1, test_palette_delegate()->create_note_count()); -} - -} // namespace ash
diff --git a/ash/system/palette/tools/laser_pointer_mode.cc b/ash/system/palette/tools/laser_pointer_mode.cc deleted file mode 100644 index bc69941..0000000 --- a/ash/system/palette/tools/laser_pointer_mode.cc +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/tools/laser_pointer_mode.h" - -#include "ash/common/palette_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/palette/palette_ids.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -LaserPointerMode::LaserPointerMode(Delegate* delegate) - : CommonPaletteTool(delegate) { -} - -LaserPointerMode::~LaserPointerMode() {} - -PaletteGroup LaserPointerMode::GetGroup() const { - return PaletteGroup::MODE; -} - -PaletteToolId LaserPointerMode::GetToolId() const { - return PaletteToolId::LASER_POINTER; -} - -void LaserPointerMode::OnEnable() { - CommonPaletteTool::OnEnable(); - - WmShell::Get()->SetLaserPointerEnabled(true); - delegate()->HidePalette(); -} - -void LaserPointerMode::OnDisable() { - CommonPaletteTool::OnDisable(); - - WmShell::Get()->SetLaserPointerEnabled(false); -} - -const gfx::VectorIcon& LaserPointerMode::GetActiveTrayIcon() const { - return kPaletteTrayIconLaserPointerIcon; -} - -const gfx::VectorIcon& LaserPointerMode::GetPaletteIcon() const { - return kPaletteModeLaserPointerIcon; -} - -views::View* LaserPointerMode::CreateView() { - return CreateDefaultView( - l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_LASER_POINTER_MODE)); -} -} // namespace ash
diff --git a/ash/system/palette/tools/laser_pointer_mode.h b/ash/system/palette/tools/laser_pointer_mode.h deleted file mode 100644 index 7f4dd65..0000000 --- a/ash/system/palette/tools/laser_pointer_mode.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_TOOLS_LASER_POINTER_MODE_H_ -#define ASH_SYSTEM_PALETTE_TOOLS_LASER_POINTER_MODE_H_ - -#include "ash/ash_export.h" -#include "ash/system/palette/common_palette_tool.h" - -namespace ash { - -// Controller for the laser pointer functionality. -class ASH_EXPORT LaserPointerMode : public CommonPaletteTool { - public: - explicit LaserPointerMode(Delegate* delegate); - ~LaserPointerMode() override; - - private: - // PaletteTool: - PaletteGroup GetGroup() const override; - PaletteToolId GetToolId() const override; - void OnEnable() override; - void OnDisable() override; - const gfx::VectorIcon& GetActiveTrayIcon() const override; - views::View* CreateView() override; - - // CommonPaletteTool: - const gfx::VectorIcon& GetPaletteIcon() const override; - - DISALLOW_COPY_AND_ASSIGN(LaserPointerMode); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_TOOLS_LASER_POINTER_MODE_H_
diff --git a/ash/system/palette/tools/magnifier_mode.cc b/ash/system/palette/tools/magnifier_mode.cc deleted file mode 100644 index 9822b01..0000000 --- a/ash/system/palette/tools/magnifier_mode.cc +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/palette/tools/magnifier_mode.h" - -#include "ash/common/palette_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/palette/palette_ids.h" -#include "ui/base/l10n/l10n_util.h" - -namespace ash { - -MagnifierMode::MagnifierMode(Delegate* delegate) - : CommonPaletteTool(delegate) {} - -MagnifierMode::~MagnifierMode() {} - -PaletteGroup MagnifierMode::GetGroup() const { - return PaletteGroup::MODE; -} - -PaletteToolId MagnifierMode::GetToolId() const { - return PaletteToolId::MAGNIFY; -} - -const gfx::VectorIcon& MagnifierMode::GetActiveTrayIcon() const { - return kPaletteTrayIconMagnifyIcon; -} - -void MagnifierMode::OnEnable() { - CommonPaletteTool::OnEnable(); - WmShell::Get()->SetPartialMagnifierEnabled(true); - delegate()->HidePalette(); -} - -void MagnifierMode::OnDisable() { - CommonPaletteTool::OnDisable(); - WmShell::Get()->SetPartialMagnifierEnabled(false); -} - -views::View* MagnifierMode::CreateView() { - return CreateDefaultView( - l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_MAGNIFIER_MODE)); -} - -const gfx::VectorIcon& MagnifierMode::GetPaletteIcon() const { - return kPaletteModeMagnifyIcon; -} - -} // namespace ash
diff --git a/ash/system/palette/tools/magnifier_mode.h b/ash/system/palette/tools/magnifier_mode.h deleted file mode 100644 index 40e570e..0000000 --- a/ash/system/palette/tools/magnifier_mode.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_PALETTE_TOOLS_MAGNIFIER_MODE_H_ -#define ASH_SYSTEM_PALETTE_TOOLS_MAGNIFIER_MODE_H_ - -#include "ash/system/palette/common_palette_tool.h" - -namespace ash { - -// Exposes a palette tool that lets the user enable a partial screen magnifier -// (ie, a spyglass) that dynamically appears when pressing the screen. -class MagnifierMode : public CommonPaletteTool { - public: - explicit MagnifierMode(Delegate* delegate); - ~MagnifierMode() override; - - private: - // PaletteTool overrides. - PaletteGroup GetGroup() const override; - PaletteToolId GetToolId() const override; - const gfx::VectorIcon& GetActiveTrayIcon() const override; - void OnEnable() override; - void OnDisable() override; - views::View* CreateView() override; - - // CommonPaletteTool overrides. - const gfx::VectorIcon& GetPaletteIcon() const override; - - DISALLOW_COPY_AND_ASSIGN(MagnifierMode); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_PALETTE_TOOLS_MAGNIFIER_MODE_H_
diff --git a/ash/system/palette/tools/screenshot_unittest.cc b/ash/system/palette/tools/screenshot_unittest.cc deleted file mode 100644 index 1b30fe2..0000000 --- a/ash/system/palette/tools/screenshot_unittest.cc +++ /dev/null
@@ -1,81 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/common/wm_shell.h" -#include "ash/system/palette/mock_palette_tool_delegate.h" -#include "ash/system/palette/palette_ids.h" -#include "ash/system/palette/palette_tool.h" -#include "ash/system/palette/tools/capture_region_mode.h" -#include "ash/system/palette/tools/capture_screen_action.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/test_palette_delegate.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" - -namespace ash { - -namespace { - -// Base class for all create note ash tests. -class ScreenshotToolTest : public test::AshTestBase { - public: - ScreenshotToolTest() {} - ~ScreenshotToolTest() override {} - - void SetUp() override { - test::AshTestBase::SetUp(); - - WmShell::Get()->SetPaletteDelegateForTesting( - base::MakeUnique<TestPaletteDelegate>()); - - palette_tool_delegate_ = base::MakeUnique<MockPaletteToolDelegate>(); - } - - TestPaletteDelegate* test_palette_delegate() { - return static_cast<TestPaletteDelegate*>( - WmShell::Get()->palette_delegate()); - } - - protected: - std::unique_ptr<MockPaletteToolDelegate> palette_tool_delegate_; - - private: - DISALLOW_COPY_AND_ASSIGN(ScreenshotToolTest); -}; - -} // namespace - -// Verifies that capturing a region triggers the partial screenshot delegate -// method. Invoking the callback passed to the delegate disables the tool. -TEST_F(ScreenshotToolTest, EnablingCaptureRegionCallsDelegateAndDisablesTool) { - std::unique_ptr<PaletteTool> tool = - base::MakeUnique<CaptureRegionMode>(palette_tool_delegate_.get()); - - // Starting a partial screenshot calls the calls the palette delegate to start - // a screenshot session and hides the palette. - EXPECT_CALL(*palette_tool_delegate_.get(), HidePalette()); - tool->OnEnable(); - EXPECT_EQ(1, test_palette_delegate()->take_partial_screenshot_count()); - testing::Mock::VerifyAndClearExpectations(palette_tool_delegate_.get()); - - // Calling the associated callback (partial screenshot finished) will disable - // the tool. - EXPECT_CALL(*palette_tool_delegate_.get(), - DisableTool(PaletteToolId::CAPTURE_REGION)); - test_palette_delegate()->partial_screenshot_done().Run(); -} - -// Verifies that capturing the screen triggers the screenshot delegate method, -// disables the tool, and hides the palette. -TEST_F(ScreenshotToolTest, EnablingCaptureScreenCallsDelegateAndDisablesTool) { - std::unique_ptr<PaletteTool> tool = - base::MakeUnique<CaptureScreenAction>(palette_tool_delegate_.get()); - EXPECT_CALL(*palette_tool_delegate_.get(), - DisableTool(PaletteToolId::CAPTURE_SCREEN)); - EXPECT_CALL(*palette_tool_delegate_.get(), HidePaletteImmediately()); - tool->OnEnable(); - EXPECT_EQ(1, test_palette_delegate()->take_screenshot_count()); -} - -} // namespace ash
diff --git a/ash/system/power/battery_notification.cc b/ash/system/power/battery_notification.cc deleted file mode 100644 index 760f34c1..0000000 --- a/ash/system/power/battery_notification.cc +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/battery_notification.h" - -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/power_status.h" -#include "ash/system/system_notifier.h" -#include "base/i18n/message_formatter.h" -#include "base/i18n/time_formatting.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/image/image.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" - -using message_center::MessageCenter; -using message_center::Notification; - -namespace ash { - -namespace { - -const char kBatteryNotificationId[] = "battery"; - -gfx::Image& GetBatteryImage(TrayPower::NotificationState notification_state) { - int resource_id; - if (PowerStatus::Get()->IsUsbChargerConnected()) { - resource_id = IDR_AURA_NOTIFICATION_BATTERY_FLUCTUATING; - } else if (notification_state == TrayPower::NOTIFICATION_LOW_POWER) { - resource_id = IDR_AURA_NOTIFICATION_BATTERY_LOW; - } else if (notification_state == TrayPower::NOTIFICATION_CRITICAL) { - resource_id = IDR_AURA_NOTIFICATION_BATTERY_CRITICAL; - } else { - NOTREACHED(); - resource_id = 0; - } - - return ui::ResourceBundle::GetSharedInstance().GetImageNamed(resource_id); -} - -std::unique_ptr<Notification> CreateNotification( - TrayPower::NotificationState notification_state) { - const PowerStatus& status = *PowerStatus::Get(); - - base::string16 message = base::i18n::MessageFormatter::FormatWithNumberedArgs( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_PERCENT), - static_cast<double>(status.GetRoundedBatteryPercent()) / 100.0); - - const base::TimeDelta time = status.IsBatteryCharging() - ? status.GetBatteryTimeToFull() - : status.GetBatteryTimeToEmpty(); - base::string16 time_message; - if (status.IsUsbChargerConnected()) { - time_message = l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE); - } else if (PowerStatus::ShouldDisplayBatteryTime(time) && - !status.IsBatteryDischargingOnLinePower()) { - if (status.IsBatteryCharging()) { - time_message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL, - TimeDurationFormat(time, base::DURATION_WIDTH_NARROW)); - } else { - // This is a low battery warning prompting the user in minutes. - time_message = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_REMAINING, - ui::TimeFormat::LENGTH_LONG, time); - } - } - - if (!time_message.empty()) - message = message + base::ASCIIToUTF16("\n") + time_message; - - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kBatteryNotificationId, - base::string16(), message, GetBatteryImage(notification_state), - base::string16(), GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierBattery), - message_center::RichNotificationData(), NULL)); - notification->SetSystemPriority(); - return notification; -} - -} // namespace - -BatteryNotification::BatteryNotification( - MessageCenter* message_center, - TrayPower::NotificationState notification_state) - : message_center_(message_center) { - message_center_->AddNotification(CreateNotification(notification_state)); -} - -BatteryNotification::~BatteryNotification() { - if (message_center_->FindVisibleNotificationById(kBatteryNotificationId)) - message_center_->RemoveNotification(kBatteryNotificationId, false); -} - -void BatteryNotification::Update( - TrayPower::NotificationState notification_state) { - if (message_center_->FindVisibleNotificationById(kBatteryNotificationId)) { - message_center_->UpdateNotification(kBatteryNotificationId, - CreateNotification(notification_state)); - } -} - -} // namespace ash
diff --git a/ash/system/power/battery_notification.h b/ash/system/power/battery_notification.h deleted file mode 100644 index ee031b5..0000000 --- a/ash/system/power/battery_notification.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_BATTERY_NOTIFICATION_H_ -#define ASH_SYSTEM_POWER_BATTERY_NOTIFICATION_H_ - -#include "ash/ash_export.h" -#include "ash/system/power/tray_power.h" -#include "base/macros.h" - -namespace message_center { -class MessageCenter; -} - -namespace ash { - -// Class for showing and hiding a MessageCenter low battery notification. -class ASH_EXPORT BatteryNotification { - public: - BatteryNotification(message_center::MessageCenter* message_center, - TrayPower::NotificationState notification_state); - ~BatteryNotification(); - - // Updates the notification if it still exists. - void Update(TrayPower::NotificationState notification_state); - - private: - message_center::MessageCenter* message_center_; - - DISALLOW_COPY_AND_ASSIGN(BatteryNotification); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_BATTERY_NOTIFICATION_H_
diff --git a/ash/system/power/dual_role_notification.cc b/ash/system/power/dual_role_notification.cc deleted file mode 100644 index 5cc1aec5..0000000 --- a/ash/system/power/dual_role_notification.cc +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/dual_role_notification.h" - -#include <set> - -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/power_status.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_controller.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/image/image.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" - -using message_center::MessageCenter; -using message_center::Notification; - -namespace ash { -namespace { - -const char kDualRoleNotificationId[] = "dual-role"; - -// Opens power settings on click. -class DualRoleNotificationDelegate - : public message_center::NotificationDelegate { - public: - DualRoleNotificationDelegate() {} - - // Overridden from message_center::NotificationDelegate. - void Click() override { - WmShell::Get()->system_tray_controller()->ShowPowerSettings(); - } - - private: - ~DualRoleNotificationDelegate() override {} - - DISALLOW_COPY_AND_ASSIGN(DualRoleNotificationDelegate); -}; - -} // namespace - -DualRoleNotification::DualRoleNotification(MessageCenter* message_center) - : message_center_(message_center), - num_dual_role_sinks_(0), - line_power_connected_(false) {} - -DualRoleNotification::~DualRoleNotification() { - if (message_center_->FindVisibleNotificationById(kDualRoleNotificationId)) - message_center_->RemoveNotification(kDualRoleNotificationId, false); -} - -void DualRoleNotification::Update() { - const PowerStatus& status = *PowerStatus::Get(); - DCHECK(status.HasDualRoleDevices()); - - std::string current_power_source_id = status.GetCurrentPowerSourceID(); - - std::unique_ptr<PowerStatus::PowerSource> new_source; - std::unique_ptr<PowerStatus::PowerSource> new_sink; - size_t num_sinks_found = 0; - for (const auto& source : status.GetPowerSources()) { - // The power source can't be changed if there's a dedicated charger. - if (source.type == PowerStatus::DEDICATED_CHARGER) { - dual_role_source_.reset(); - line_power_connected_ = true; - if (message_center_->FindVisibleNotificationById(kDualRoleNotificationId)) - message_center_->RemoveNotification(kDualRoleNotificationId, false); - return; - } - - if (source.id == current_power_source_id) { - new_source.reset(new PowerStatus::PowerSource(source)); - continue; - } - num_sinks_found++; - // The notification only shows the sink port if it is the only sink. - if (num_sinks_found == 1) - new_sink.reset(new PowerStatus::PowerSource(source)); - else - new_sink.reset(); - } - - // Check if the notification should change. - bool change = false; - if (PowerStatus::Get()->IsLinePowerConnected() != line_power_connected_) { - change = true; - line_power_connected_ = PowerStatus::Get()->IsLinePowerConnected(); - } else if (new_source && dual_role_source_) { - if (new_source->description_id != dual_role_source_->description_id) - change = true; - } else if (new_source || dual_role_source_) { - change = true; - } else { - // Notification differs for 0, 1, and 2+ sinks. - if ((num_sinks_found < num_dual_role_sinks_ && num_sinks_found < 2) || - (num_sinks_found > num_dual_role_sinks_ && num_dual_role_sinks_ < 2)) { - change = true; - } else if (num_sinks_found == 1) { - // The description matters if there's only one dual-role device. - change = new_sink->description_id != dual_role_sink_->description_id; - } - } - - dual_role_source_ = std::move(new_source); - dual_role_sink_ = std::move(new_sink); - num_dual_role_sinks_ = num_sinks_found; - - if (!change) - return; - - if (!message_center_->FindVisibleNotificationById(kDualRoleNotificationId)) { - message_center_->AddNotification(CreateNotification()); - } else { - message_center_->UpdateNotification(kDualRoleNotificationId, - CreateNotification()); - } -} - -std::unique_ptr<Notification> DualRoleNotification::CreateNotification() { - base::string16 title; - if (dual_role_source_) { - title = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_CHARGING_FROM_DUAL_ROLE_TITLE, - l10n_util::GetStringUTF16(dual_role_source_->description_id)); - } else if (num_dual_role_sinks_ == 1) { - title = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_CHARGING_DUAL_ROLE_DEVICE_TITLE, - l10n_util::GetStringUTF16(dual_role_sink_->description_id)); - } else { - title = l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_CHARGING_DUAL_ROLE_DEVICES_TITLE); - } - - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kDualRoleNotificationId, title, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DUAL_ROLE_MESSAGE), - ui::ResourceBundle::GetSharedInstance().GetImageNamed( - IDR_AURA_NOTIFICATION_LOW_POWER_CHARGER), - base::string16(), GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierDualRole), - message_center::RichNotificationData(), - new DualRoleNotificationDelegate)); - notification->set_priority(message_center::MIN_PRIORITY); - return notification; -} - -} // namespace ash
diff --git a/ash/system/power/dual_role_notification.h b/ash/system/power/dual_role_notification.h deleted file mode 100644 index 27252df..0000000 --- a/ash/system/power/dual_role_notification.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_DUAL_ROLE_NOTIFICATION_H_ -#define ASH_SYSTEM_POWER_DUAL_ROLE_NOTIFICATION_H_ - -#include <stddef.h> - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/system/power/power_status.h" -#include "base/macros.h" - -namespace message_center { -class MessageCenter; -class Notification; -} - -namespace ash { - -// Shows a non-toasting MessageCenter notification based on what dual-role -// devices are connected. -class ASH_EXPORT DualRoleNotification { - public: - explicit DualRoleNotification(message_center::MessageCenter* message_center); - ~DualRoleNotification(); - - // Creates or updates the notification. - void Update(); - - private: - // Creates the notification using the updated status. - std::unique_ptr<message_center::Notification> CreateNotification(); - - message_center::MessageCenter* message_center_; - std::unique_ptr<PowerStatus::PowerSource> dual_role_source_; - std::unique_ptr<PowerStatus::PowerSource> dual_role_sink_; - size_t num_dual_role_sinks_; - bool line_power_connected_; - - DISALLOW_COPY_AND_ASSIGN(DualRoleNotification); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_DUAL_ROLE_NOTIFICATION_H_
diff --git a/ash/system/power/power_event_observer.cc b/ash/system/power/power_event_observer.cc deleted file mode 100644 index ac24aed..0000000 --- a/ash/system/power/power_event_observer.cc +++ /dev/null
@@ -1,165 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_event_observer.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/shell.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/wm/power_button_controller.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/user_activity/user_activity_detector.h" -#include "ui/compositor/compositor.h" -#include "ui/display/manager/chromeos/display_configurator.h" - -namespace ash { - -namespace { - -// Tells the compositor for each of the displays to finish all pending -// rendering requests and block any new ones. -void StopRenderingRequests() { - for (aura::Window* window : Shell::GetAllRootWindows()) { - ui::Compositor* compositor = window->GetHost()->compositor(); - compositor->SetVisible(false); - } -} - -// Tells the compositor for each of the displays to resume sending rendering -// requests to the GPU. -void ResumeRenderingRequests() { - for (aura::Window* window : Shell::GetAllRootWindows()) - window->GetHost()->compositor()->SetVisible(true); -} - -void OnSuspendDisplaysCompleted(const base::Closure& suspend_callback, - bool status) { - suspend_callback.Run(); -} - -} // namespace - -PowerEventObserver::PowerEventObserver() - : screen_locked_(false), waiting_for_lock_screen_animations_(false) { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( - this); - chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver( - this); -} - -PowerEventObserver::~PowerEventObserver() { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( - this); - chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver( - this); -} - -void PowerEventObserver::OnLockAnimationsComplete() { - VLOG(1) << "Screen locker animations have completed."; - waiting_for_lock_screen_animations_ = false; - - if (!screen_lock_callback_.is_null()) { - StopRenderingRequests(); - - screen_lock_callback_.Run(); - screen_lock_callback_.Reset(); - } -} - -void PowerEventObserver::BrightnessChanged(int level, bool user_initiated) { - Shell::GetInstance()->power_button_controller()->OnScreenBrightnessChanged( - static_cast<double>(level)); -} - -void PowerEventObserver::SuspendImminent() { - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - - // This class is responsible for disabling all rendering requests at suspend - // time and then enabling them at resume time. When the - // auto-screen-lock pref is not set this is easy to do since - // StopRenderingRequests() is just called directly from this function. If the - // auto-screen-lock pref _is_ set, then the suspend needs to be delayed - // until the lock screen is fully visible. While it is sufficient from a - // security perspective to block only until the lock screen is ready, which - // guarantees that the contents of the user's screen are no longer visible, - // this leads to poor UX on the first resume since neither the user pod nor - // the header bar will be visible for a few hundred milliseconds until the GPU - // process starts rendering again. To deal with this, the suspend is delayed - // until all the lock screen animations have completed and the suspend request - // is unblocked from OnLockAnimationsComplete(). - if (!screen_locked_ && delegate->ShouldLockScreenAutomatically() && - delegate->CanLockScreen()) { - screen_lock_callback_ = chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->GetSuspendReadinessCallback(); - VLOG(1) << "Requesting screen lock from PowerEventObserver"; - chromeos::DBusThreadManager::Get() - ->GetSessionManagerClient() - ->RequestLockScreen(); - } else if (waiting_for_lock_screen_animations_) { - // The lock-before-suspending pref has been set and the lock screen is ready - // but the animations have not completed yet. This can happen if a suspend - // request is canceled after the lock screen is ready but before the - // animations have completed and then another suspend request is immediately - // started. In practice, it is highly unlikely that this will ever happen - // but it's better to be safe since the cost of not dealing with it properly - // is a memory leak in the GPU and weird artifacts on the screen. - screen_lock_callback_ = chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->GetSuspendReadinessCallback(); - } else { - // The lock-before-suspending pref is not set or the screen has already been - // locked and the animations have completed. Rendering can be stopped now. - StopRenderingRequests(); - } - - ui::UserActivityDetector::Get()->OnDisplayPowerChanging(); - - // TODO(derat): After mus exposes a method for suspending displays, call it - // here: http://crbug.com/692193 - if (!WmShell::Get()->IsRunningInMash()) { - Shell::GetInstance()->display_configurator()->SuspendDisplays(base::Bind( - &OnSuspendDisplaysCompleted, chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->GetSuspendReadinessCallback())); - } -} - -void PowerEventObserver::SuspendDone(const base::TimeDelta& sleep_duration) { - // TODO(derat): After mus exposes a method for resuming displays, call it - // here: http://crbug.com/692193 - if (!WmShell::Get()->IsRunningInMash()) - Shell::GetInstance()->display_configurator()->ResumeDisplays(); - WmShell::Get()->system_tray_notifier()->NotifyRefreshClock(); - - // If the suspend request was being blocked while waiting for the lock - // animation to complete, clear the blocker since the suspend has already - // completed. This prevents rendering requests from being blocked after a - // resume if the lock screen took too long to show. - screen_lock_callback_.Reset(); - - ResumeRenderingRequests(); -} - -void PowerEventObserver::ScreenIsLocked() { - screen_locked_ = true; - waiting_for_lock_screen_animations_ = true; - - // The screen is now locked but the pending suspend, if any, will be blocked - // until all the animations have completed. - if (!screen_lock_callback_.is_null()) { - VLOG(1) << "Screen locked due to suspend"; - } else { - VLOG(1) << "Screen locked without suspend"; - } -} - -void PowerEventObserver::ScreenIsUnlocked() { - screen_locked_ = false; -} - -} // namespace ash
diff --git a/ash/system/power/power_event_observer.h b/ash/system/power/power_event_observer.h deleted file mode 100644 index 63365b6..0000000 --- a/ash/system/power/power_event_observer.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_POWER_EVENT_OBSERVER_H_ -#define ASH_SYSTEM_POWER_POWER_EVENT_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "chromeos/dbus/power_manager_client.h" -#include "chromeos/dbus/session_manager_client.h" - -namespace ash { - -// A class that observes power-management-related events. -class ASH_EXPORT PowerEventObserver - : public chromeos::PowerManagerClient::Observer, - public chromeos::SessionManagerClient::Observer { - public: - // This class registers/unregisters itself as an observer in ctor/dtor. - PowerEventObserver(); - ~PowerEventObserver() override; - - // Called by the WebUIScreenLocker when all the lock screen animations have - // completed. This really should be implemented via an observer but since - // ash/ isn't allowed to depend on chrome/ we need to have the - // WebUIScreenLocker reach into ash::Shell to make this call. - void OnLockAnimationsComplete(); - - // chromeos::PowerManagerClient::Observer overrides: - void BrightnessChanged(int level, bool user_initiated) override; - void SuspendImminent() override; - void SuspendDone(const base::TimeDelta& sleep_duration) override; - - // chromeos::SessionManagerClient::Observer overrides. - void ScreenIsLocked() override; - void ScreenIsUnlocked() override; - - // Is the screen currently locked? - bool screen_locked_; - - // Have the lock screen animations completed? - bool waiting_for_lock_screen_animations_; - - // If set, called when the lock screen animations have completed to confirm - // that the system is ready to be suspended. - base::Closure screen_lock_callback_; - - private: - DISALLOW_COPY_AND_ASSIGN(PowerEventObserver); -}; - -} // namespace chromeos - -#endif // ASH_SYSTEM_POWER_POWER_EVENT_OBSERVER_H_
diff --git a/ash/system/power/power_event_observer_unittest.cc b/ash/system/power/power_event_observer_unittest.cc deleted file mode 100644 index d6325bb..0000000 --- a/ash/system/power/power_event_observer_unittest.cc +++ /dev/null
@@ -1,163 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_event_observer.h" - -#include <memory> - -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/test_session_state_delegate.h" -#include "base/time/time.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#include "ui/compositor/compositor.h" - -namespace ash { - -class PowerEventObserverTest : public test::AshTestBase { - public: - PowerEventObserverTest() {} - ~PowerEventObserverTest() override {} - - // test::AshTestBase::SetUp() overrides: - void SetUp() override { - test::AshTestBase::SetUp(); - observer_.reset(new PowerEventObserver()); - } - - void TearDown() override { - observer_.reset(); - test::AshTestBase::TearDown(); - } - - protected: - int GetNumVisibleCompositors() { - int result = 0; - for (auto* window : Shell::GetAllRootWindows()) { - if (window->GetHost()->compositor()->IsVisible()) - ++result; - } - - return result; - } - - std::unique_ptr<PowerEventObserver> observer_; - - private: - DISALLOW_COPY_AND_ASSIGN(PowerEventObserverTest); -}; - -TEST_F(PowerEventObserverTest, LockBeforeSuspend) { - chromeos::PowerManagerClient* client = - chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); - ASSERT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); - - // Check that the observer requests a suspend-readiness callback when it hears - // that the system is about to suspend. - test::TestSessionStateDelegate::SetCanLockScreen(true); - SetShouldLockScreenAutomatically(true); - observer_->SuspendImminent(); - EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks()); - - // It should run the callback when it hears that the screen is locked and the - // lock screen animations have completed. - observer_->ScreenIsLocked(); - observer_->OnLockAnimationsComplete(); - EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); - - // If the system is already locked, no callback should be requested. - observer_->SuspendDone(base::TimeDelta()); - observer_->ScreenIsUnlocked(); - observer_->ScreenIsLocked(); - observer_->OnLockAnimationsComplete(); - observer_->SuspendImminent(); - EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); - - // It also shouldn't request a callback if it isn't instructed to lock the - // screen. - observer_->SuspendDone(base::TimeDelta()); - SetShouldLockScreenAutomatically(false); - observer_->SuspendImminent(); - EXPECT_EQ(0, client->GetNumPendingSuspendReadinessCallbacks()); -} - -TEST_F(PowerEventObserverTest, SetInvisibleBeforeSuspend) { - // Tests that all the Compositors are marked invisible before a suspend - // request when the screen is not supposed to be locked before a suspend. - EXPECT_EQ(1, GetNumVisibleCompositors()); - - observer_->SuspendImminent(); - EXPECT_EQ(0, GetNumVisibleCompositors()); - observer_->SuspendDone(base::TimeDelta()); - - // Tests that all the Compositors are marked invisible _after_ the screen lock - // animations have completed. - test::TestSessionStateDelegate::SetCanLockScreen(true); - SetShouldLockScreenAutomatically(true); - - observer_->SuspendImminent(); - EXPECT_EQ(1, GetNumVisibleCompositors()); - - observer_->ScreenIsLocked(); - EXPECT_EQ(1, GetNumVisibleCompositors()); - - observer_->OnLockAnimationsComplete(); - EXPECT_EQ(0, GetNumVisibleCompositors()); - - observer_->SuspendDone(base::TimeDelta()); - EXPECT_EQ(1, GetNumVisibleCompositors()); -} - -TEST_F(PowerEventObserverTest, CanceledSuspend) { - // Tests that the Compositors are not marked invisible if a suspend is - // canceled or the system resumes before the lock screen is ready. - test::TestSessionStateDelegate::SetCanLockScreen(true); - SetShouldLockScreenAutomatically(true); - observer_->SuspendImminent(); - EXPECT_EQ(1, GetNumVisibleCompositors()); - - observer_->SuspendDone(base::TimeDelta()); - observer_->ScreenIsLocked(); - observer_->OnLockAnimationsComplete(); - EXPECT_EQ(1, GetNumVisibleCompositors()); -} - -TEST_F(PowerEventObserverTest, DelayResuspendForLockAnimations) { - // Tests that the following order of events is handled correctly: - // - // - A suspend request is started. - // - The screen is locked. - // - The suspend request is canceled. - // - Another suspend request is started. - // - The screen lock animations complete. - // - // In this case, the observer should block the second suspend request until - // the animations have completed. - test::TestSessionStateDelegate::SetCanLockScreen(true); - SetShouldLockScreenAutomatically(true); - - chromeos::PowerManagerClient* client = - chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); - observer_->SuspendImminent(); - EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks()); - - observer_->ScreenIsLocked(); - observer_->SuspendDone(base::TimeDelta()); - observer_->SuspendImminent(); - - // The expected number of suspend readiness callbacks is 2 because the - // observer has not run the callback that it got from the first suspend - // request. The real PowerManagerClient would reset its internal counter in - // this situation but the stub client is not that smart. - EXPECT_EQ(2, client->GetNumPendingSuspendReadinessCallbacks()); - - observer_->OnLockAnimationsComplete(); - EXPECT_EQ(1, client->GetNumPendingSuspendReadinessCallbacks()); - EXPECT_EQ(0, GetNumVisibleCompositors()); -} - -} // namespace ash
diff --git a/ash/system/power/power_status.cc b/ash/system/power/power_status.cc deleted file mode 100644 index 92deb8e..0000000 --- a/ash/system/power/power_status.cc +++ /dev/null
@@ -1,518 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_status.h" - -#include <algorithm> -#include <cmath> - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/gfx/paint_vector_icon.h" - -namespace ash { -namespace { - -// Updates |proto| to ensure that its fields are consistent. -void SanitizeProto(power_manager::PowerSupplyProperties* proto) { - DCHECK(proto); - - if (proto->battery_state() == - power_manager::PowerSupplyProperties_BatteryState_FULL) - proto->set_battery_percent(100.0); - - if (!proto->is_calculating_battery_time()) { - const bool on_line_power = - proto->external_power() != - power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED; - if ((on_line_power && proto->battery_time_to_full_sec() < 0) || - (!on_line_power && proto->battery_time_to_empty_sec() < 0)) - proto->set_is_calculating_battery_time(true); - } -} - -base::string16 GetBatteryTimeAccessibilityString(int hour, int min) { - DCHECK(hour || min); - if (hour && !min) { - return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, - base::TimeDelta::FromHours(hour)); - } - if (min && !hour) { - return ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, - base::TimeDelta::FromMinutes(min)); - } - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_TIME_ACCESSIBLE, - ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, - base::TimeDelta::FromHours(hour)), - ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, - base::TimeDelta::FromMinutes(min))); -} - -int PowerSourceToMessageID( - const power_manager::PowerSupplyProperties_PowerSource& source) { - switch (source.port()) { - case power_manager::PowerSupplyProperties_PowerSource_Port_UNKNOWN: - return IDS_ASH_POWER_SOURCE_PORT_UNKNOWN; - case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT: - return IDS_ASH_POWER_SOURCE_PORT_LEFT; - case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT: - return IDS_ASH_POWER_SOURCE_PORT_RIGHT; - case power_manager::PowerSupplyProperties_PowerSource_Port_BACK: - return IDS_ASH_POWER_SOURCE_PORT_BACK; - case power_manager::PowerSupplyProperties_PowerSource_Port_FRONT: - return IDS_ASH_POWER_SOURCE_PORT_FRONT; - case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT_FRONT: - return IDS_ASH_POWER_SOURCE_PORT_LEFT_FRONT; - case power_manager::PowerSupplyProperties_PowerSource_Port_LEFT_BACK: - return IDS_ASH_POWER_SOURCE_PORT_LEFT_BACK; - case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT_FRONT: - return IDS_ASH_POWER_SOURCE_PORT_RIGHT_FRONT; - case power_manager::PowerSupplyProperties_PowerSource_Port_RIGHT_BACK: - return IDS_ASH_POWER_SOURCE_PORT_RIGHT_BACK; - case power_manager::PowerSupplyProperties_PowerSource_Port_BACK_LEFT: - return IDS_ASH_POWER_SOURCE_PORT_BACK_LEFT; - case power_manager::PowerSupplyProperties_PowerSource_Port_BACK_RIGHT: - return IDS_ASH_POWER_SOURCE_PORT_BACK_RIGHT; - } - NOTREACHED(); - return 0; -} - -const gfx::VectorIcon& VectorIconForIconBadge( - PowerStatus::IconBadge icon_badge) { - switch (icon_badge) { - case PowerStatus::ICON_BADGE_NONE: - return gfx::kNoneIcon; - case PowerStatus::ICON_BADGE_ALERT: - return kSystemTrayBatteryAlertIcon; - case PowerStatus::ICON_BADGE_BOLT: - return kSystemTrayBatteryBoltIcon; - case PowerStatus::ICON_BADGE_X: - return kSystemTrayBatteryXIcon; - case PowerStatus::ICON_BADGE_UNRELIABLE: - return kSystemTrayBatteryUnreliableIcon; - } - NOTREACHED(); - return gfx::kNoneIcon; -} - -static PowerStatus* g_power_status = NULL; - -// Minimum battery percentage rendered in UI. -const int kMinBatteryPercent = 1; - -// Width and height of battery images. -const int kBatteryImageHeight = 25; -const int kBatteryImageWidth = 25; - -// Number of different power states. -const int kNumPowerImages = 15; - -// The height of the battery icon in material design (as measured from the -// user-visible bottom of the icon to the user-visible top of the icon). -const int kBatteryImageHeightMd = 12; - -// The dimensions of the canvas containing the material design battery icon. -const int kBatteryCanvasSizeMd = 16; - -// The minimum height (in dp) of the charged region of the material design -// battery icon when the battery is present and has a charge greater than 0. -const int kMinVisualChargeLevelMd = 1; - -// The empty background color of the battery icon in the system tray. Used -// for material design. -// TODO(tdanderson): Move these constants to a shared location if they are -// shared by more than one material design system icon. -const SkColor kBatteryBaseColor = SkColorSetA(SK_ColorWHITE, 0x4C); - -// The background color of the charged region of the battery in the system -// tray. Used for material design. -const SkColor kBatteryChargeColor = SK_ColorWHITE; - -// The color of the battery's badge (bolt, unreliable, X). -const SkColor kBatteryBadgeColor = SkColorSetA(SK_ColorBLACK, 0xB2); - -// The color used for the battery's badge and charged color when the battery -// charge level is critically low. -const SkColor kBatteryAlertColor = SkColorSetRGB(0xDA, 0x27, 0x12); - -} // namespace - -bool PowerStatus::BatteryImageInfo::operator==( - const BatteryImageInfo& o) const { - if (ash::MaterialDesignController::UseMaterialDesignSystemIcons()) - return icon_badge == o.icon_badge && charge_level == o.charge_level; - - // TODO(tdanderson): |resource_id|, |offset|, and |index| are only used for - // non-MD. Remove these once MD is enabled by default. See crbug.com/614453. - return resource_id == o.resource_id && offset == o.offset && index == o.index; -} - -const int PowerStatus::kMaxBatteryTimeToDisplaySec = 24 * 60 * 60; - -const double PowerStatus::kCriticalBatteryChargePercentageMd = 5; - -// static -void PowerStatus::Initialize() { - CHECK(!g_power_status); - g_power_status = new PowerStatus(); -} - -// static -void PowerStatus::Shutdown() { - CHECK(g_power_status); - delete g_power_status; - g_power_status = NULL; -} - -// static -bool PowerStatus::IsInitialized() { - return g_power_status != NULL; -} - -// static -PowerStatus* PowerStatus::Get() { - CHECK(g_power_status) << "PowerStatus::Get() called before Initialize()."; - return g_power_status; -} - -// static -bool PowerStatus::ShouldDisplayBatteryTime(const base::TimeDelta& time) { - return time >= base::TimeDelta::FromMinutes(1) && - time.InSeconds() <= kMaxBatteryTimeToDisplaySec; -} - -// static -void PowerStatus::SplitTimeIntoHoursAndMinutes(const base::TimeDelta& time, - int* hours, - int* minutes) { - DCHECK(hours); - DCHECK(minutes); - const int total_minutes = static_cast<int>(time.InSecondsF() / 60 + 0.5); - *hours = total_minutes / 60; - *minutes = total_minutes % 60; -} - -void PowerStatus::AddObserver(Observer* observer) { - DCHECK(observer); - observers_.AddObserver(observer); -} - -void PowerStatus::RemoveObserver(Observer* observer) { - DCHECK(observer); - observers_.RemoveObserver(observer); -} - -void PowerStatus::RequestStatusUpdate() { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->RequestStatusUpdate(); -} - -void PowerStatus::SetPowerSource(const std::string& id) { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->SetPowerSource( - id); -} - -bool PowerStatus::IsBatteryPresent() const { - return proto_.battery_state() != - power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT; -} - -bool PowerStatus::IsBatteryFull() const { - return proto_.battery_state() == - power_manager::PowerSupplyProperties_BatteryState_FULL; -} - -bool PowerStatus::IsBatteryCharging() const { - return proto_.battery_state() == - power_manager::PowerSupplyProperties_BatteryState_CHARGING; -} - -bool PowerStatus::IsBatteryDischargingOnLinePower() const { - return IsLinePowerConnected() && - proto_.battery_state() == - power_manager::PowerSupplyProperties_BatteryState_DISCHARGING; -} - -double PowerStatus::GetBatteryPercent() const { - return proto_.battery_percent(); -} - -int PowerStatus::GetRoundedBatteryPercent() const { - return std::max(kMinBatteryPercent, - static_cast<int>(GetBatteryPercent() + 0.5)); -} - -bool PowerStatus::IsBatteryTimeBeingCalculated() const { - return proto_.is_calculating_battery_time(); -} - -base::TimeDelta PowerStatus::GetBatteryTimeToEmpty() const { - return base::TimeDelta::FromSeconds(proto_.battery_time_to_empty_sec()); -} - -base::TimeDelta PowerStatus::GetBatteryTimeToFull() const { - return base::TimeDelta::FromSeconds(proto_.battery_time_to_full_sec()); -} - -bool PowerStatus::IsLinePowerConnected() const { - return proto_.external_power() != - power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED; -} - -bool PowerStatus::IsMainsChargerConnected() const { - return proto_.external_power() == - power_manager::PowerSupplyProperties_ExternalPower_AC; -} - -bool PowerStatus::IsUsbChargerConnected() const { - return proto_.external_power() == - power_manager::PowerSupplyProperties_ExternalPower_USB; -} - -bool PowerStatus::SupportsDualRoleDevices() const { - return proto_.supports_dual_role_devices(); -} - -bool PowerStatus::HasDualRoleDevices() const { - if (!SupportsDualRoleDevices()) - return false; - - for (int i = 0; i < proto_.available_external_power_source_size(); i++) { - if (!proto_.available_external_power_source(i).active_by_default()) - return true; - } - return false; -} - -std::vector<PowerStatus::PowerSource> PowerStatus::GetPowerSources() const { - std::vector<PowerSource> sources; - for (int i = 0; i < proto_.available_external_power_source_size(); i++) { - const auto& source = proto_.available_external_power_source(i); - sources.push_back( - {source.id(), - source.active_by_default() ? DEDICATED_CHARGER : DUAL_ROLE_USB, - PowerSourceToMessageID(source)}); - } - return sources; -} - -std::string PowerStatus::GetCurrentPowerSourceID() const { - return proto_.external_power_source_id(); -} - -PowerStatus::BatteryImageInfo PowerStatus::GetBatteryImageInfo( - IconSet icon_set) const { - BatteryImageInfo info; - if (MaterialDesignController::UseMaterialDesignSystemIcons()) - CalculateBatteryImageInfoMd(&info); - else - CalculateBatteryImageInfoNonMd(&info, icon_set); - return info; -} - -void PowerStatus::CalculateBatteryImageInfoMd(BatteryImageInfo* info) const { - if (!IsUsbChargerConnected() && !IsBatteryPresent()) { - info->icon_badge = ICON_BADGE_X; - info->charge_level = 0; - return; - } - - if (IsUsbChargerConnected()) - info->icon_badge = ICON_BADGE_UNRELIABLE; - else if (IsLinePowerConnected()) - info->icon_badge = ICON_BADGE_BOLT; - else - info->icon_badge = ICON_BADGE_NONE; - - // |charge_state| is a value between 0 and kBatteryImageHeightMd representing - // the number of device pixels the battery image should be shown charged. The - // exception is when |charge_state| is 0 (a critically-low battery); in this - // case, still draw 1dp of charge. - int charge_state = - static_cast<int>(GetBatteryPercent() / 100.0 * kBatteryImageHeightMd); - charge_state = std::max(std::min(charge_state, kBatteryImageHeightMd), 0); - info->charge_level = std::max(charge_state, kMinVisualChargeLevelMd); - - // Use ICON_BADGE_ALERT if the battery is critically low and does not already - // have a badge assigned. - if (GetBatteryPercent() < kCriticalBatteryChargePercentageMd && - info->icon_badge == ICON_BADGE_NONE) { - info->icon_badge = ICON_BADGE_ALERT; - } -} - -void PowerStatus::CalculateBatteryImageInfoNonMd( - BatteryImageInfo* info, - const IconSet& icon_set) const { - if (IsUsbChargerConnected()) { - info->resource_id = - (icon_set == ICON_DARK) - ? IDR_AURA_UBER_TRAY_POWER_SMALL_CHARGING_UNRELIABLE_DARK - : IDR_AURA_UBER_TRAY_POWER_SMALL_CHARGING_UNRELIABLE; - } else { - info->resource_id = (icon_set == ICON_DARK) - ? IDR_AURA_UBER_TRAY_POWER_SMALL_DARK - : IDR_AURA_UBER_TRAY_POWER_SMALL; - } - - info->offset = IsUsbChargerConnected() ? 0 : (IsLinePowerConnected() ? 1 : 0); - - if (GetBatteryPercent() >= 100.0) { - info->index = kNumPowerImages - 1; - } else if (!IsBatteryPresent()) { - info->index = kNumPowerImages; - } else { - info->index = - static_cast<int>(GetBatteryPercent() / 100.0 * (kNumPowerImages - 1)); - info->index = std::max(std::min(info->index, kNumPowerImages - 2), 0); - } -} - -gfx::ImageSkia PowerStatus::GetBatteryImage( - const BatteryImageInfo& info) const { - if (!MaterialDesignController::UseMaterialDesignSystemIcons()) - return GetBatteryImageNonMd(info); - - const bool use_alert_color = - (info.charge_level == kMinVisualChargeLevelMd && !IsLinePowerConnected()); - const SkColor badge_color = - use_alert_color ? kBatteryAlertColor : kBatteryBadgeColor; - const SkColor charge_color = - use_alert_color ? kBatteryAlertColor : kBatteryChargeColor; - gfx::Canvas canvas( - gfx::Size(kBatteryCanvasSizeMd, kBatteryCanvasSizeMd), - display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(), - false); - - // Paint the battery's base (background) color. - PaintVectorIcon(&canvas, kSystemTrayBatteryIcon, kBatteryCanvasSizeMd, - kBatteryBaseColor); - - // Paint the charged portion of the battery. Note that |charge_height| adjusts - // for the 2dp of padding between the bottom of the battery icon and the - // bottom edge of |canvas|. - const int charge_height = info.charge_level + 2; - gfx::Rect clip_rect(0, kBatteryCanvasSizeMd - charge_height, - kBatteryCanvasSizeMd, charge_height); - canvas.Save(); - canvas.ClipRect(clip_rect); - PaintVectorIcon(&canvas, kSystemTrayBatteryIcon, kBatteryCanvasSizeMd, - charge_color); - canvas.Restore(); - - // Paint the badge over top of the battery, if applicable. - if (info.icon_badge != ICON_BADGE_NONE) { - PaintVectorIcon(&canvas, VectorIconForIconBadge(info.icon_badge), - kBatteryCanvasSizeMd, badge_color); - } - - return gfx::ImageSkia(canvas.ExtractImageRep()); -} - -gfx::ImageSkia PowerStatus::GetBatteryImageNonMd( - const BatteryImageInfo& info) const { - gfx::Image all; - all = ui::ResourceBundle::GetSharedInstance().GetImageNamed(info.resource_id); - gfx::Rect region(info.offset * kBatteryImageWidth, - info.index * kBatteryImageHeight, kBatteryImageWidth, - kBatteryImageHeight); - return gfx::ImageSkiaOperations::ExtractSubset(*all.ToImageSkia(), region); -} - -base::string16 PowerStatus::GetAccessibleNameString( - bool full_description) const { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - if (IsBatteryFull()) { - return rb.GetLocalizedString( - IDS_ASH_STATUS_TRAY_BATTERY_FULL_CHARGE_ACCESSIBLE); - } - - base::string16 battery_percentage_accessible = l10n_util::GetStringFUTF16( - IsBatteryCharging() - ? IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_CHARGING_ACCESSIBLE - : IDS_ASH_STATUS_TRAY_BATTERY_PERCENT_ACCESSIBLE, - base::IntToString16(GetRoundedBatteryPercent())); - if (!full_description) - return battery_percentage_accessible; - - base::string16 battery_time_accessible = base::string16(); - const base::TimeDelta time = - IsBatteryCharging() ? GetBatteryTimeToFull() : GetBatteryTimeToEmpty(); - - if (IsUsbChargerConnected()) { - battery_time_accessible = rb.GetLocalizedString( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE_ACCESSIBLE); - } else if (IsBatteryTimeBeingCalculated()) { - battery_time_accessible = rb.GetLocalizedString( - IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING_ACCESSIBLE); - } else if (ShouldDisplayBatteryTime(time) && - !IsBatteryDischargingOnLinePower()) { - int hour = 0, min = 0; - PowerStatus::SplitTimeIntoHoursAndMinutes(time, &hour, &min); - base::string16 minute = - min < 10 ? base::ASCIIToUTF16("0") + base::IntToString16(min) - : base::IntToString16(min); - battery_time_accessible = l10n_util::GetStringFUTF16( - IsBatteryCharging() - ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_ACCESSIBLE - : IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_ACCESSIBLE, - GetBatteryTimeAccessibilityString(hour, min)); - } - return battery_time_accessible.empty() - ? battery_percentage_accessible - : battery_percentage_accessible + base::ASCIIToUTF16(". ") + - battery_time_accessible; -} - -PowerStatus::PowerStatus() { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( - this); - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->RequestStatusUpdate(); -} - -PowerStatus::~PowerStatus() { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( - this); -} - -void PowerStatus::SetProtoForTesting( - const power_manager::PowerSupplyProperties& proto) { - proto_ = proto; - SanitizeProto(&proto_); -} - -void PowerStatus::PowerChanged( - const power_manager::PowerSupplyProperties& proto) { - proto_ = proto; - SanitizeProto(&proto_); - for (auto& observer : observers_) - observer.OnPowerStatusChanged(); -} - -} // namespace ash
diff --git a/ash/system/power/power_status.h b/ash/system/power/power_status.h deleted file mode 100644 index 60aadd9..0000000 --- a/ash/system/power/power_status.h +++ /dev/null
@@ -1,265 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_POWER_STATUS_H_ -#define ASH_SYSTEM_POWER_POWER_STATUS_H_ - -#include <string> -#include <vector> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/strings/string16.h" -#include "base/time/time.h" -#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/gfx/image/image_skia.h" - -namespace ash { - -// PowerStatus is a singleton that receives updates about the system's -// power status from chromeos::PowerManagerClient and makes the information -// available to interested classes within Ash. -class ASH_EXPORT PowerStatus : public chromeos::PowerManagerClient::Observer { - public: - // Types of badges which can be drawn on top of a battery icon. - enum IconBadge { - ICON_BADGE_NONE, - ICON_BADGE_ALERT, - ICON_BADGE_BOLT, - ICON_BADGE_X, - ICON_BADGE_UNRELIABLE - }; - - // Different styles of battery icons. - enum IconSet { ICON_LIGHT, ICON_DARK }; - - // Interface for classes that wish to be notified when the power status - // has changed. - class Observer { - public: - // Called when the power status changes. - virtual void OnPowerStatusChanged() = 0; - - protected: - virtual ~Observer() {} - }; - - // Power source types. - enum DeviceType { - // Dedicated charger (AC adapter, USB power supply, etc.). - DEDICATED_CHARGER, - - // Dual-role device. - DUAL_ROLE_USB, - }; - - // Information about an available power source. - struct PowerSource { - // ID provided by kernel. - std::string id; - - // Type of power source. - DeviceType type; - - // Message ID of a description for this port. - int description_id; - }; - - // Information about the battery image corresponding to the status at a given - // point in time. This can be cached and later compared to avoid unnecessarily - // updating onscreen icons (GetBatteryImage() creates a new image on each - // call). - struct BatteryImageInfo { - BatteryImageInfo() - : resource_id(-1), - offset(-1), - index(-1), - icon_badge(ICON_BADGE_NONE), - charge_level(-1) {} - - bool operator==(const BatteryImageInfo& o) const; - - bool operator!=(const BatteryImageInfo& o) const { return !(*this == o); } - - // Resource ID of the image containing the specific battery icon to use. - // Only used in non-MD. - int resource_id; - - // Horizontal offset in the battery icon array image. The USB / "unreliable - // charging" image has a single column of icons; the other image contains a - // "battery" column on the left and a "line power" column on the right. - // Only used in non-MD. - int offset; - - // Vertical offset corresponding to the current battery level. Only used in - // non-MD. - int index; - - // The badge (lightning bolt, exclamation mark, etc) that should be drawn - // on top of the battery icon. Only used for MD. - // TODO(tdanderson): Consider using gfx::VectorIconId instead of this enum - // once all possible badges have been vectorized. See crbug.com/617298. - IconBadge icon_badge; - - // A value between 0 and kBatteryImageHeightMD representing the height - // of the battery's charge level in dp. Only used for MD. - int charge_level; - }; - - // Maximum battery time-to-full or time-to-empty that should be displayed - // in the UI. If the current is close to zero, battery time estimates can - // get very large; avoid displaying these large numbers. - static const int kMaxBatteryTimeToDisplaySec; - - // An alert badge is drawn over the material design battery icon if the - // battery is not connected to a charger and has less than - // |kCriticalBatteryChargePercentageMd| percentage of charge remaining. - static const double kCriticalBatteryChargePercentageMd; - - // Sets the global instance. Must be called before any calls to Get(). - static void Initialize(); - - // Destroys the global instance. - static void Shutdown(); - - // Returns true if the global instance is initialized. - static bool IsInitialized(); - - // Gets the global instance. Initialize must be called first. - static PowerStatus* Get(); - - // Returns true if |time|, a time returned by GetBatteryTimeToEmpty() or - // GetBatteryTimeToFull(), should be displayed in the UI. - // Less-than-a-minute or very large values aren't displayed. - static bool ShouldDisplayBatteryTime(const base::TimeDelta& time); - - // Copies the hour and minute components of |time| to |hours| and |minutes|. - // The minute component is rounded rather than truncated: a |time| value - // corresponding to 92 seconds will produce a |minutes| value of 2, for - // example. - static void SplitTimeIntoHoursAndMinutes(const base::TimeDelta& time, - int* hours, - int* minutes); - - // Adds or removes an observer. - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - - // Requests updated status from the power manager. - void RequestStatusUpdate(); - - // Changes the power source to the source with the given ID. - void SetPowerSource(const std::string& id); - - // Returns true if a battery is present. - bool IsBatteryPresent() const; - - // Returns true if the battery is full. This also implies that a charger - // is connected. - bool IsBatteryFull() const; - - // Returns true if the battery is charging. Note that this implies that a - // charger is connected but the converse is not necessarily true: the - // battery may be discharging even while a (perhaps low-power) charger is - // connected. Use Is*Connected() to test for the presence of a charger - // and also see IsBatteryDischargingOnLinePower(). - bool IsBatteryCharging() const; - - // Returns true if the battery is discharging (or neither charging nor - // discharging while not being full) while line power is connected. - bool IsBatteryDischargingOnLinePower() const; - - // Returns the battery's remaining charge as a value in the range [0.0, - // 100.0]. - double GetBatteryPercent() const; - - // Returns the battery's remaining charge, rounded to an integer with a - // maximum value of 100. - int GetRoundedBatteryPercent() const; - - // Returns true if the battery's time-to-full and time-to-empty estimates - // should not be displayed because the power manager is still calculating - // them. - bool IsBatteryTimeBeingCalculated() const; - - // Returns the estimated time until the battery is empty (if line power - // is disconnected) or full (if line power is connected). These estimates - // should only be used if IsBatteryTimeBeingCalculated() returns false. - base::TimeDelta GetBatteryTimeToEmpty() const; - base::TimeDelta GetBatteryTimeToFull() const; - - // Returns true if line power (including a charger of any type) is connected. - bool IsLinePowerConnected() const; - - // Returns true if an official, non-USB charger is connected. - bool IsMainsChargerConnected() const; - - // Returns true if a USB charger (which is likely to only support a low - // charging rate) is connected. - bool IsUsbChargerConnected() const; - - // Returns true if the system allows some connected devices to function as - // either power sources or sinks. - bool SupportsDualRoleDevices() const; - - // Returns true if at least one dual-role device is connected. - bool HasDualRoleDevices() const; - - // Returns a list of available power sources which the user may select. - std::vector<PowerSource> GetPowerSources() const; - - // Returns the ID of the currently used power source, or an empty string if no - // power source is selected. - std::string GetCurrentPowerSourceID() const; - - // Returns information about the image that would be returned by - // GetBatteryImage(). This can be cached and compared against future objects - // returned by this method to avoid creating new images unnecessarily. - BatteryImageInfo GetBatteryImageInfo(IconSet icon_set) const; - - // A helper function called by GetBatteryImageInfo(). Populates the - // MD-specific fields of |info|. - void CalculateBatteryImageInfoMd(BatteryImageInfo* info) const; - - // A helper function called by GetBatteryImageInfo(). Populates the - // non-MD-specific fields of |info|. - void CalculateBatteryImageInfoNonMd(BatteryImageInfo* info, - const IconSet& icon_set) const; - - // Creates a new image that should be shown for the battery's current state. - gfx::ImageSkia GetBatteryImage(const BatteryImageInfo& info) const; - - // A version of GetBatteryImage() that is used when material design is not - // enabled. - // TODO(tdanderson): Remove this once material design is enabled by default. - // See crbug.com/614453. - gfx::ImageSkia GetBatteryImageNonMd(const BatteryImageInfo& info) const; - - // Returns an string describing the current state for accessibility. - base::string16 GetAccessibleNameString(bool full_description) const; - - // Updates |proto_|. Does not notify observers. - void SetProtoForTesting(const power_manager::PowerSupplyProperties& proto); - - protected: - PowerStatus(); - ~PowerStatus() override; - - private: - // Overriden from PowerManagerClient::Observer. - void PowerChanged(const power_manager::PowerSupplyProperties& proto) override; - - base::ObserverList<Observer> observers_; - - // Current state. - power_manager::PowerSupplyProperties proto_; - - DISALLOW_COPY_AND_ASSIGN(PowerStatus); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_POWER_STATUS_H_
diff --git a/ash/system/power/power_status_unittest.cc b/ash/system/power/power_status_unittest.cc deleted file mode 100644 index 9dcc02d..0000000 --- a/ash/system/power/power_status_unittest.cc +++ /dev/null
@@ -1,319 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_status.h" - -#include <memory> - -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/cros_system_api/dbus/service_constants.h" - -using power_manager::PowerSupplyProperties; - -namespace ash { -namespace { - -class TestObserver : public PowerStatus::Observer { - public: - TestObserver() : power_changed_count_(0) {} - ~TestObserver() override {} - - int power_changed_count() const { return power_changed_count_; } - - // PowerStatus::Observer overrides: - void OnPowerStatusChanged() override { ++power_changed_count_; } - - private: - int power_changed_count_; - - DISALLOW_COPY_AND_ASSIGN(TestObserver); -}; - -} // namespace - -class PowerStatusTest : public testing::Test { - public: - PowerStatusTest() : power_status_(NULL) {} - ~PowerStatusTest() override {} - - void SetUp() override { - chromeos::DBusThreadManager::Initialize(); - PowerStatus::Initialize(); - power_status_ = PowerStatus::Get(); - test_observer_.reset(new TestObserver); - power_status_->AddObserver(test_observer_.get()); - } - - void TearDown() override { - power_status_->RemoveObserver(test_observer_.get()); - test_observer_.reset(); - PowerStatus::Shutdown(); - chromeos::DBusThreadManager::Shutdown(); - } - - protected: - base::MessageLoopForUI message_loop_; - PowerStatus* power_status_; // Not owned. - std::unique_ptr<TestObserver> test_observer_; - - private: - DISALLOW_COPY_AND_ASSIGN(PowerStatusTest); -}; - -TEST_F(PowerStatusTest, InitializeAndUpdate) { - // Test that the initial power supply state should be acquired after - // PowerStatus is instantiated. This depends on - // PowerManagerClientStubImpl, which responds to power status update - // requests, pretends there is a battery present, and generates some valid - // power supply status data. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, test_observer_->power_changed_count()); - - // Test RequestUpdate, test_obsever_ should be notified for power suuply - // status change. - power_status_->RequestStatusUpdate(); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2, test_observer_->power_changed_count()); -} - -TEST_F(PowerStatusTest, ShouldDisplayBatteryTime) { - EXPECT_FALSE( - PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(-1))); - EXPECT_FALSE( - PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(0))); - EXPECT_FALSE( - PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(59))); - EXPECT_TRUE( - PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(60))); - EXPECT_TRUE( - PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds(600))); - EXPECT_TRUE(PowerStatus::ShouldDisplayBatteryTime( - base::TimeDelta::FromSeconds(3600))); - EXPECT_TRUE(PowerStatus::ShouldDisplayBatteryTime( - base::TimeDelta::FromSeconds(PowerStatus::kMaxBatteryTimeToDisplaySec))); - EXPECT_FALSE( - PowerStatus::ShouldDisplayBatteryTime(base::TimeDelta::FromSeconds( - PowerStatus::kMaxBatteryTimeToDisplaySec + 1))); -} - -TEST_F(PowerStatusTest, SplitTimeIntoHoursAndMinutes) { - int hours = 0, minutes = 0; - PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(0), - &hours, &minutes); - EXPECT_EQ(0, hours); - EXPECT_EQ(0, minutes); - - PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(60), - &hours, &minutes); - EXPECT_EQ(0, hours); - EXPECT_EQ(1, minutes); - - PowerStatus::SplitTimeIntoHoursAndMinutes(base::TimeDelta::FromSeconds(3600), - &hours, &minutes); - EXPECT_EQ(1, hours); - EXPECT_EQ(0, minutes); - - PowerStatus::SplitTimeIntoHoursAndMinutes( - base::TimeDelta::FromSeconds(3600 + 60), &hours, &minutes); - EXPECT_EQ(1, hours); - EXPECT_EQ(1, minutes); - - PowerStatus::SplitTimeIntoHoursAndMinutes( - base::TimeDelta::FromSeconds(7 * 3600 + 23 * 60), &hours, &minutes); - EXPECT_EQ(7, hours); - EXPECT_EQ(23, minutes); - - // Check that minutes are rounded. - PowerStatus::SplitTimeIntoHoursAndMinutes( - base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 30), &hours, &minutes); - EXPECT_EQ(2, hours); - EXPECT_EQ(4, minutes); - - PowerStatus::SplitTimeIntoHoursAndMinutes( - base::TimeDelta::FromSeconds(2 * 3600 + 3 * 60 + 29), &hours, &minutes); - EXPECT_EQ(2, hours); - EXPECT_EQ(3, minutes); - - // Check that times close to hour boundaries aren't incorrectly rounded such - // that they display 60 minutes: http://crbug.com/368261 - PowerStatus::SplitTimeIntoHoursAndMinutes( - base::TimeDelta::FromSecondsD(3599.9), &hours, &minutes); - EXPECT_EQ(1, hours); - EXPECT_EQ(0, minutes); - - PowerStatus::SplitTimeIntoHoursAndMinutes( - base::TimeDelta::FromSecondsD(3600.1), &hours, &minutes); - EXPECT_EQ(1, hours); - EXPECT_EQ(0, minutes); -} - -TEST_F(PowerStatusTest, GetBatteryImageInfo) { - PowerSupplyProperties prop; - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::CHARGING); - prop.set_battery_percent(98.0); - power_status_->SetProtoForTesting(prop); - const PowerStatus::BatteryImageInfo info_charging_98 = - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT); - - // 99% should use the same icon as 98%. - prop.set_battery_percent(99.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ(info_charging_98, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); - - // The dark icon set should use a different image for non-MD, but the - // same image for MD. - prop.set_battery_percent(98.0); - EXPECT_EQ(info_charging_98, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_DARK)); - - // A different icon should be used when the battery is full, too. - prop.set_battery_state(PowerSupplyProperties::FULL); - prop.set_battery_percent(100.0); - power_status_->SetProtoForTesting(prop); - EXPECT_NE(info_charging_98, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); - - // A much-lower battery level should use a different icon. - prop.set_battery_state(PowerSupplyProperties::CHARGING); - prop.set_battery_percent(20.0); - power_status_->SetProtoForTesting(prop); - EXPECT_NE(info_charging_98, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); - - // Ditto for 98%, but on USB instead of AC. - prop.set_external_power(PowerSupplyProperties::USB); - prop.set_battery_percent(98.0); - power_status_->SetProtoForTesting(prop); - EXPECT_NE(info_charging_98, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT)); -} - -// Tests that the |icon_badge| member of BatteryImageInfo is set correctly -// with various power supply property values. -TEST_F(PowerStatusTest, BatteryImageInfoIconBadge) { - PowerSupplyProperties prop; - - // A charging battery connected to AC power should have an ICON_BADGE_BOLT. - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::CHARGING); - prop.set_battery_percent(98.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_BOLT, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - - // A discharging battery connected to AC should also have an ICON_BADGE_BOLT. - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_BOLT, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - - // A charging battery connected to USB power should have an - // ICON_BADGE_UNRELIABLE. - prop.set_external_power(PowerSupplyProperties::USB); - prop.set_battery_state(PowerSupplyProperties::CHARGING); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_UNRELIABLE, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - - // A discharging battery connected to USB power should also have an - // ICON_BADGE_UNRELIABLE. - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_UNRELIABLE, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - - // Show an ICON_BADGE_X when no battery is present. - prop.set_external_power(PowerSupplyProperties::DISCONNECTED); - prop.set_battery_state(PowerSupplyProperties::NOT_PRESENT); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_X, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - - // Do not show a badge when the battery is discharging. - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_NONE, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - - // Show ICON_BADGE_ALERT for a discharging battery when it falls below - // a charge level of PowerStatus::kCriticalBatteryChargePercentageMd. - prop.set_battery_percent(PowerStatus::kCriticalBatteryChargePercentageMd); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_NONE, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); - prop.set_battery_percent(PowerStatus::kCriticalBatteryChargePercentageMd - 1); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - PowerStatus::ICON_BADGE_ALERT, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).icon_badge); -} - -// Tests that the |charge_level| member of BatteryImageInfo is set correctly -// with various power supply property values. -TEST_F(PowerStatusTest, BatteryImageInfoChargeLevel) { - PowerSupplyProperties prop; - - // No charge level is drawn when the battery is not present. - prop.set_external_power(PowerSupplyProperties::DISCONNECTED); - prop.set_battery_state(PowerSupplyProperties::NOT_PRESENT); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - 0, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); - - // A charge level of 0 when the battery is 0% full. - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::CHARGING); - prop.set_battery_percent(0.0); - EXPECT_EQ( - 0, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); - - // A charge level of 1 when the battery is up to 16% full, and a level of 2 - // for 17% full. - prop.set_battery_percent(16.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - 1, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); - prop.set_battery_percent(17.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - 2, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); - - // A charge level of 6 when the battery is 50% full. - prop.set_battery_percent(50.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - 6, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); - - // A charge level of 11 when the battery is 99% full, and a level of 12 when - // the battery is 100% full. - prop.set_battery_percent(99.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - 11, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); - prop.set_battery_percent(100.0); - power_status_->SetProtoForTesting(prop); - EXPECT_EQ( - 12, - power_status_->GetBatteryImageInfo(PowerStatus::ICON_LIGHT).charge_level); -} - -} // namespace ash
diff --git a/ash/system/power/power_status_view.cc b/ash/system/power/power_status_view.cc deleted file mode 100644 index bcb33af..0000000 --- a/ash/system/power/power_status_view.cc +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_status_view.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/power_status.h" -#include "ash/system/power/tray_power.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "base/i18n/number_formatting.h" -#include "base/i18n/time_formatting.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/grid_layout.h" - -namespace ash { - -// Padding between battery status text and battery icon on default view. -const int kPaddingBetweenBatteryStatusAndIcon = 3; - -PowerStatusView::PowerStatusView(bool default_view_right_align) - : default_view_right_align_(default_view_right_align), - percentage_label_(new views::Label), - separator_label_(new views::Label), - time_status_label_(new views::Label), - icon_(nullptr) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - SetFocusBehavior(FocusBehavior::ALWAYS); - - percentage_label_->SetEnabledColor(kHeaderTextColorNormal); - separator_label_->SetEnabledColor(kHeaderTextColorNormal); - separator_label_->SetText(base::ASCIIToUTF16(" - ")); - LayoutView(); - PowerStatus::Get()->AddObserver(this); - OnPowerStatusChanged(); -} - -PowerStatusView::~PowerStatusView() { - PowerStatus::Get()->RemoveObserver(this); -} - -void PowerStatusView::OnPowerStatusChanged() { - UpdateText(); - - // We do not show a battery icon in the material design system menu. - // TODO(tdanderson): Remove the non-MD code and the IconSet enum once - // material design is enabled by default. See crbug.com/614453. - if (MaterialDesignController::UseMaterialDesignSystemIcons()) - return; - - const PowerStatus::BatteryImageInfo info = - PowerStatus::Get()->GetBatteryImageInfo(PowerStatus::ICON_DARK); - if (info != previous_battery_image_info_) { - icon_->SetImage(PowerStatus::Get()->GetBatteryImage(info)); - icon_->SetVisible(true); - previous_battery_image_info_ = info; - } -} - -void PowerStatusView::LayoutView() { - if (default_view_right_align_) { - views::BoxLayout* layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, - kPaddingBetweenBatteryStatusAndIcon); - SetLayoutManager(layout); - - AddChildView(percentage_label_); - AddChildView(separator_label_); - AddChildView(time_status_label_); - - icon_ = new views::ImageView; - AddChildView(icon_); - - return; - } - - // TODO(tdanderson): Tweak padding values for material design. - const bool material_design = - MaterialDesignController::IsSystemTrayMenuMaterial(); - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, material_design ? 12 : 0, 0, - kTrayPopupPaddingBetweenItems); - SetLayoutManager(layout); - - if (!material_design) { - icon_ = TrayPopupUtils::CreateMainImageView(); - AddChildView(icon_); - } - - AddChildView(percentage_label_); - AddChildView(separator_label_); - AddChildView(time_status_label_); -} - -void PowerStatusView::UpdateText() { - const PowerStatus& status = *PowerStatus::Get(); - base::string16 battery_percentage; - base::string16 battery_time_status; - - if (status.IsBatteryFull()) { - battery_time_status = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_FULL); - } else { - battery_percentage = base::FormatPercent(status.GetRoundedBatteryPercent()); - if (status.IsUsbChargerConnected()) { - battery_time_status = l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE); - } else if (status.IsBatteryTimeBeingCalculated()) { - battery_time_status = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING); - } else { - base::TimeDelta time = status.IsBatteryCharging() - ? status.GetBatteryTimeToFull() - : status.GetBatteryTimeToEmpty(); - if (PowerStatus::ShouldDisplayBatteryTime(time) && - !status.IsBatteryDischargingOnLinePower()) { - battery_time_status = l10n_util::GetStringFUTF16( - status.IsBatteryCharging() - ? IDS_ASH_STATUS_TRAY_BATTERY_TIME_UNTIL_FULL_SHORT - : IDS_ASH_STATUS_TRAY_BATTERY_TIME_LEFT_SHORT, - TimeDurationFormat(time, base::DURATION_WIDTH_NUMERIC)); - } - } - } - percentage_label_->SetVisible(!battery_percentage.empty()); - percentage_label_->SetText(battery_percentage); - separator_label_->SetVisible(!battery_percentage.empty() && - !battery_time_status.empty()); - time_status_label_->SetVisible(!battery_time_status.empty()); - time_status_label_->SetText(battery_time_status); - - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true); - - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO); - style.SetupLabel(percentage_label_); - style.SetupLabel(separator_label_); - style.SetupLabel(time_status_label_); - } -} - -void PowerStatusView::ChildPreferredSizeChanged(views::View* child) { - PreferredSizeChanged(); -} - -void PowerStatusView::Layout() { - views::View::Layout(); - - // Move the time_status_label_, separator_label_, and percentage_label_ - // closer to each other. - if (percentage_label_ && separator_label_ && time_status_label_ && - percentage_label_->visible() && time_status_label_->visible()) { - separator_label_->SetX(percentage_label_->bounds().right() + 1); - time_status_label_->SetX(separator_label_->bounds().right() + 1); - } -} - -void PowerStatusView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - - node_data->role = ui::AX_ROLE_LABEL_TEXT; - node_data->SetName(accessible_name_); -} - -} // namespace ash
diff --git a/ash/system/power/power_status_view.h b/ash/system/power/power_status_view.h deleted file mode 100644 index 75c163a..0000000 --- a/ash/system/power/power_status_view.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_POWER_STATUS_VIEW_H_ -#define ASH_SYSTEM_POWER_POWER_STATUS_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/system/power/power_status.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/views/view.h" - -namespace views { -class ImageView; -class Label; -} - -namespace ash { - -class ASH_EXPORT PowerStatusView : public views::View, - public PowerStatus::Observer { - public: - explicit PowerStatusView(bool default_view_right_align); - ~PowerStatusView() override; - - // views::View: - void Layout() override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - - // PowerStatus::Observer: - void OnPowerStatusChanged() override; - - private: - friend class PowerStatusViewTest; - - void LayoutView(); - void UpdateText(); - - // views::View: - void ChildPreferredSizeChanged(views::View* child) override; - - // Layout default view UI items on the right side of system tray pop up item - // if true; otherwise, layout the UI items on the left side. - bool default_view_right_align_; - - views::Label* percentage_label_; - views::Label* separator_label_; - views::Label* time_status_label_; - - // Battery status indicator icon. Unused in material design. - views::ImageView* icon_; - - // Information about the image last used to update |icon_|. Cached to avoid - // unnecessary updates (http://crbug.com/589348). - PowerStatus::BatteryImageInfo previous_battery_image_info_; - - // Only used in material design. - base::string16 accessible_name_; - - DISALLOW_COPY_AND_ASSIGN(PowerStatusView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_POWER_STATUS_VIEW_H_
diff --git a/ash/system/power/power_status_view_unittest.cc b/ash/system/power/power_status_view_unittest.cc deleted file mode 100644 index 7e63c4e..0000000 --- a/ash/system/power/power_status_view_unittest.cc +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/power_status_view.h" - -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/power_status.h" -#include "ash/test/ash_test_base.h" -#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" - -using power_manager::PowerSupplyProperties; - -namespace ash { - -class PowerStatusViewTest : public test::AshTestBase { - public: - PowerStatusViewTest() {} - ~PowerStatusViewTest() override {} - - // Overridden from testing::Test: - void SetUp() override { - test::AshTestBase::SetUp(); - view_.reset(new PowerStatusView(false)); - } - - void TearDown() override { - view_.reset(); - test::AshTestBase::TearDown(); - } - - protected: - void UpdatePowerStatus(const power_manager::PowerSupplyProperties& proto) { - PowerStatus::Get()->SetProtoForTesting(proto); - view_->OnPowerStatusChanged(); - } - - bool IsPercentageVisible() const { - return view_->percentage_label_->visible(); - } - - bool IsTimeStatusVisible() const { - return view_->time_status_label_->visible(); - } - - base::string16 RemainingTimeInView() const { - return view_->time_status_label_->text(); - } - - gfx::ImageSkia GetBatteryImage() const { return view_->icon_->GetImage(); } - - private: - std::unique_ptr<PowerStatusView> view_; - - DISALLOW_COPY_AND_ASSIGN(PowerStatusViewTest); -}; - -TEST_F(PowerStatusViewTest, Basic) { - EXPECT_FALSE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - - // Disconnect the power. - PowerSupplyProperties prop; - prop.set_external_power(PowerSupplyProperties::DISCONNECTED); - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - prop.set_battery_percent(99.0); - prop.set_battery_time_to_empty_sec(120); - prop.set_is_calculating_battery_time(true); - UpdatePowerStatus(prop); - - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), - RemainingTimeInView()); - - prop.set_is_calculating_battery_time(false); - UpdatePowerStatus(prop); - EXPECT_NE(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), - RemainingTimeInView()); - EXPECT_NE(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), - RemainingTimeInView()); - - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::CHARGING); - prop.set_battery_time_to_full_sec(120); - UpdatePowerStatus(prop); - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - EXPECT_NE(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BATTERY_CALCULATING), - RemainingTimeInView()); - EXPECT_NE(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), - RemainingTimeInView()); - - prop.set_external_power(PowerSupplyProperties::USB); - UpdatePowerStatus(prop); - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_TRUE(IsTimeStatusVisible()); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BATTERY_CHARGING_UNRELIABLE), - RemainingTimeInView()); - - // Tricky -- connected to non-USB but still discharging. Not likely happening - // on production though. - prop.set_external_power(PowerSupplyProperties::AC); - prop.set_battery_state(PowerSupplyProperties::DISCHARGING); - prop.set_battery_time_to_full_sec(120); - UpdatePowerStatus(prop); - EXPECT_TRUE(IsPercentageVisible()); - EXPECT_FALSE(IsTimeStatusVisible()); -} - -} // namespace ash
diff --git a/ash/system/power/tablet_power_button_controller.cc b/ash/system/power/tablet_power_button_controller.cc deleted file mode 100644 index 3a06df60..0000000 --- a/ash/system/power/tablet_power_button_controller.cc +++ /dev/null
@@ -1,265 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/tablet_power_button_controller.h" - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/shell.h" -#include "ash/wm/lock_state_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "base/time/default_tick_clock.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "ui/events/devices/input_device_manager.h" -#include "ui/events/devices/stylus_state.h" -#include "ui/events/event.h" - -namespace ash { - -namespace { - -// Amount of time the power button must be held to start the pre-shutdown -// animation when in tablet mode. This differs depending on whether the screen -// is on or off when the power button is initially pressed. -constexpr int kShutdownWhenScreenOnTimeoutMs = 500; -// TODO(derat): This is currently set to a high value to work around delays in -// powerd's reports of button-up events when the preceding button-down event -// turns the display on. Set it to a lower value once powerd no longer blocks on -// asking Chrome to turn the display on: http://crbug.com/685734 -constexpr int kShutdownWhenScreenOffTimeoutMs = 2000; - -// Amount of time since last SuspendDone() that power button event needs to be -// ignored. -constexpr int kIgnorePowerButtonAfterResumeMs = 2000; - -// Ignore button-up events occurring within this many milliseconds of the -// previous button-up event. This prevents us from falling behind if the power -// button is pressed repeatedly. -constexpr int kIgnoreRepeatedButtonUpMs = 500; - -// Returns true if device is a convertible/tablet device, otherwise false. -bool IsTabletModeSupported() { - MaximizeModeController* maximize_mode_controller = - WmShell::Get()->maximize_mode_controller(); - return maximize_mode_controller && - maximize_mode_controller->CanEnterMaximizeMode(); -} - -// Returns true if device is currently in tablet/maximize mode, otherwise false. -bool IsTabletModeActive() { - MaximizeModeController* maximize_mode_controller = - WmShell::Get()->maximize_mode_controller(); - return maximize_mode_controller && - maximize_mode_controller->IsMaximizeModeWindowManagerEnabled(); -} - -} // namespace - -TabletPowerButtonController::TestApi::TestApi( - TabletPowerButtonController* controller) - : controller_(controller) {} - -TabletPowerButtonController::TestApi::~TestApi() {} - -bool TabletPowerButtonController::TestApi::ShutdownTimerIsRunning() const { - return controller_->shutdown_timer_.IsRunning(); -} - -void TabletPowerButtonController::TestApi::TriggerShutdownTimeout() { - DCHECK(ShutdownTimerIsRunning()); - controller_->OnShutdownTimeout(); - controller_->shutdown_timer_.Stop(); -} - -TabletPowerButtonController::TabletPowerButtonController( - LockStateController* controller) - : tick_clock_(new base::DefaultTickClock()), - force_off_on_button_up_(true), - controller_(controller), - weak_ptr_factory_(this) { - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( - this); - WmShell::Get()->AddShellObserver(this); - // TODO(mash): Provide a way for this class to observe stylus events: - // http://crbug.com/682460 - if (ui::InputDeviceManager::HasInstance()) - ui::InputDeviceManager::GetInstance()->AddObserver(this); - Shell::GetInstance()->PrependPreTargetHandler(this); - - GetInitialBacklightsForcedOff(); -} - -TabletPowerButtonController::~TabletPowerButtonController() { - Shell::GetInstance()->RemovePreTargetHandler(this); - if (ui::InputDeviceManager::HasInstance()) - ui::InputDeviceManager::GetInstance()->RemoveObserver(this); - WmShell::Get()->RemoveShellObserver(this); - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( - this); -} - -bool TabletPowerButtonController::ShouldHandlePowerButtonEvents() const { - return IsTabletModeSupported(); -} - -void TabletPowerButtonController::OnPowerButtonEvent( - bool down, - const base::TimeTicks& timestamp) { - if (down) { - force_off_on_button_up_ = true; - // When the system resumes in response to the power button being pressed, - // Chrome receives powerd's SuspendDone signal and notification that the - // backlight has been turned back on before seeing the power button events - // that woke the system. Avoid forcing off display just after resuming to - // ensure that we don't turn the display off in response to the events. - if (timestamp - last_resume_time_ <= - base::TimeDelta::FromMilliseconds(kIgnorePowerButtonAfterResumeMs)) { - force_off_on_button_up_ = false; - } - screen_off_when_power_button_down_ = brightness_level_is_zero_; - SetDisplayForcedOff(false); - StartShutdownTimer(); - } else { - // When power button is released, cancel shutdown animation whenever it is - // still cancellable. - if (controller_->CanCancelShutdownAnimation()) - controller_->CancelShutdownAnimation(); - - const base::TimeTicks previous_up_time = last_button_up_time_; - last_button_up_time_ = tick_clock_->NowTicks(); - // Ignore the event if it comes too soon after the last one. - if (timestamp - previous_up_time <= - base::TimeDelta::FromMilliseconds(kIgnoreRepeatedButtonUpMs)) { - shutdown_timer_.Stop(); - return; - } - - if (shutdown_timer_.IsRunning()) { - shutdown_timer_.Stop(); - if (!screen_off_when_power_button_down_ && force_off_on_button_up_) { - SetDisplayForcedOff(true); - LockScreenIfRequired(); - } - } - } -} - -void TabletPowerButtonController::PowerManagerRestarted() { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->SetBacklightsForcedOff(backlights_forced_off_); -} - -void TabletPowerButtonController::BrightnessChanged(int level, - bool user_initiated) { - brightness_level_is_zero_ = level == 0; -} - -void TabletPowerButtonController::SuspendDone( - const base::TimeDelta& sleep_duration) { - last_resume_time_ = tick_clock_->NowTicks(); -} - -void TabletPowerButtonController::OnMaximizeModeStarted() { - shutdown_timer_.Stop(); - if (controller_->CanCancelShutdownAnimation()) - controller_->CancelShutdownAnimation(); -} - -void TabletPowerButtonController::OnMaximizeModeEnded() { - shutdown_timer_.Stop(); - if (controller_->CanCancelShutdownAnimation()) - controller_->CancelShutdownAnimation(); -} - -void TabletPowerButtonController::OnKeyEvent(ui::KeyEvent* event) { - // Ignore key events generated by the power button since power button activity - // is already handled by OnPowerButtonEvent(). - if (event->key_code() == ui::VKEY_POWER) - return; - - if (!IsTabletModeActive() && backlights_forced_off_) - SetDisplayForcedOff(false); -} - -void TabletPowerButtonController::OnMouseEvent(ui::MouseEvent* event) { - if (event->flags() & ui::EF_IS_SYNTHESIZED) - return; - - if (!IsTabletModeActive() && backlights_forced_off_) - SetDisplayForcedOff(false); -} - -void TabletPowerButtonController::OnStylusStateChanged(ui::StylusState state) { - if (IsTabletModeSupported() && state == ui::StylusState::REMOVED && - backlights_forced_off_) { - SetDisplayForcedOff(false); - } -} - -void TabletPowerButtonController::SetTickClockForTesting( - std::unique_ptr<base::TickClock> tick_clock) { - DCHECK(tick_clock); - tick_clock_ = std::move(tick_clock); -} - -void TabletPowerButtonController::SetDisplayForcedOff(bool forced_off) { - if (backlights_forced_off_ == forced_off) - return; - - // Set the display and keyboard backlights (if present) to |forced_off|. - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->SetBacklightsForcedOff(forced_off); - backlights_forced_off_ = forced_off; - - ShellDelegate* delegate = WmShell::Get()->delegate(); - delegate->SetTouchscreenEnabledInPrefs(!forced_off, - true /* use_local_state */); - delegate->UpdateTouchscreenStatusFromPrefs(); - - // Send an a11y alert. - WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert( - forced_off ? A11Y_ALERT_SCREEN_OFF : A11Y_ALERT_SCREEN_ON); -} - -void TabletPowerButtonController::GetInitialBacklightsForcedOff() { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->GetBacklightsForcedOff(base::Bind( - &TabletPowerButtonController::OnGotInitialBacklightsForcedOff, - weak_ptr_factory_.GetWeakPtr())); -} - -void TabletPowerButtonController::OnGotInitialBacklightsForcedOff( - bool is_forced_off) { - backlights_forced_off_ = is_forced_off; -} - -void TabletPowerButtonController::StartShutdownTimer() { - base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( - screen_off_when_power_button_down_ ? kShutdownWhenScreenOffTimeoutMs - : kShutdownWhenScreenOnTimeoutMs); - shutdown_timer_.Start(FROM_HERE, timeout, this, - &TabletPowerButtonController::OnShutdownTimeout); -} - -void TabletPowerButtonController::OnShutdownTimeout() { - controller_->StartShutdownAnimation(); -} - -void TabletPowerButtonController::LockScreenIfRequired() { - SessionStateDelegate* session_state_delegate = - WmShell::Get()->GetSessionStateDelegate(); - if (session_state_delegate->ShouldLockScreenAutomatically() && - session_state_delegate->CanLockScreen() && - !session_state_delegate->IsUserSessionBlocked() && - !controller_->LockRequested()) { - session_state_delegate->LockScreen(); - } -} - -} // namespace ash
diff --git a/ash/system/power/tablet_power_button_controller.h b/ash/system/power/tablet_power_button_controller.h deleted file mode 100644 index 834045e1..0000000 --- a/ash/system/power/tablet_power_button_controller.h +++ /dev/null
@@ -1,139 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_ -#define ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/time/tick_clock.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "chromeos/dbus/power_manager_client.h" -#include "ui/events/devices/input_device_event_observer.h" -#include "ui/events/event_handler.h" - -namespace ash { - -class LockStateController; - -// Handles power button events on convertible/tablet device. This class is -// instantiated and used in PowerButtonController. -class ASH_EXPORT TabletPowerButtonController - : public chromeos::PowerManagerClient::Observer, - public ShellObserver, - public ui::EventHandler, - public ui::InputDeviceEventObserver { - public: - // Helper class used by tablet power button tests to access internal state. - class ASH_EXPORT TestApi { - public: - explicit TestApi(TabletPowerButtonController* controller); - ~TestApi(); - - // Returns true when |shutdown_timer_| is running. - bool ShutdownTimerIsRunning() const; - - // Emulates |shutdown_timer_| timeout. - void TriggerShutdownTimeout(); - - private: - TabletPowerButtonController* controller_; // Not owned. - - DISALLOW_COPY_AND_ASSIGN(TestApi); - }; - - explicit TabletPowerButtonController(LockStateController* controller); - ~TabletPowerButtonController() override; - - // Returns true if power button events should be handled by this class instead - // of PowerButtonController. - bool ShouldHandlePowerButtonEvents() const; - - // Handles a power button event. - void OnPowerButtonEvent(bool down, const base::TimeTicks& timestamp); - - // Overridden from chromeos::PowerManagerClient::Observer: - void PowerManagerRestarted() override; - void BrightnessChanged(int level, bool user_initiated) override; - void SuspendDone(const base::TimeDelta& sleep_duration) override; - - // Overridden from ShellObserver: - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - - // Overridden from ui::EventHandler: - void OnKeyEvent(ui::KeyEvent* event) override; - void OnMouseEvent(ui::MouseEvent* event) override; - - // Overridden from ui::InputDeviceObserver: - void OnStylusStateChanged(ui::StylusState state) override; - - // Overrides the tick clock used by |this| for testing. - void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock); - - private: - // Updates the power manager's backlights-forced-off state and enables or - // disables the touchscreen. No-op if |backlights_forced_off_| already equals - // |forced_off|. - void SetDisplayForcedOff(bool forced_off); - - // Sends a request to powerd to get the backlights forced off state so that - // |backlights_forced_off_| can be initialized. - void GetInitialBacklightsForcedOff(); - - // Initializes |backlights_forced_off_|. - void OnGotInitialBacklightsForcedOff(bool is_forced_off); - - // Starts |shutdown_timer_| when the power button is pressed while in - // tablet mode. - void StartShutdownTimer(); - - // Called by |shutdown_timer_| to start the pre-shutdown animation. - void OnShutdownTimeout(); - - // Locks the screen if the "require password to wake from sleep" pref is set - // and locking is possible. - void LockScreenIfRequired(); - - // True if the brightness level is currently set to off. - bool brightness_level_is_zero_ = false; - - // Current forced-off state of backlights. - bool backlights_forced_off_ = false; - - // True if the screen was off when the power button was pressed. - bool screen_off_when_power_button_down_ = false; - - // Time source for performed action times. - std::unique_ptr<base::TickClock> tick_clock_; - - // Saves the most recent timestamp that powerd is resuming from suspend, - // updated in SuspendDone(). - base::TimeTicks last_resume_time_; - - // Saves the most recent timestamp that power button is released. - base::TimeTicks last_button_up_time_; - - // True if power button released should force off display. - bool force_off_on_button_up_; - - // Started when the tablet power button is pressed and stopped when it's - // released. Runs OnShutdownTimeout() to start shutdown. - base::OneShotTimer shutdown_timer_; - - LockStateController* controller_; // Not owned. - - base::WeakPtrFactory<TabletPowerButtonController> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonController); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_TABLET_POWER_BUTTON_CONTROLLER_H_
diff --git a/ash/system/power/tablet_power_button_controller_unittest.cc b/ash/system/power/tablet_power_button_controller_unittest.cc deleted file mode 100644 index e9a1373..0000000 --- a/ash/system/power/tablet_power_button_controller_unittest.cc +++ /dev/null
@@ -1,481 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/tablet_power_button_controller.h" - -#include <memory> - -#include "ash/common/ash_switches.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/shell.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/lock_state_controller_test_api.h" -#include "ash/test/test_shell_delegate.h" -#include "ash/wm/lock_state_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/power_button_controller.h" -#include "base/command_line.h" -#include "base/compiler_specific.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/test/simple_test_tick_clock.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_power_manager_client.h" -#include "ui/events/event.h" -#include "ui/events/test/event_generator.h" - -namespace ash { -namespace test { - -namespace { - -// A non-zero brightness used for test. -constexpr int kNonZeroBrightness = 10; - -void CopyResult(bool* dest, bool src) { - *dest = src; -} - -} // namespace - -class TabletPowerButtonControllerTest : public AshTestBase { - public: - TabletPowerButtonControllerTest() {} - ~TabletPowerButtonControllerTest() override {} - - void SetUp() override { - // This also initializes DBusThreadManager. - std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter = - chromeos::DBusThreadManager::GetSetterForTesting(); - power_manager_client_ = new chromeos::FakePowerManagerClient(); - dbus_setter->SetPowerManagerClient(base::WrapUnique(power_manager_client_)); - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kAshEnableTouchView); - AshTestBase::SetUp(); - - lock_state_controller_ = Shell::GetInstance()->lock_state_controller(); - tablet_controller_ = Shell::GetInstance() - ->power_button_controller() - ->tablet_power_button_controller_for_test(); - test_api_ = base::MakeUnique<TabletPowerButtonController::TestApi>( - tablet_controller_); - lock_state_test_api_ = - base::MakeUnique<LockStateControllerTestApi>(lock_state_controller_); - tick_clock_ = new base::SimpleTestTickClock; - tablet_controller_->SetTickClockForTesting( - std::unique_ptr<base::TickClock>(tick_clock_)); - shell_delegate_ = - static_cast<TestShellDelegate*>(WmShell::Get()->delegate()); - generator_ = &AshTestBase::GetEventGenerator(); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_FALSE(GetBacklightsForcedOff()); - } - - void TearDown() override { - generator_ = nullptr; - const bool is_mash = WmShell::Get()->IsRunningInMash(); - AshTestBase::TearDown(); - // Mash shuts down dbus after each test. - if (!is_mash) - chromeos::DBusThreadManager::Shutdown(); - } - - protected: - void PressPowerButton() { - tablet_controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); - } - - void ReleasePowerButton() { - tablet_controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); - } - - void UnlockScreen() { - lock_state_controller_->OnLockStateChanged(false); - WmShell::Get()->GetSessionStateDelegate()->UnlockScreen(); - } - - void Initialize(LoginStatus status) { - lock_state_controller_->OnLoginStateChanged(status); - SetUserLoggedIn(status != LoginStatus::NOT_LOGGED_IN); - lock_state_controller_->OnLockStateChanged(false); - } - - void EnableMaximizeMode(bool enabled) { - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - enabled); - } - - bool GetLockedState() { - return WmShell::Get()->GetSessionStateDelegate()->IsScreenLocked(); - } - - bool GetBacklightsForcedOff() WARN_UNUSED_RESULT { - bool forced_off = false; - power_manager_client_->GetBacklightsForcedOff( - base::Bind(&CopyResult, base::Unretained(&forced_off))); - base::RunLoop().RunUntilIdle(); - return forced_off; - } - - // Ownership is passed on to chromeos::DBusThreadManager. - chromeos::FakePowerManagerClient* power_manager_client_; - - LockStateController* lock_state_controller_; // Not owned. - TabletPowerButtonController* tablet_controller_; // Not owned. - std::unique_ptr<TabletPowerButtonController::TestApi> test_api_; - std::unique_ptr<LockStateControllerTestApi> lock_state_test_api_; - base::SimpleTestTickClock* tick_clock_; // Not owned. - TestShellDelegate* shell_delegate_; // Not owned. - ui::test::EventGenerator* generator_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(TabletPowerButtonControllerTest); -}; - -TEST_F(TabletPowerButtonControllerTest, LockScreenIfRequired) { - Initialize(LoginStatus::USER); - SetShouldLockScreenAutomatically(true); - EXPECT_FALSE(GetLockedState()); - - // On User logged in status, power-button-press-release should lock screen if - // automatic screen-locking was requested. - PressPowerButton(); - ReleasePowerButton(); - EXPECT_TRUE(GetLockedState()); - - // On locked state, power-button-press-release should do nothing. - PressPowerButton(); - ReleasePowerButton(); - EXPECT_TRUE(GetLockedState()); - - // Unlock the sceen. - UnlockScreen(); - ASSERT_FALSE(GetLockedState()); - - // power-button-press-release should not lock the screen if automatic - // screen-locking wasn't requested. - SetShouldLockScreenAutomatically(false); - PressPowerButton(); - ReleasePowerButton(); - EXPECT_FALSE(GetLockedState()); -} - -// Tests that shutdown animation is not started if the power button is released -// quickly. -TEST_F(TabletPowerButtonControllerTest, - ReleasePowerButtonBeforeStartingShutdownAnimation) { - PressPowerButton(); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - EXPECT_FALSE(GetBacklightsForcedOff()); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - EXPECT_TRUE(GetBacklightsForcedOff()); - - PressPowerButton(); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - EXPECT_FALSE(GetBacklightsForcedOff()); - ReleasePowerButton(); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - EXPECT_FALSE(GetBacklightsForcedOff()); -} - -// Tests that the shutdown animation is started when the power button is -// released after the timer fires. -TEST_F(TabletPowerButtonControllerTest, - ReleasePowerButtonDuringShutdownAnimation) { - PressPowerButton(); - test_api_->TriggerShutdownTimeout(); - EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); - ReleasePowerButton(); - EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Test again when backlights is forced off. - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - - PressPowerButton(); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_FALSE(GetBacklightsForcedOff()); - test_api_->TriggerShutdownTimeout(); - EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); - ReleasePowerButton(); - EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); - EXPECT_FALSE(GetBacklightsForcedOff()); -} - -// Tests tapping power button when screen is idle off. -TEST_F(TabletPowerButtonControllerTest, TappingPowerButtonWhenScreenIsIdleOff) { - power_manager_client_->SendBrightnessChanged(0, false); - PressPowerButton(); - EXPECT_FALSE(GetBacklightsForcedOff()); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - ReleasePowerButton(); - EXPECT_FALSE(GetBacklightsForcedOff()); -} - -// Tests tapping power button when device is suspended without backlights forced -// off. -TEST_F(TabletPowerButtonControllerTest, - TappingPowerButtonWhenSuspendedWithoutBacklightsForcedOff) { - power_manager_client_->SendSuspendImminent(); - power_manager_client_->SendBrightnessChanged(0, false); - // There is a power button pressed here, but PowerButtonEvent is sent later. - power_manager_client_->SendSuspendDone(); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - - // Send the power button event after a short delay and check that backlights - // are not forced off. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(500)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Send the power button event after a longer delay and check that backlights - // are forced off. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1600)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - EXPECT_TRUE(GetBacklightsForcedOff()); -} - -// Tests tapping power button when device is suspended with backlights forced -// off. -TEST_F(TabletPowerButtonControllerTest, - TappingPowerButtonWhenSuspendedWithBacklightsForcedOff) { - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - power_manager_client_->SendSuspendImminent(); - // There is a power button pressed here, but PowerButtonEvent is sent later. - // Because of backlights forced off, resuming system will not restore - // brightness. - power_manager_client_->SendSuspendDone(); - - // Send the power button event after a short delay and check that backlights - // are not forced off. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(500)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Send the power button event after a longer delay and check that backlights - // are forced off. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1600)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - EXPECT_TRUE(GetBacklightsForcedOff()); -} - -// For convertible device working on laptop mode, tests keyboard/mouse event -// when screen is off. -TEST_F(TabletPowerButtonControllerTest, ConvertibleOnLaptopMode) { - EnableMaximizeMode(false); - - // KeyEvent should SetBacklightsForcedOff(false). - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - generator_->PressKey(ui::VKEY_L, ui::EF_NONE); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Regular mouse event should SetBacklightsForcedOff(false). - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - generator_->MoveMouseBy(1, 1); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Synthesized mouse event should not SetBacklightsForcedOff(false). - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - generator_->set_flags(ui::EF_IS_SYNTHESIZED); - generator_->MoveMouseBy(1, 1); - generator_->set_flags(ui::EF_NONE); - EXPECT_TRUE(GetBacklightsForcedOff()); -} - -// For convertible device working on tablet mode, keyboard/mouse event should -// not SetBacklightsForcedOff(false) when screen is off. -TEST_F(TabletPowerButtonControllerTest, ConvertibleOnMaximizeMode) { - EnableMaximizeMode(true); - - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - generator_->PressKey(ui::VKEY_L, ui::EF_NONE); - EXPECT_TRUE(GetBacklightsForcedOff()); - - generator_->MoveMouseBy(1, 1); - EXPECT_TRUE(GetBacklightsForcedOff()); -} - -// Tests that a single set of power button pressed-and-released operation should -// cause only one SetBacklightsForcedOff call. -TEST_F(TabletPowerButtonControllerTest, IgnorePowerOnKeyEvent) { - ui::KeyEvent power_key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_POWER, - ui::EF_NONE); - ui::KeyEvent power_key_released(ui::ET_KEY_RELEASED, ui::VKEY_POWER, - ui::EF_NONE); - - // There are two |power_key_pressed| events and |power_key_released| events - // generated for each pressing and releasing, and multiple repeating pressed - // events depending on holding. - tablet_controller_->OnKeyEvent(&power_key_pressed); - tablet_controller_->OnKeyEvent(&power_key_pressed); - PressPowerButton(); - tablet_controller_->OnKeyEvent(&power_key_pressed); - tablet_controller_->OnKeyEvent(&power_key_pressed); - tablet_controller_->OnKeyEvent(&power_key_pressed); - ReleasePowerButton(); - tablet_controller_->OnKeyEvent(&power_key_released); - tablet_controller_->OnKeyEvent(&power_key_released); - EXPECT_EQ(1, power_manager_client_->num_set_backlights_forced_off_calls()); -} - -// Tests that under (1) tablet power button pressed/released, (2) keyboard/mouse -// events on laptop mode when screen is off, requesting/stopping backlights -// forced off should also set corresponding touch screen state in local pref. -TEST_F(TabletPowerButtonControllerTest, TouchScreenState) { - // Tests tablet power button. - EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_FALSE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); - - PressPowerButton(); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - ReleasePowerButton(); - EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); - - EnableMaximizeMode(false); - // KeyEvent on laptop mode when screen is off. - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - EXPECT_FALSE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); - generator_->PressKey(ui::VKEY_L, ui::EF_NONE); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); - - // MouseEvent on laptop mode when screen is off. - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - EXPECT_FALSE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); - generator_->MoveMouseBy(1, 1); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - EXPECT_TRUE(shell_delegate_->IsTouchscreenEnabledInPrefs(true)); -} - -// When user switches convertible device between laptop mode and tablet mode, -// power button may be pressed and held, which may cause unwanted shutdown. -TEST_F(TabletPowerButtonControllerTest, - EnterOrLeaveMaximizeModeWhilePressingPowerButton) { - Initialize(LoginStatus::USER); - SetShouldLockScreenAutomatically(true); - EXPECT_FALSE(GetLockedState()); - - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - tablet_controller_->OnMaximizeModeStarted(); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1500)); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(GetLockedState()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - test_api_->TriggerShutdownTimeout(); - EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); - tablet_controller_->OnMaximizeModeStarted(); - EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(2500)); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(GetLockedState()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - EXPECT_TRUE(test_api_->ShutdownTimerIsRunning()); - tablet_controller_->OnMaximizeModeEnded(); - EXPECT_FALSE(test_api_->ShutdownTimerIsRunning()); - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(3500)); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(GetLockedState()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - test_api_->TriggerShutdownTimeout(); - EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running()); - tablet_controller_->OnMaximizeModeEnded(); - EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running()); - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(4500)); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(GetLockedState()); - EXPECT_FALSE(GetBacklightsForcedOff()); -} - -// Tests that repeated power button releases are ignored (crbug.com/675291). -TEST_F(TabletPowerButtonControllerTest, IgnoreRepeatedPowerButtonReleases) { - // Advance a long duration from initialized last resume time in - // |tablet_controller_| to avoid cross interference. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(2000)); - - // Set backlights forced off for starting point. - PressPowerButton(); - ReleasePowerButton(); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); - - // Test that a pressing-releasing operation after a short duration, backlights - // forced off is stopped since we don't drop request for power button pressed. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Test that after another short duration, backlights will not be forced off - // since this immediately following forcing off request needs to be dropped. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(200)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - EXPECT_FALSE(GetBacklightsForcedOff()); - - // Test that after another long duration, backlights should be forced off. - tick_clock_->Advance(base::TimeDelta::FromMilliseconds(800)); - power_manager_client_->SendPowerButtonEvent(true, tick_clock_->NowTicks()); - power_manager_client_->SendPowerButtonEvent(false, tick_clock_->NowTicks()); - power_manager_client_->SendBrightnessChanged(0, false); - EXPECT_TRUE(GetBacklightsForcedOff()); -} - -} // namespace test -} // namespace ash
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc deleted file mode 100644 index 3cf6f61..0000000 --- a/ash/system/power/tray_power.cc +++ /dev/null
@@ -1,363 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/tray_power.h" - -#include <utility> - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/ash_switches.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/date/date_view.h" -#include "ash/system/devicetype_utils.h" -#include "ash/system/power/battery_notification.h" -#include "ash/system/power/dual_role_notification.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_utils.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/metrics/histogram.h" -#include "base/time/time.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/view.h" - -using message_center::MessageCenter; -using message_center::Notification; - -namespace ash { - -// Informs the TrayPower instance when a USB notification is closed. -class UsbNotificationDelegate : public message_center::NotificationDelegate { - public: - explicit UsbNotificationDelegate(TrayPower* tray_power) - : tray_power_(tray_power) {} - - // Overridden from message_center::NotificationDelegate. - void Close(bool by_user) override { - if (by_user) - tray_power_->NotifyUsbNotificationClosedByUser(); - } - - private: - ~UsbNotificationDelegate() override {} - - TrayPower* tray_power_; - - DISALLOW_COPY_AND_ASSIGN(UsbNotificationDelegate); -}; - -namespace { - -std::string GetNotificationStateString( - TrayPower::NotificationState notification_state) { - switch (notification_state) { - case TrayPower::NOTIFICATION_NONE: - return "none"; - case TrayPower::NOTIFICATION_LOW_POWER: - return "low power"; - case TrayPower::NOTIFICATION_CRITICAL: - return "critical power"; - } - NOTREACHED() << "Unknown state " << notification_state; - return "Unknown state"; -} - -void LogBatteryForUsbCharger(TrayPower::NotificationState state, - int battery_percent) { - LOG(WARNING) << "Showing " << GetNotificationStateString(state) - << " notification. USB charger is connected. " - << "Battery percentage: " << battery_percent << "%."; -} - -void LogBatteryForNoCharger(TrayPower::NotificationState state, - int remaining_minutes) { - LOG(WARNING) << "Showing " << GetNotificationStateString(state) - << " notification. No charger connected." - << " Remaining time: " << remaining_minutes << " minutes."; -} - -} // namespace - -namespace tray { - -// This view is used only for the tray. -class PowerTrayView : public TrayItemView { - public: - explicit PowerTrayView(SystemTrayItem* owner) : TrayItemView(owner) { - CreateImageView(); - UpdateImage(); - } - - ~PowerTrayView() override {} - - // Overriden from views::View. - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->SetName(accessible_name_); - node_data->role = ui::AX_ROLE_BUTTON; - } - - void UpdateStatus(bool battery_alert) { - UpdateImage(); - SetVisible(PowerStatus::Get()->IsBatteryPresent()); - - if (battery_alert) { - accessible_name_ = PowerStatus::Get()->GetAccessibleNameString(true); - NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); - } - } - - private: - void UpdateImage() { - const PowerStatus::BatteryImageInfo info = - PowerStatus::Get()->GetBatteryImageInfo(PowerStatus::ICON_LIGHT); - if (info != previous_image_info_) { - image_view()->SetImage(PowerStatus::Get()->GetBatteryImage(info)); - previous_image_info_ = info; - } - } - - base::string16 accessible_name_; - - // Information about the last-used image. Cached to avoid unnecessary updates - // (http://crbug.com/589348). - PowerStatus::BatteryImageInfo previous_image_info_; - - DISALLOW_COPY_AND_ASSIGN(PowerTrayView); -}; - -} // namespace tray - -const int TrayPower::kCriticalMinutes = 5; -const int TrayPower::kLowPowerMinutes = 15; -const int TrayPower::kNoWarningMinutes = 30; -const int TrayPower::kCriticalPercentage = 5; -const int TrayPower::kLowPowerPercentage = 10; -const int TrayPower::kNoWarningPercentage = 15; - -const char TrayPower::kUsbNotificationId[] = "usb-charger"; - -TrayPower::TrayPower(SystemTray* system_tray, MessageCenter* message_center) - : SystemTrayItem(system_tray, UMA_POWER), - message_center_(message_center), - power_tray_(NULL), - notification_state_(NOTIFICATION_NONE), - usb_charger_was_connected_(false), - line_power_was_connected_(false), - usb_notification_dismissed_(false) { - PowerStatus::Get()->AddObserver(this); -} - -TrayPower::~TrayPower() { - PowerStatus::Get()->RemoveObserver(this); - message_center_->RemoveNotification(kUsbNotificationId, false); -} - -views::View* TrayPower::CreateTrayView(LoginStatus status) { - // There may not be enough information when this is created about whether - // there is a battery or not. So always create this, and adjust visibility as - // necessary. - CHECK(power_tray_ == NULL); - power_tray_ = new tray::PowerTrayView(this); - power_tray_->UpdateStatus(false); - return power_tray_; -} - -views::View* TrayPower::CreateDefaultView(LoginStatus status) { - // Make sure icon status is up to date. (Also triggers stub activation). - PowerStatus::Get()->RequestStatusUpdate(); - return NULL; -} - -void TrayPower::DestroyTrayView() { - power_tray_ = NULL; -} - -void TrayPower::DestroyDefaultView() {} - -void TrayPower::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayPower::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - SetTrayImageItemBorder(power_tray_, alignment); -} - -void TrayPower::OnPowerStatusChanged() { - bool battery_alert = UpdateNotificationState(); - if (power_tray_) - power_tray_->UpdateStatus(battery_alert); - - // Factory testing may place the battery into unusual states. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - ash::switches::kAshHideNotificationsForFactory)) - return; - - MaybeShowUsbChargerNotification(); - MaybeShowDualRoleNotification(); - - if (battery_alert) { - // Remove any existing notification so it's dismissed before adding a new - // one. Otherwise we might update a "low battery" notification to "critical" - // without it being shown again. - battery_notification_.reset(); - battery_notification_.reset( - new BatteryNotification(message_center_, notification_state_)); - } else if (notification_state_ == NOTIFICATION_NONE) { - battery_notification_.reset(); - } else if (battery_notification_.get()) { - battery_notification_->Update(notification_state_); - } - - usb_charger_was_connected_ = PowerStatus::Get()->IsUsbChargerConnected(); - line_power_was_connected_ = PowerStatus::Get()->IsLinePowerConnected(); -} - -bool TrayPower::MaybeShowUsbChargerNotification() { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const PowerStatus& status = *PowerStatus::Get(); - - bool usb_charger_is_connected = status.IsUsbChargerConnected(); - - // Check for a USB charger being connected. - if (usb_charger_is_connected && !usb_charger_was_connected_ && - !usb_notification_dismissed_) { - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kUsbNotificationId, - rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_TITLE), - ash::SubstituteChromeOSDeviceType( - IDS_ASH_STATUS_TRAY_LOW_POWER_CHARGER_MESSAGE_SHORT), - rb.GetImageNamed(IDR_AURA_NOTIFICATION_LOW_POWER_CHARGER), - base::string16(), GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierPower), - message_center::RichNotificationData(), - new UsbNotificationDelegate(this))); - message_center_->AddNotification(std::move(notification)); - return true; - } else if (!usb_charger_is_connected && usb_charger_was_connected_) { - // USB charger was unplugged or was identified as a different type while - // the USB charger notification was showing. - message_center_->RemoveNotification(kUsbNotificationId, false); - if (!status.IsLinePowerConnected()) - usb_notification_dismissed_ = false; - return true; - } - return false; -} - -void TrayPower::MaybeShowDualRoleNotification() { - const PowerStatus& status = *PowerStatus::Get(); - if (!status.HasDualRoleDevices()) { - dual_role_notification_.reset(); - return; - } - - if (!dual_role_notification_) - dual_role_notification_.reset(new DualRoleNotification(message_center_)); - dual_role_notification_->Update(); -} - -bool TrayPower::UpdateNotificationState() { - const PowerStatus& status = *PowerStatus::Get(); - if (!status.IsBatteryPresent() || status.IsBatteryTimeBeingCalculated() || - status.IsMainsChargerConnected()) { - notification_state_ = NOTIFICATION_NONE; - return false; - } - - return status.IsUsbChargerConnected() - ? UpdateNotificationStateForRemainingPercentage() - : UpdateNotificationStateForRemainingTime(); -} - -bool TrayPower::UpdateNotificationStateForRemainingTime() { - // The notification includes a rounded minutes value, so round the estimate - // received from the power manager to match. - const int remaining_minutes = static_cast<int>( - PowerStatus::Get()->GetBatteryTimeToEmpty().InSecondsF() / 60.0 + 0.5); - - if (remaining_minutes >= kNoWarningMinutes || - PowerStatus::Get()->IsBatteryFull()) { - notification_state_ = NOTIFICATION_NONE; - return false; - } - - switch (notification_state_) { - case NOTIFICATION_NONE: - if (remaining_minutes <= kCriticalMinutes) { - notification_state_ = NOTIFICATION_CRITICAL; - LogBatteryForNoCharger(notification_state_, remaining_minutes); - return true; - } - if (remaining_minutes <= kLowPowerMinutes) { - notification_state_ = NOTIFICATION_LOW_POWER; - LogBatteryForNoCharger(notification_state_, remaining_minutes); - return true; - } - return false; - case NOTIFICATION_LOW_POWER: - if (remaining_minutes <= kCriticalMinutes) { - notification_state_ = NOTIFICATION_CRITICAL; - LogBatteryForNoCharger(notification_state_, remaining_minutes); - return true; - } - return false; - case NOTIFICATION_CRITICAL: - return false; - } - NOTREACHED(); - return false; -} - -bool TrayPower::UpdateNotificationStateForRemainingPercentage() { - // The notification includes a rounded percentage, so round the value received - // from the power manager to match. - const int remaining_percentage = - PowerStatus::Get()->GetRoundedBatteryPercent(); - - if (remaining_percentage >= kNoWarningPercentage || - PowerStatus::Get()->IsBatteryFull()) { - notification_state_ = NOTIFICATION_NONE; - return false; - } - - switch (notification_state_) { - case NOTIFICATION_NONE: - if (remaining_percentage <= kCriticalPercentage) { - notification_state_ = NOTIFICATION_CRITICAL; - LogBatteryForUsbCharger(notification_state_, remaining_percentage); - return true; - } - if (remaining_percentage <= kLowPowerPercentage) { - notification_state_ = NOTIFICATION_LOW_POWER; - LogBatteryForUsbCharger(notification_state_, remaining_percentage); - return true; - } - return false; - case NOTIFICATION_LOW_POWER: - if (remaining_percentage <= kCriticalPercentage) { - notification_state_ = NOTIFICATION_CRITICAL; - LogBatteryForUsbCharger(notification_state_, remaining_percentage); - return true; - } - return false; - case NOTIFICATION_CRITICAL: - return false; - } - NOTREACHED(); - return false; -} - -void TrayPower::NotifyUsbNotificationClosedByUser() { - usb_notification_dismissed_ = true; -} - -} // namespace ash
diff --git a/ash/system/power/tray_power.h b/ash/system/power/tray_power.h deleted file mode 100644 index ebaf5c7b..0000000 --- a/ash/system/power/tray_power.h +++ /dev/null
@@ -1,117 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_TRAY_POWER_H_ -#define ASH_SYSTEM_POWER_TRAY_POWER_H_ - -#include <memory> - -#include "ash/system/power/power_status.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace message_center { -class MessageCenter; -} - -namespace ash { - -class BatteryNotification; -class DualRoleNotification; - -namespace tray { -class PowerTrayView; -} - -class ASH_EXPORT TrayPower : public SystemTrayItem, - public PowerStatus::Observer { - public: - enum NotificationState { - NOTIFICATION_NONE, - - // Low battery charge. - NOTIFICATION_LOW_POWER, - - // Critically low battery charge. - NOTIFICATION_CRITICAL, - }; - - // Time-based notification thresholds when on battery power. - static const int kCriticalMinutes; - static const int kLowPowerMinutes; - static const int kNoWarningMinutes; - - // Percentage-based notification thresholds when using a low-power charger. - static const int kCriticalPercentage; - static const int kLowPowerPercentage; - static const int kNoWarningPercentage; - - static const char kUsbNotificationId[]; - - TrayPower(SystemTray* system_tray, - message_center::MessageCenter* message_center); - ~TrayPower() override; - - void NotifyUsbNotificationClosedByUser(); - - private: - friend class TrayPowerTest; - - // This enum is used for histogram. The existing values should not be removed, - // and the new values should be added just before CHARGER_TYPE_COUNT. - enum ChargerType { - UNKNOWN_CHARGER, - MAINS_CHARGER, - USB_CHARGER, - UNCONFIRMED_SPRING_CHARGER, - SAFE_SPRING_CHARGER, - CHARGER_TYPE_COUNT, - }; - - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // Overridden from PowerStatus::Observer. - void OnPowerStatusChanged() override; - - // Shows a notification that a low-power USB charger has been connected. - // Returns true if a notification was shown or explicitly hidden. - bool MaybeShowUsbChargerNotification(); - - // Shows a notification when dual-role devices are connected. - void MaybeShowDualRoleNotification(); - - // Sets |notification_state_|. Returns true if a notification should be shown. - bool UpdateNotificationState(); - bool UpdateNotificationStateForRemainingTime(); - bool UpdateNotificationStateForRemainingPercentage(); - - message_center::MessageCenter* message_center_; // Not owned. - tray::PowerTrayView* power_tray_; - std::unique_ptr<BatteryNotification> battery_notification_; - std::unique_ptr<DualRoleNotification> dual_role_notification_; - NotificationState notification_state_; - - // Was a USB charger connected the last time OnPowerStatusChanged() was - // called? - bool usb_charger_was_connected_; - - // Was line power connected the last time onPowerStatusChanged() was called? - bool line_power_was_connected_; - - // Has the user already dismissed a low-power notification? Should be set - // back to false when all power sources are disconnected. - bool usb_notification_dismissed_; - - DISALLOW_COPY_AND_ASSIGN(TrayPower); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_TRAY_POWER_H_
diff --git a/ash/system/power/tray_power_unittest.cc b/ash/system/power/tray_power_unittest.cc deleted file mode 100644 index fcdbb4a..0000000 --- a/ash/system/power/tray_power_unittest.cc +++ /dev/null
@@ -1,434 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/tray_power.h" - -#include <map> -#include <memory> -#include <string> - -#include "ash/test/ash_test_base.h" -#include "chromeos/dbus/power_manager/power_supply_properties.pb.h" -#include "ui/message_center/fake_message_center.h" - -using message_center::Notification; -using power_manager::PowerSupplyProperties; - -namespace { - -class MockMessageCenter : public message_center::FakeMessageCenter { - public: - MockMessageCenter() : add_count_(0), remove_count_(0), update_count_(0) {} - ~MockMessageCenter() override {} - - int add_count() const { return add_count_; } - int remove_count() const { return remove_count_; } - int update_count() const { return update_count_; } - - // message_center::FakeMessageCenter overrides: - void AddNotification(std::unique_ptr<Notification> notification) override { - add_count_++; - notifications_.insert( - std::make_pair(notification->id(), std::move(notification))); - } - void RemoveNotification(const std::string& id, bool by_user) override { - Notification* notification = FindVisibleNotificationById(id); - if (notification && notification->delegate()) - notification->delegate()->Close(by_user); - remove_count_++; - notifications_.erase(id); - } - void UpdateNotification( - const std::string& id, - std::unique_ptr<Notification> new_notification) override { - update_count_++; - Notification* notification = FindVisibleNotificationById(id); - if (notification) - notifications_.erase(id); - notifications_.insert( - std::make_pair(new_notification->id(), std::move(new_notification))); - } - - Notification* FindVisibleNotificationById(const std::string& id) override { - auto it = notifications_.find(id); - return it == notifications_.end() ? NULL : it->second.get(); - } - - private: - int add_count_; - int remove_count_; - int update_count_; - std::map<std::string, std::unique_ptr<Notification>> notifications_; - - DISALLOW_COPY_AND_ASSIGN(MockMessageCenter); -}; - -} // namespace - -namespace ash { - -class TrayPowerTest : public test::AshTestBase { - public: - TrayPowerTest() {} - ~TrayPowerTest() override {} - - MockMessageCenter* message_center() { return message_center_.get(); } - TrayPower* tray_power() { return tray_power_.get(); } - - // test::AshTestBase::SetUp() overrides: - void SetUp() override { - test::AshTestBase::SetUp(); - message_center_.reset(new MockMessageCenter()); - tray_power_.reset(new TrayPower(NULL, message_center_.get())); - } - - void TearDown() override { - tray_power_.reset(); - message_center_.reset(); - test::AshTestBase::TearDown(); - } - - TrayPower::NotificationState notification_state() const { - return tray_power_->notification_state_; - } - - bool MaybeShowUsbChargerNotification(const PowerSupplyProperties& proto) { - PowerStatus::Get()->SetProtoForTesting(proto); - return tray_power_->MaybeShowUsbChargerNotification(); - } - - void MaybeShowDualRoleNotification(const PowerSupplyProperties& proto) { - PowerStatus::Get()->SetProtoForTesting(proto); - tray_power_->MaybeShowDualRoleNotification(); - } - - void UpdateNotificationState(const PowerSupplyProperties& proto, - TrayPower::NotificationState expected_state, - bool expected_add, - bool expected_remove) { - int prev_add = message_center_->add_count(); - int prev_remove = message_center_->remove_count(); - PowerStatus::Get()->SetProtoForTesting(proto); - tray_power_->OnPowerStatusChanged(); - EXPECT_EQ(expected_state, notification_state()); - EXPECT_EQ(expected_add, message_center_->add_count() == prev_add + 1); - EXPECT_EQ(expected_remove, - message_center_->remove_count() == prev_remove + 1); - } - - void SetUsbChargerConnected(bool connected) { - tray_power_->usb_charger_was_connected_ = connected; - } - - // Returns a discharging PowerSupplyProperties more appropriate for testing. - static PowerSupplyProperties DefaultPowerSupplyProperties() { - PowerSupplyProperties proto; - proto.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED); - proto.set_battery_state( - power_manager::PowerSupplyProperties_BatteryState_DISCHARGING); - proto.set_battery_percent(50.0); - proto.set_battery_time_to_empty_sec(3 * 60 * 60); - proto.set_battery_time_to_full_sec(2 * 60 * 60); - proto.set_is_calculating_battery_time(false); - return proto; - } - - private: - std::unique_ptr<MockMessageCenter> message_center_; - std::unique_ptr<TrayPower> tray_power_; - - DISALLOW_COPY_AND_ASSIGN(TrayPowerTest); -}; - -TEST_F(TrayPowerTest, MaybeShowUsbChargerNotification) { - PowerSupplyProperties discharging = DefaultPowerSupplyProperties(); - EXPECT_FALSE(MaybeShowUsbChargerNotification(discharging)); - EXPECT_EQ(0, message_center()->add_count()); - EXPECT_EQ(0, message_center()->remove_count()); - - // Notification shows when connecting a USB charger. - PowerSupplyProperties usb_connected = DefaultPowerSupplyProperties(); - usb_connected.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected)); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(0, message_center()->remove_count()); - SetUsbChargerConnected(true); - - // Change in charge does not trigger the notification again. - PowerSupplyProperties more_charge = DefaultPowerSupplyProperties(); - more_charge.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - more_charge.set_battery_time_to_full_sec(60 * 60); - more_charge.set_battery_percent(75.0); - EXPECT_FALSE(MaybeShowUsbChargerNotification(more_charge)); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(0, message_center()->remove_count()); - - // Disconnecting a USB charger with the notification showing should close - // the notification. - EXPECT_TRUE(MaybeShowUsbChargerNotification(discharging)); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(1, message_center()->remove_count()); - SetUsbChargerConnected(false); - - // Notification shows when connecting a USB charger again. - EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected)); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(1, message_center()->remove_count()); - SetUsbChargerConnected(true); - - // Notification hides when external power switches to AC. - PowerSupplyProperties ac_charger = DefaultPowerSupplyProperties(); - ac_charger.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_AC); - EXPECT_TRUE(MaybeShowUsbChargerNotification(ac_charger)); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(2, message_center()->remove_count()); - SetUsbChargerConnected(false); - - // Notification shows when external power switches back to USB. - EXPECT_TRUE(MaybeShowUsbChargerNotification(usb_connected)); - EXPECT_EQ(3, message_center()->add_count()); - EXPECT_EQ(2, message_center()->remove_count()); - SetUsbChargerConnected(true); - - // Notification does not re-appear after being manually dismissed if - // power supply flickers between AC and USB charger. - message_center()->RemoveNotification(TrayPower::kUsbNotificationId, true); - EXPECT_EQ(3, message_center()->remove_count()); - EXPECT_TRUE(MaybeShowUsbChargerNotification(ac_charger)); - SetUsbChargerConnected(false); - EXPECT_FALSE(MaybeShowUsbChargerNotification(usb_connected)); - EXPECT_EQ(3, message_center()->add_count()); - SetUsbChargerConnected(true); - - // Notification appears again after being manually dismissed if the charger - // is removed, and then a USB charger is attached. - MaybeShowUsbChargerNotification(discharging); - EXPECT_EQ(3, message_center()->add_count()); - SetUsbChargerConnected(false); - MaybeShowUsbChargerNotification(usb_connected); - EXPECT_EQ(4, message_center()->add_count()); - SetUsbChargerConnected(true); -} - -TEST_F(TrayPowerTest, MaybeShowDualRoleNotification) { - PowerSupplyProperties discharging = DefaultPowerSupplyProperties(); - discharging.set_supports_dual_role_devices(true); - MaybeShowDualRoleNotification(discharging); - EXPECT_EQ(0, message_center()->add_count()); - EXPECT_EQ(0, message_center()->update_count()); - EXPECT_EQ(0, message_center()->remove_count()); - - // Notification shows when connecting a dual-role device. - PowerSupplyProperties dual_role = DefaultPowerSupplyProperties(); - dual_role.set_supports_dual_role_devices(true); - power_manager::PowerSupplyProperties_PowerSource* source = - dual_role.add_available_external_power_source(); - source->set_id("dual-role1"); - source->set_active_by_default(false); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(0, message_center()->update_count()); - EXPECT_EQ(0, message_center()->remove_count()); - - // Connecting another dual-role device updates the notification to be plural. - source = dual_role.add_available_external_power_source(); - source->set_id("dual-role2"); - source->set_active_by_default(false); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(1, message_center()->update_count()); - EXPECT_EQ(0, message_center()->remove_count()); - - // Connecting a 3rd dual-role device doesn't affect the notification. - source = dual_role.add_available_external_power_source(); - source->set_id("dual-role3"); - source->set_active_by_default(false); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(1, message_center()->update_count()); - EXPECT_EQ(0, message_center()->remove_count()); - - // Connecting a legacy USB device removes the notification. - PowerSupplyProperties legacy(dual_role); - power_manager::PowerSupplyProperties_PowerSource* legacy_source = - legacy.add_available_external_power_source(); - legacy_source->set_id("legacy"); - legacy_source->set_active_by_default(true); - legacy.set_external_power_source_id("legacy"); - legacy.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - MaybeShowDualRoleNotification(legacy); - EXPECT_EQ(1, message_center()->add_count()); - EXPECT_EQ(1, message_center()->update_count()); - EXPECT_EQ(1, message_center()->remove_count()); - - // Removing the legacy USB device adds the notification again. - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(1, message_center()->update_count()); - EXPECT_EQ(1, message_center()->remove_count()); - - // Charging from the device updates the notification. - dual_role.set_external_power_source_id("dual-role1"); - dual_role.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(2, message_center()->update_count()); - EXPECT_EQ(1, message_center()->remove_count()); - - // Adding a device as a sink doesn't change the notification, because the - // notification exposes the source. - source = dual_role.add_available_external_power_source(); - source->set_active_by_default(false); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(2, message_center()->update_count()); - EXPECT_EQ(1, message_center()->remove_count()); - - // Changing the source to a sink changes the notification. - dual_role.set_external_power_source_id(""); - dual_role.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(3, message_center()->update_count()); - EXPECT_EQ(1, message_center()->remove_count()); - - // An unrelated change has no effect. - dual_role.set_battery_time_to_empty_sec(2 * 60 * 60); - MaybeShowDualRoleNotification(dual_role); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(3, message_center()->update_count()); - EXPECT_EQ(1, message_center()->remove_count()); - - // Removing devices hides the notification. - MaybeShowDualRoleNotification(discharging); - EXPECT_EQ(2, message_center()->add_count()); - EXPECT_EQ(3, message_center()->update_count()); - EXPECT_EQ(2, message_center()->remove_count()); -} - -TEST_F(TrayPowerTest, UpdateNotificationState) { - // No notifications when no battery present. - PowerSupplyProperties no_battery = DefaultPowerSupplyProperties(); - no_battery.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_AC); - no_battery.set_battery_state( - power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT); - { - SCOPED_TRACE("No notifications when no battery present"); - UpdateNotificationState(no_battery, TrayPower::NOTIFICATION_NONE, false, - false); - } - - // No notification when calculating remaining battery time. - PowerSupplyProperties calculating = DefaultPowerSupplyProperties(); - calculating.set_is_calculating_battery_time(true); - { - SCOPED_TRACE("No notification when calculating remaining battery time"); - UpdateNotificationState(calculating, TrayPower::NOTIFICATION_NONE, false, - false); - } - - // No notification when charging. - PowerSupplyProperties charging = DefaultPowerSupplyProperties(); - charging.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_AC); - charging.set_battery_state( - power_manager::PowerSupplyProperties_BatteryState_CHARGING); - { - SCOPED_TRACE("No notification when charging"); - UpdateNotificationState(charging, TrayPower::NOTIFICATION_NONE, false, - false); - } - - // When the rounded minutes-to-empty are above the threshold, no notification - // should be shown. - PowerSupplyProperties low = DefaultPowerSupplyProperties(); - low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 30); - { - SCOPED_TRACE("No notification when time to empty above threshold"); - UpdateNotificationState(low, TrayPower::NOTIFICATION_NONE, false, false); - } - - // When the rounded value matches the threshold, the notification should - // appear. - low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 + 29); - { - SCOPED_TRACE("Notification when time to empty matches threshold"); - UpdateNotificationState(low, TrayPower::NOTIFICATION_LOW_POWER, true, - false); - } - - // It should persist at lower values. - low.set_battery_time_to_empty_sec(TrayPower::kLowPowerMinutes * 60 - 20); - { - SCOPED_TRACE("Notification persists at lower values"); - UpdateNotificationState(low, TrayPower::NOTIFICATION_LOW_POWER, false, - false); - } - - // The critical low battery notification should be shown when the rounded - // value is at the lower threshold. - PowerSupplyProperties critical = DefaultPowerSupplyProperties(); - critical.set_battery_time_to_empty_sec(TrayPower::kCriticalMinutes * 60 + 29); - { - SCOPED_TRACE("Critical notification when time to empty is critical"); - UpdateNotificationState(critical, TrayPower::NOTIFICATION_CRITICAL, true, - true); - } - - // The notification should be dismissed when the no-warning threshold is - // reached. - PowerSupplyProperties safe = DefaultPowerSupplyProperties(); - safe.set_battery_time_to_empty_sec(TrayPower::kNoWarningMinutes * 60 - 29); - { - SCOPED_TRACE("Notification removed when battery not low"); - UpdateNotificationState(safe, TrayPower::NOTIFICATION_NONE, false, true); - } - - // Test that rounded percentages are used when a USB charger is connected. - PowerSupplyProperties low_usb = DefaultPowerSupplyProperties(); - low_usb.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.5); - { - SCOPED_TRACE("No notification for rounded battery percent"); - UpdateNotificationState(low_usb, TrayPower::NOTIFICATION_NONE, true, false); - } - - low_usb.set_battery_percent(TrayPower::kLowPowerPercentage + 0.49); - { - SCOPED_TRACE("Notification for rounded low power percent"); - UpdateNotificationState(low_usb, TrayPower::NOTIFICATION_LOW_POWER, true, - false); - } - - PowerSupplyProperties critical_usb = DefaultPowerSupplyProperties(); - critical_usb.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - critical_usb.set_battery_percent(TrayPower::kCriticalPercentage + 0.2); - { - SCOPED_TRACE("Notification for rounded critical power percent"); - UpdateNotificationState(critical_usb, TrayPower::NOTIFICATION_CRITICAL, - true, true); - } - - PowerSupplyProperties safe_usb = DefaultPowerSupplyProperties(); - safe_usb.set_external_power( - power_manager::PowerSupplyProperties_ExternalPower_USB); - safe_usb.set_battery_percent(TrayPower::kNoWarningPercentage - 0.1); - { - SCOPED_TRACE("Notification removed for rounded percent above threshold"); - UpdateNotificationState(safe_usb, TrayPower::NOTIFICATION_NONE, false, - true); - } -} - -} // namespace ash
diff --git a/ash/system/power/video_activity_notifier.cc b/ash/system/power/video_activity_notifier.cc deleted file mode 100644 index c230eb59..0000000 --- a/ash/system/power/video_activity_notifier.cc +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/video_activity_notifier.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/shell.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/power_manager_client.h" - -namespace ash { -namespace { - -// Minimum number of seconds between repeated notifications of the same state. -// This should be less than powerd's timeout for determining whether video is -// still active for the purposes of controlling the keyboard backlight. -const int kNotifyIntervalSec = 5; - -} // namespace - -VideoActivityNotifier::VideoActivityNotifier(VideoDetector* detector) - : detector_(detector), - video_state_(detector->state()), - screen_is_locked_( - Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) { - detector_->AddObserver(this); - WmShell::Get()->AddShellObserver(this); - - MaybeNotifyPowerManager(); - UpdateTimer(); -} - -VideoActivityNotifier::~VideoActivityNotifier() { - WmShell::Get()->RemoveShellObserver(this); - detector_->RemoveObserver(this); -} - -void VideoActivityNotifier::OnVideoStateChanged(VideoDetector::State state) { - if (video_state_ != state) { - video_state_ = state; - MaybeNotifyPowerManager(); - UpdateTimer(); - } -} - -void VideoActivityNotifier::OnLockStateChanged(bool locked) { - if (screen_is_locked_ != locked) { - screen_is_locked_ = locked; - MaybeNotifyPowerManager(); - UpdateTimer(); - } -} - -bool VideoActivityNotifier::TriggerTimeoutForTest() { - if (!notify_timer_.IsRunning()) - return false; - - MaybeNotifyPowerManager(); - return true; -} - -void VideoActivityNotifier::UpdateTimer() { - if (!should_notify_power_manager()) { - notify_timer_.Stop(); - } else { - notify_timer_.Start(FROM_HERE, - base::TimeDelta::FromSeconds(kNotifyIntervalSec), this, - &VideoActivityNotifier::MaybeNotifyPowerManager); - } -} - -void VideoActivityNotifier::MaybeNotifyPowerManager() { - if (should_notify_power_manager()) { - chromeos::DBusThreadManager::Get() - ->GetPowerManagerClient() - ->NotifyVideoActivity(video_state_ == - VideoDetector::State::PLAYING_FULLSCREEN); - } -} - -} // namespace ash
diff --git a/ash/system/power/video_activity_notifier.h b/ash/system/power/video_activity_notifier.h deleted file mode 100644 index a3b378d..0000000 --- a/ash/system/power/video_activity_notifier.h +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_POWER_VIDEO_ACTIVITY_NOTIFIER_H_ -#define ASH_SYSTEM_POWER_VIDEO_ACTIVITY_NOTIFIER_H_ - -#include "ash/ash_export.h" -#include "ash/wm/video_detector.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/time/time.h" - -namespace ash { - -// Notifies the power manager when a video is playing. -class ASH_EXPORT VideoActivityNotifier : public VideoDetector::Observer, - public ShellObserver { - public: - explicit VideoActivityNotifier(VideoDetector* detector); - ~VideoActivityNotifier() override; - - // VideoDetector::Observer implementation. - void OnVideoStateChanged(VideoDetector::State state) override; - - // ShellObserver implementation. - void OnLockStateChanged(bool locked) override; - - // If |notify_timer_| is running, calls MaybeNotifyPowerManager() and returns - // true. Returns false otherwise. - bool TriggerTimeoutForTest() WARN_UNUSED_RESULT; - - private: - bool should_notify_power_manager() { - return video_state_ != VideoDetector::State::NOT_PLAYING && - !screen_is_locked_; - } - - // Starts or stops |notify_timer_| as needed. - void UpdateTimer(); - - // Notifies powerd about video activity if should_notify_power_manager() is - // true. - void MaybeNotifyPowerManager(); - - VideoDetector* detector_; // not owned - - // Most-recently-observed video state. - VideoDetector::State video_state_; - - // True if the screen is currently locked. - bool screen_is_locked_; - - // Periodically calls MaybeNotifyPowerManager() while - // should_notify_power_manager() is true. - base::RepeatingTimer notify_timer_; - - DISALLOW_COPY_AND_ASSIGN(VideoActivityNotifier); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_POWER_VIDEO_ACTIVITY_NOTIFIER_H_
diff --git a/ash/system/power/video_activity_notifier_unittest.cc b/ash/system/power/video_activity_notifier_unittest.cc deleted file mode 100644 index cb8d8650..0000000 --- a/ash/system/power/video_activity_notifier_unittest.cc +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/power/video_activity_notifier.h" - -#include <memory> - -#include "ash/test/ash_test_base.h" -#include "ash/wm/video_detector.h" -#include "base/macros.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_power_manager_client.h" - -namespace ash { - -class VideoActivityNotifierTest : public test::AshTestBase { - public: - VideoActivityNotifierTest() {} - ~VideoActivityNotifierTest() override {} - - void SetUp() override { - test::AshTestBase::SetUp(); - power_client_ = static_cast<chromeos::FakePowerManagerClient*>( - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()); - detector_.reset(new VideoDetector()); - notifier_.reset(new VideoActivityNotifier(detector_.get())); - } - - void TearDown() override { - notifier_.reset(); - detector_.reset(); - test::AshTestBase::TearDown(); - } - - protected: - chromeos::FakePowerManagerClient* power_client_; // Not owned. - - std::unique_ptr<VideoDetector> detector_; - std::unique_ptr<VideoActivityNotifier> notifier_; - - DISALLOW_COPY_AND_ASSIGN(VideoActivityNotifierTest); -}; - -// Test that powerd is notified immediately when video changes to a new playing -// state or the screen is unlocked. -TEST_F(VideoActivityNotifierTest, NotifyImmediatelyOnStateChange) { - EXPECT_FALSE(power_client_->have_video_activity_report()); - - notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); - EXPECT_FALSE(power_client_->PopVideoActivityReport()); - - notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_FULLSCREEN); - EXPECT_TRUE(power_client_->PopVideoActivityReport()); - - notifier_->OnLockStateChanged(true); - EXPECT_FALSE(power_client_->have_video_activity_report()); - - notifier_->OnLockStateChanged(false); - EXPECT_TRUE(power_client_->PopVideoActivityReport()); - - notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); - EXPECT_FALSE(power_client_->PopVideoActivityReport()); - - notifier_->OnVideoStateChanged(VideoDetector::State::NOT_PLAYING); - EXPECT_FALSE(power_client_->have_video_activity_report()); - - notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); - EXPECT_FALSE(power_client_->PopVideoActivityReport()); -} - -// Test that powerd is notified periodically while video is ongoing. -TEST_F(VideoActivityNotifierTest, NotifyPeriodically) { - // The timer shouldn't be running initially. - EXPECT_FALSE(notifier_->TriggerTimeoutForTest()); - - // The timer should start in response to windowed video. - notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_WINDOWED); - EXPECT_FALSE(power_client_->PopVideoActivityReport()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - EXPECT_TRUE(notifier_->TriggerTimeoutForTest()); - EXPECT_FALSE(power_client_->PopVideoActivityReport()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - - // After fullscreen video starts, the timer should start reporting that - // instead. - notifier_->OnVideoStateChanged(VideoDetector::State::PLAYING_FULLSCREEN); - EXPECT_TRUE(power_client_->PopVideoActivityReport()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - EXPECT_TRUE(notifier_->TriggerTimeoutForTest()); - EXPECT_TRUE(power_client_->PopVideoActivityReport()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - - // Locking the screen should stop the timer. - notifier_->OnLockStateChanged(true); - EXPECT_FALSE(notifier_->TriggerTimeoutForTest()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - - // Unlocking it should restart the timer. - notifier_->OnLockStateChanged(false); - EXPECT_TRUE(power_client_->PopVideoActivityReport()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - EXPECT_TRUE(notifier_->TriggerTimeoutForTest()); - EXPECT_TRUE(power_client_->PopVideoActivityReport()); - EXPECT_FALSE(power_client_->have_video_activity_report()); - - // The timer should stop when video video. - notifier_->OnVideoStateChanged(VideoDetector::State::NOT_PLAYING); - EXPECT_FALSE(notifier_->TriggerTimeoutForTest()); - EXPECT_FALSE(power_client_->have_video_activity_report()); -} - -} // namespace ash
diff --git a/ash/system/rotation/tray_rotation_lock.cc b/ash/system/rotation/tray_rotation_lock.cc deleted file mode 100644 index 502b5b4..0000000 --- a/ash/system/rotation/tray_rotation_lock.cc +++ /dev/null
@@ -1,219 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/rotation/tray_rotation_lock.h" - -#include "ash/common/wm_shell.h" -#include "ash/display/screen_orientation_controller_chromeos.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/display/display.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -namespace { - -bool IsMaximizeModeWindowManagerEnabled() { - return WmShell::Get() - ->maximize_mode_controller() - ->IsMaximizeModeWindowManagerEnabled(); -} - -bool IsRotationLocked() { - return Shell::GetInstance() - ->screen_orientation_controller() - ->rotation_locked(); -} - -} // namespace - -namespace tray { - -class RotationLockDefaultView : public ActionableView, - public ShellObserver, - public ScreenOrientationController::Observer { - public: - explicit RotationLockDefaultView(SystemTrayItem* owner); - ~RotationLockDefaultView() override; - - private: - // Updates icon and label according to current rotation lock status. - void Update(); - - // Stop observing rotation lock status. - void StopObservingRotation(); - - // ActionableView: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - bool PerformAction(const ui::Event& event) override; - - // ShellObserver: - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - - // ScreenOrientationController::Obsever: - void OnRotationLockChanged(bool rotation_locked) override; - - views::ImageView* icon_; - views::Label* label_; - - DISALLOW_COPY_AND_ASSIGN(RotationLockDefaultView); -}; - -RotationLockDefaultView::RotationLockDefaultView(SystemTrayItem* owner) - : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), - icon_(TrayPopupUtils::CreateMainImageView()), - label_(TrayPopupUtils::CreateDefaultLabel()) { - SetLayoutManager(new views::FillLayout); - - TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view); - - tri_view->AddView(TriView::Container::START, icon_); - tri_view->AddView(TriView::Container::CENTER, label_); - tri_view->SetContainerVisible(TriView::Container::END, false); - - Update(); - - SetInkDropMode(InkDropHostView::InkDropMode::ON); - - SetVisible(IsMaximizeModeWindowManagerEnabled()); - WmShell::Get()->AddShellObserver(this); - if (IsMaximizeModeWindowManagerEnabled()) - Shell::GetInstance()->screen_orientation_controller()->AddObserver(this); -} - -RotationLockDefaultView::~RotationLockDefaultView() { - StopObservingRotation(); - WmShell::Get()->RemoveShellObserver(this); -} - -void RotationLockDefaultView::Update() { - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - icon_->SetImage(gfx::CreateVectorIcon(IsRotationLocked() - ? kSystemMenuRotationLockLockedIcon - : kSystemMenuRotationLockAutoIcon, - kMenuIconSize, style.GetIconColor())); - - base::string16 label = l10n_util::GetStringUTF16( - IsRotationLocked() ? IDS_ASH_STATUS_TRAY_ROTATION_LOCK_LOCKED - : IDS_ASH_STATUS_TRAY_ROTATION_LOCK_AUTO); - label_->SetText(label); - style.SetupLabel(label_); - - Layout(); - SchedulePaint(); -} - -void RotationLockDefaultView::StopObservingRotation() { - ScreenOrientationController* controller = - Shell::GetInstance()->screen_orientation_controller(); - if (controller) - controller->RemoveObserver(this); -} - -void RotationLockDefaultView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - ActionableView::GetAccessibleNodeData(node_data); - if (!label_->text().empty()) - node_data->SetName(label_->text()); -} - -bool RotationLockDefaultView::PerformAction(const ui::Event& event) { - Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( - !IsRotationLocked()); - return true; -} - -void RotationLockDefaultView::OnMaximizeModeStarted() { - Update(); - SetVisible(true); - Shell::GetInstance()->screen_orientation_controller()->AddObserver(this); -} - -void RotationLockDefaultView::OnMaximizeModeEnded() { - SetVisible(false); - StopObservingRotation(); -} - -void RotationLockDefaultView::OnRotationLockChanged(bool rotation_locked) { - Update(); -} - -} // namespace tray - -TrayRotationLock::TrayRotationLock(SystemTray* system_tray) - : TrayImageItem(system_tray, - kSystemTrayRotationLockLockedIcon, - UMA_ROTATION_LOCK) { - WmShell::Get()->AddShellObserver(this); -} - -TrayRotationLock::~TrayRotationLock() { - WmShell::Get()->RemoveShellObserver(this); -} - -void TrayRotationLock::OnRotationLockChanged(bool rotation_locked) { - tray_view()->SetVisible(ShouldBeVisible()); -} - -views::View* TrayRotationLock::CreateDefaultView(LoginStatus status) { - if (OnPrimaryDisplay()) - return new tray::RotationLockDefaultView(this); - return nullptr; -} - -void TrayRotationLock::OnMaximizeModeStarted() { - tray_view()->SetVisible(IsRotationLocked()); - Shell::GetInstance()->screen_orientation_controller()->AddObserver(this); -} - -void TrayRotationLock::OnMaximizeModeEnded() { - tray_view()->SetVisible(false); - StopObservingRotation(); -} - -void TrayRotationLock::DestroyTrayView() { - StopObservingRotation(); - WmShell::Get()->RemoveShellObserver(this); - TrayImageItem::DestroyTrayView(); -} - -bool TrayRotationLock::GetInitialVisibility() { - return ShouldBeVisible(); -} - -bool TrayRotationLock::ShouldBeVisible() { - return OnPrimaryDisplay() && IsMaximizeModeWindowManagerEnabled() && - IsRotationLocked(); -} - -bool TrayRotationLock::OnPrimaryDisplay() const { - gfx::NativeView native_view = system_tray()->GetWidget()->GetNativeView(); - display::Display parent_display = - display::Screen::GetScreen()->GetDisplayNearestWindow(native_view); - return parent_display.IsInternal(); -} - -void TrayRotationLock::StopObservingRotation() { - ScreenOrientationController* controller = - Shell::GetInstance()->screen_orientation_controller(); - if (controller) - controller->RemoveObserver(this); -} - -} // namespace ash
diff --git a/ash/system/rotation/tray_rotation_lock.h b/ash/system/rotation/tray_rotation_lock.h deleted file mode 100644 index 6030b3c..0000000 --- a/ash/system/rotation/tray_rotation_lock.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_ROTATION_TRAY_ROTATION_LOCK_H_ -#define ASH_SYSTEM_ROTATION_TRAY_ROTATION_LOCK_H_ - -#include "ash/common/shell_observer.h" -#include "ash/display/screen_orientation_controller_chromeos.h" -#include "ash/system/tray/tray_image_item.h" -#include "base/macros.h" - -namespace ash { - -// TrayRotationLock is a provider of views for the SystemTray. Both a tray view -// and a default view are provided. Each view indicates the current state of -// the rotation lock for the display which it appears on. The default view can -// be interacted with, it toggles the state of the rotation lock. -// TrayRotationLock is only available on the primary display. -class ASH_EXPORT TrayRotationLock - : public TrayImageItem, - public ScreenOrientationController::Observer, - public ShellObserver { - public: - explicit TrayRotationLock(SystemTray* system_tray); - ~TrayRotationLock() override; - - // ScreenOrientationController::Observer: - void OnRotationLockChanged(bool rotation_locked) override; - - // SystemTrayItem: - views::View* CreateDefaultView(LoginStatus status) override; - - // ShellObserver: - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - - // TrayImageItem: - void DestroyTrayView() override; - - protected: - // TrayImageItem: - bool GetInitialVisibility() override; - - private: - friend class TrayRotationLockTest; - - // True if |on_primary_display_|, maximize mode is enabled, and rotation is - // locked. - bool ShouldBeVisible(); - - // True if this is owned by a SystemTray on the primary display. - bool OnPrimaryDisplay() const; - - // Removes TrayRotationLock as a ScreenOrientationController::Observer if - // currently observing. - void StopObservingRotation(); - - DISALLOW_COPY_AND_ASSIGN(TrayRotationLock); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_ROTATION_TRAY_ROTATION_LOCK_H_
diff --git a/ash/system/rotation/tray_rotation_lock_unittest.cc b/ash/system/rotation/tray_rotation_lock_unittest.cc deleted file mode 100644 index 82e15aa..0000000 --- a/ash/system/rotation/tray_rotation_lock_unittest.cc +++ /dev/null
@@ -1,267 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/rotation/tray_rotation_lock.h" - -#include <memory> - -#include "ash/common/wm_shell.h" -#include "ash/display/screen_orientation_controller_chromeos.h" -#include "ash/root_window_controller.h" -#include "ash/shell.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/status_area_widget_test_helper.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "base/command_line.h" -#include "base/time/time.h" -#include "ui/display/display_switches.h" -#include "ui/display/manager/display_manager.h" -#include "ui/display/types/display_constants.h" -#include "ui/events/event.h" -#include "ui/events/event_constants.h" -#include "ui/views/view.h" - -namespace ash { - -class TrayRotationLockTest : public test::AshTestBase { - public: - TrayRotationLockTest() {} - ~TrayRotationLockTest() override {} - - TrayRotationLock* tray() { return tray_.get(); } - - views::View* tray_view() { return tray_view_.get(); } - - views::View* default_view() { return default_view_.get(); } - - // Creates the tray view associated to |tray_rotation_lock|. - views::View* CreateTrayView(TrayRotationLock* tray_rotation_lock); - - // Destroys only the |tray_view_|. Tests may call this to simulate destruction - // order during the deletion of the StatusAreaWidget. - void DestroyTrayView(); - - // Sets up a TrayRotationLock, its tray view, and its default view, for the - // given SystemTray and its display. On a primary display all will be - // created. On a secondary display both the tray view and default view will - // be null. - void SetUpForStatusAreaWidget(StatusAreaWidget* status_area_widget); - - // Resets |tray_| |tray_view_| and |default_view_| so that all components of - // TrayRotationLock have been cleared. Tests may then call - // SetUpForStatusAreaWidget in order to initial the components. - void TearDownViews(); - - // test::AshTestBase: - void SetUp() override; - void TearDown() override; - - private: - std::unique_ptr<TrayRotationLock> tray_; - std::unique_ptr<views::View> tray_view_; - std::unique_ptr<views::View> default_view_; - - DISALLOW_COPY_AND_ASSIGN(TrayRotationLockTest); -}; - -views::View* TrayRotationLockTest::CreateTrayView( - TrayRotationLock* tray_rotation_lock) { - return tray_rotation_lock->CreateTrayView( - StatusAreaWidgetTestHelper::GetUserLoginStatus()); -} - -void TrayRotationLockTest::DestroyTrayView() { - tray_view_.reset(); - tray_->DestroyTrayView(); -} - -void TrayRotationLockTest::SetUpForStatusAreaWidget( - StatusAreaWidget* status_area_widget) { - tray_.reset(new TrayRotationLock(status_area_widget->system_tray())); - tray_view_.reset( - tray_->CreateTrayView(StatusAreaWidgetTestHelper::GetUserLoginStatus())); - default_view_.reset(tray_->CreateDefaultView( - StatusAreaWidgetTestHelper::GetUserLoginStatus())); -} - -void TrayRotationLockTest::TearDownViews() { - tray_view_.reset(); - default_view_.reset(); - tray_.reset(); -} - -void TrayRotationLockTest::SetUp() { - // The Display used for testing is not an internal display. This flag - // allows for DisplayManager to treat it as one. TrayRotationLock is only - // visible on internal primary displays. - base::CommandLine::ForCurrentProcess()->AppendSwitch( - ::switches::kUseFirstDisplayAsInternal); - test::AshTestBase::SetUp(); - SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); -} - -void TrayRotationLockTest::TearDown() { - TearDownViews(); - test::AshTestBase::TearDown(); -} - -// Tests that when the tray view is initially created, that it is created -// not visible. -TEST_F(TrayRotationLockTest, CreateTrayView) { - EXPECT_FALSE(tray_view()->visible()); -} - -// Tests that when the tray view is created, while MaximizeMode is active, that -// it is not visible. -TEST_F(TrayRotationLockTest, CreateTrayViewDuringMaximizeMode) { - TearDownViews(); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); - EXPECT_FALSE(tray_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); -} - -// Tests that when the tray view is created, while MaximizeMode is active, and -// rotation is locked, that it is visible. -TEST_F(TrayRotationLockTest, CreateTrayViewDuringMaximizeModeAndRotationLock) { - TearDownViews(); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( - true); - SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); - EXPECT_TRUE(tray_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - EXPECT_FALSE(tray_view()->visible()); -} - -// Tests that the enabling of MaximizeMode affects a previously created tray -// view, changing the visibility. -TEST_F(TrayRotationLockTest, TrayViewVisibilityChangesDuringMaximizeMode) { - ASSERT_FALSE(tray_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( - true); - EXPECT_TRUE(tray_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - EXPECT_FALSE(tray_view()->visible()); -} - -// Tests that the when the tray view is created for a secondary display, that -// it is not visible, and that MaximizeMode does not affect visibility. -TEST_F(TrayRotationLockTest, CreateSecondaryTrayView) { - UpdateDisplay("400x400,200x200"); - - SetUpForStatusAreaWidget( - StatusAreaWidgetTestHelper::GetSecondaryStatusAreaWidget()); - EXPECT_FALSE(tray_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - EXPECT_FALSE(tray_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - EXPECT_FALSE(tray_view()->visible()); -} - -// Tests that when the default view is initially created, that it is created -// not visible. -TEST_F(TrayRotationLockTest, CreateDefaultView) { - EXPECT_FALSE(default_view()->visible()); -} - -// Tests that when the default view is created, while MaximizeMode is active, -// that it is visible. -TEST_F(TrayRotationLockTest, CreateDefaultViewDuringMaximizeMode) { - TearDownViews(); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - SetUpForStatusAreaWidget(StatusAreaWidgetTestHelper::GetStatusAreaWidget()); - EXPECT_TRUE(default_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); -} - -// Tests that the enabling of MaximizeMode affects a previously created default -// view, changing the visibility. -TEST_F(TrayRotationLockTest, DefaultViewVisibilityChangesDuringMaximizeMode) { - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - EXPECT_TRUE(default_view()->visible()); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); - EXPECT_FALSE(default_view()->visible()); -} - -// Tests that no default view is created when the target is a secondary -// display. -TEST_F(TrayRotationLockTest, CreateSecondaryDefaultView) { - UpdateDisplay("400x400,200x200"); - - TearDownViews(); - SetUpForStatusAreaWidget( - StatusAreaWidgetTestHelper::GetSecondaryStatusAreaWidget()); - EXPECT_EQ(NULL, default_view()); -} - -// Tests that activating the default view causes the display to have its -// rotation locked, and that the tray view becomes visible. -TEST_F(TrayRotationLockTest, PerformActionOnDefaultView) { - MaximizeModeController* maximize_mode_controller = - WmShell::Get()->maximize_mode_controller(); - ScreenOrientationController* screen_orientation_controller = - Shell::GetInstance()->screen_orientation_controller(); - ASSERT_FALSE(screen_orientation_controller->rotation_locked()); - maximize_mode_controller->EnableMaximizeModeWindowManager(true); - ASSERT_FALSE(tray_view()->visible()); - - ui::GestureEvent tap(0, 0, 0, base::TimeTicks(), - ui::GestureEventDetails(ui::ET_GESTURE_TAP)); - default_view()->OnGestureEvent(&tap); - EXPECT_TRUE(screen_orientation_controller->rotation_locked()); - EXPECT_TRUE(tray_view()->visible()); - - maximize_mode_controller->EnableMaximizeModeWindowManager(false); -} - -// Tests that when the tray is created without the internal display being known, -// that it will still display correctly once the internal display is known. -TEST_F(TrayRotationLockTest, InternalDisplayNotAvailableAtCreation) { - int64_t internal_display_id = display::Display::InternalDisplayId(); - TearDownViews(); - display::Display::SetInternalDisplayId(display::kInvalidDisplayId); - - std::unique_ptr<TrayRotationLock> tray(new TrayRotationLock( - StatusAreaWidgetTestHelper::GetStatusAreaWidget()->system_tray())); - - display::Display::SetInternalDisplayId(internal_display_id); - std::unique_ptr<views::View> tray_view(CreateTrayView(tray.get())); - std::unique_ptr<views::View> default_view(tray->CreateDefaultView( - StatusAreaWidgetTestHelper::GetUserLoginStatus())); - EXPECT_TRUE(default_view); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - EXPECT_TRUE(default_view->visible()); -} - -// Tests that when the tray view is deleted, while TrayRotationLock has not been -// deleted, that updates to the rotation lock state do not crash. -TEST_F(TrayRotationLockTest, LockUpdatedDuringDesctruction) { - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - true); - DestroyTrayView(); - Shell::GetInstance()->screen_orientation_controller()->SetRotationLocked( - true); - WmShell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager( - false); -} - -} // namespace ash
diff --git a/ash/system/screen_layout_observer.cc b/ash/system/screen_layout_observer.cc deleted file mode 100644 index 672a990..0000000 --- a/ash/system/screen_layout_observer.cc +++ /dev/null
@@ -1,424 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/screen_layout_observer.h" - -#include <memory> -#include <utility> -#include <vector> - -#include "ash/common/wm_shell.h" -#include "ash/display/screen_orientation_controller_chromeos.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/devicetype_utils.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "base/bind.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/display/display.h" -#include "ui/display/manager/display_manager.h" -#include "ui/display/types/display_constants.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/strings/grit/ui_strings.h" - -using message_center::Notification; - -namespace ash { -namespace { - -display::DisplayManager* GetDisplayManager() { - return Shell::GetInstance()->display_manager(); -} - -base::string16 GetDisplayName(int64_t display_id) { - return base::UTF8ToUTF16( - GetDisplayManager()->GetDisplayNameForId(display_id)); -} - -base::string16 GetDisplaySize(int64_t display_id) { - display::DisplayManager* display_manager = GetDisplayManager(); - - const display::Display* display = - &display_manager->GetDisplayForId(display_id); - - // We don't show display size for mirrored display. Fallback - // to empty string if this happens on release build. - bool mirroring = display_manager->mirroring_display_id() == display_id; - DCHECK(!mirroring); - if (mirroring) - return base::string16(); - - DCHECK(display->is_valid()); - return base::UTF8ToUTF16(display->size().ToString()); -} - -// Attempts to open the display settings, returns true if successful. -bool OpenSettings() { - // switch is intentionally introduced without default, to cause an error when - // a new type of login status is introduced. - switch (WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()) { - case LoginStatus::NOT_LOGGED_IN: - case LoginStatus::LOCKED: - return false; - - case LoginStatus::USER: - case LoginStatus::OWNER: - case LoginStatus::GUEST: - case LoginStatus::PUBLIC: - case LoginStatus::SUPERVISED: - case LoginStatus::KIOSK_APP: - case LoginStatus::ARC_KIOSK_APP: - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (delegate->ShouldShowSettings()) { - WmShell::Get()->system_tray_controller()->ShowDisplaySettings(); - return true; - } - break; - } - - return false; -} - -// Callback to handle a user selecting the notification view. -void OpenSettingsFromNotification() { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED); - if (OpenSettings()) { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS); - } -} - -// Returns the name of the currently connected external display whose ID is -// |external_display_id|. This should not be used when the external display is -// used for mirroring. -base::string16 GetExternalDisplayName(int64_t external_display_id) { - DCHECK(!display::Display::IsInternalDisplayId(external_display_id)); - - display::DisplayManager* display_manager = GetDisplayManager(); - DCHECK(!display_manager->IsInMirrorMode()); - - if (external_display_id == display::kInvalidDisplayId) - return l10n_util::GetStringUTF16(IDS_DISPLAY_NAME_UNKNOWN); - - // The external display name may have an annotation of "(width x height)" in - // case that the display is rotated or its resolution is changed. - base::string16 name = GetDisplayName(external_display_id); - const display::ManagedDisplayInfo& display_info = - display_manager->GetDisplayInfo(external_display_id); - if (display_info.GetActiveRotation() != display::Display::ROTATE_0 || - display_info.configured_ui_scale() != 1.0f || - !display_info.overscan_insets_in_dip().IsEmpty()) { - name = - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, - name, GetDisplaySize(external_display_id)); - } else if (display_info.overscan_insets_in_dip().IsEmpty() && - display_info.has_overscan()) { - name = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME, name, - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN)); - } - - return name; -} - -// Returns true if docked mode is currently enabled. -bool IsDockedModeEnabled() { - display::DisplayManager* display_manager = GetDisplayManager(); - if (!display::Display::HasInternalDisplay()) - return false; - - for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { - if (display::Display::IsInternalDisplayId( - display_manager->GetDisplayAt(i).id())) { - return false; - } - } - - // We have an internal display but it's not one of the active displays. - return true; -} - -// Returns the notification message that should be shown when mirror display -// mode is entered. -base::string16 GetEnterMirrorModeMessage() { - if (display::Display::HasInternalDisplay()) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, - GetDisplayName(GetDisplayManager()->mirroring_display_id())); - } - - return l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL); -} - -// Returns the notification message that should be shown when unified desktop -// mode is entered. -base::string16 GetEnterUnifiedModeMessage() { - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED); -} - -// Returns the notification message that should be shown when unified desktop -// mode is exited. -base::string16 GetExitUnifiedModeMessage() { - return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING); -} - -base::string16 GetDisplayRemovedMessage( - const display::ManagedDisplayInfo& removed_display_info, - base::string16* out_additional_message) { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED, - base::UTF8ToUTF16(removed_display_info.name())); -} - -base::string16 GetDisplayAddedMessage(int64_t added_display_id, - base::string16* additional_message_out) { - if (!display::Display::HasInternalDisplay()) { - return l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL); - } - - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, - GetExternalDisplayName(added_display_id)); -} - -} // namespace - -const char ScreenLayoutObserver::kNotificationId[] = - "chrome://settings/display"; - -ScreenLayoutObserver::ScreenLayoutObserver() { - WmShell::Get()->AddDisplayObserver(this); - UpdateDisplayInfo(NULL); -} - -ScreenLayoutObserver::~ScreenLayoutObserver() { - WmShell::Get()->RemoveDisplayObserver(this); -} - -void ScreenLayoutObserver::UpdateDisplayInfo( - ScreenLayoutObserver::DisplayInfoMap* old_info) { - if (old_info) - old_info->swap(display_info_); - display_info_.clear(); - - display::DisplayManager* display_manager = GetDisplayManager(); - for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { - int64_t id = display_manager->GetDisplayAt(i).id(); - display_info_[id] = display_manager->GetDisplayInfo(id); - } -} - -bool ScreenLayoutObserver::GetDisplayMessageForNotification( - const ScreenLayoutObserver::DisplayInfoMap& old_info, - base::string16* out_message, - base::string16* out_additional_message) { - if (old_display_mode_ != current_display_mode_) { - // Detect changes in the mirror mode status. - if (current_display_mode_ == DisplayMode::MIRRORING) { - *out_message = GetEnterMirrorModeMessage(); - return true; - } - if (old_display_mode_ == DisplayMode::MIRRORING && - GetExitMirrorModeMessage(out_message, out_additional_message)) { - return true; - } - - // Detect changes in the unified mode status. - if (current_display_mode_ == DisplayMode::UNIFIED) { - *out_message = GetEnterUnifiedModeMessage(); - return true; - } - if (old_display_mode_ == DisplayMode::UNIFIED) { - *out_message = GetExitUnifiedModeMessage(); - return true; - } - - if (current_display_mode_ == DisplayMode::DOCKED || - old_display_mode_ == DisplayMode::DOCKED) { - // We no longer show any notification for docked mode events. - // crbug.com/674719. - return false; - } - } - - // Displays are added or removed. - if (display_info_.size() < old_info.size()) { - // A display has been removed. - for (const auto& iter : old_info) { - if (display_info_.count(iter.first)) - continue; - - *out_message = - GetDisplayRemovedMessage(iter.second, out_additional_message); - return true; - } - } else if (display_info_.size() > old_info.size()) { - // A display has been added. - for (const auto& iter : display_info_) { - if (old_info.count(iter.first)) - continue; - - *out_message = GetDisplayAddedMessage(iter.first, out_additional_message); - return true; - } - } - - for (const auto& iter : display_info_) { - DisplayInfoMap::const_iterator old_iter = old_info.find(iter.first); - if (old_iter == old_info.end()) { - // The display's number is same but different displays. This happens - // for the transition between docked mode and mirrored display. - // This condition can never be reached here, since it is handled above. - NOTREACHED() << "A display mode transition that should have been handled" - "earlier."; - return false; - } - - if (iter.second.configured_ui_scale() != - old_iter->second.configured_ui_scale()) { - *out_additional_message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, - GetDisplayName(iter.first), GetDisplaySize(iter.first)); - return true; - } - if (iter.second.GetActiveRotation() != - old_iter->second.GetActiveRotation()) { - int rotation_text_id = 0; - switch (iter.second.GetActiveRotation()) { - case display::Display::ROTATE_0: - rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION; - break; - case display::Display::ROTATE_90: - rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90; - break; - case display::Display::ROTATE_180: - rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180; - break; - case display::Display::ROTATE_270: - rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270; - break; - } - *out_additional_message = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetDisplayName(iter.first), - l10n_util::GetStringUTF16(rotation_text_id)); - return true; - } - } - - // Found nothing special - return false; -} - -void ScreenLayoutObserver::CreateOrUpdateNotification( - const base::string16& message, - const base::string16& additional_message) { - // Always remove the notification to make sure the notification appears - // as a popup in any situation. - message_center::MessageCenter::Get()->RemoveNotification(kNotificationId, - false /* by_user */); - - if (message.empty() && additional_message.empty()) - return; - - // Don't display notifications for accelerometer triggered screen rotations. - // See http://crbug.com/364949 - if (Shell::GetInstance() - ->screen_orientation_controller() - ->ignore_display_configuration_updates()) { - return; - } - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, message, - additional_message, bundle.GetImageNamed(IDR_AURA_NOTIFICATION_DISPLAY), - base::string16(), // display_source - GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierDisplay), - message_center::RichNotificationData(), - new message_center::HandleNotificationClickedDelegate( - base::Bind(&OpenSettingsFromNotification)))); - - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_DISPLAY_NOTIFICATION_CREATED); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -void ScreenLayoutObserver::OnDisplayConfigurationChanged() { - DisplayInfoMap old_info; - UpdateDisplayInfo(&old_info); - - old_display_mode_ = current_display_mode_; - if (GetDisplayManager()->IsInMirrorMode()) - current_display_mode_ = DisplayMode::MIRRORING; - else if (GetDisplayManager()->IsInUnifiedMode()) - current_display_mode_ = DisplayMode::UNIFIED; - else if (IsDockedModeEnabled()) - current_display_mode_ = DisplayMode::DOCKED; - else if (GetDisplayManager()->GetNumDisplays() > 2) - current_display_mode_ = DisplayMode::EXTENDED_3_PLUS; - else if (GetDisplayManager()->GetNumDisplays() == 2) - current_display_mode_ = DisplayMode::EXTENDED_2; - else - current_display_mode_ = DisplayMode::SINGLE; - - if (!show_notifications_for_testing) - return; - - base::string16 message; - base::string16 additional_message; - if (GetDisplayMessageForNotification(old_info, &message, &additional_message)) - CreateOrUpdateNotification(message, additional_message); -} - -bool ScreenLayoutObserver::GetExitMirrorModeMessage( - base::string16* out_message, - base::string16* out_additional_message) { - switch (current_display_mode_) { - case DisplayMode::EXTENDED_3_PLUS: - // Mirror mode was turned off due to having more than two displays. - // Show a message that mirror mode for 3+ displays is not supported. - *out_message = - l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED); - return true; - - case DisplayMode::DOCKED: - // Handle disabling mirror mode as a result of going to docked mode - // when we only have a single display (this means we actually have two - // physical displays, one of which is the internal display, but they - // were in mirror mode, and hence considered as one. Closing the - // internal display disables mirror mode and we still have a single - // active display). - // Falls through. - case DisplayMode::SINGLE: - // We're exiting mirror mode because we removed one of the two - // displays. - *out_message = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT); - return true; - - default: - // Mirror mode was turned off; other messages should be shown e.g. - // extended mode is on, ... etc. - return false; - } -} - -} // namespace ash
diff --git a/ash/system/screen_layout_observer.h b/ash/system/screen_layout_observer.h deleted file mode 100644 index 24943ae..0000000 --- a/ash/system/screen_layout_observer.h +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SCREEN_LAYOUT_OBSERVER_H_ -#define ASH_SYSTEM_SCREEN_LAYOUT_OBSERVER_H_ - -#include <stdint.h> - -#include <map> - -#include "ash/ash_export.h" -#include "ash/common/wm_display_observer.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/display/manager/managed_display_info.h" - -namespace ash { - -// ScreenLayoutObserver is responsible to send notification to users when screen -// resolution changes or screen rotation changes. -class ASH_EXPORT ScreenLayoutObserver : public WmDisplayObserver { - public: - ScreenLayoutObserver(); - ~ScreenLayoutObserver() override; - - // Overridden from WmDisplayObserver: - void OnDisplayConfigurationChanged() override; - - // Notifications are shown in production and are not shown in unit tests. - // Allow individual unit tests to show notifications. - void set_show_notifications_for_testing(bool show) { - show_notifications_for_testing = show; - } - - private: - friend class ScreenLayoutObserverTest; - - using DisplayInfoMap = std::map<int64_t, display::ManagedDisplayInfo>; - - static const char kNotificationId[]; - - // Scans the current display info and updates |display_info_|. Sets the - // previous data to |old_info| if it's not NULL. - void UpdateDisplayInfo(DisplayInfoMap* old_info); - - // Compares the current display settings with |old_info| and determine what - // message should be shown for notification. Returns true if there's a - // meaningful change. Note that it's possible to return true and set - // |message_out| to empty, which means the notification should be removed. It - // also sets |additional_message_out| which appears in the notification with - // the |message_out|. - bool GetDisplayMessageForNotification(const DisplayInfoMap& old_info, - base::string16* out_message, - base::string16* out_additional_message); - - // Creates or updates the display notification. - void CreateOrUpdateNotification(const base::string16& message, - const base::string16& additional_message); - - // Returns the notification message that should be shown when mirror display - // mode is exited. - bool GetExitMirrorModeMessage(base::string16* out_message, - base::string16* out_additional_message); - - DisplayInfoMap display_info_; - - enum class DisplayMode { - SINGLE, - EXTENDED_2, // 2 displays in extended mode. - EXTENDED_3_PLUS, // 3+ displays in extended mode. - MIRRORING, - UNIFIED, - DOCKED - }; - - DisplayMode old_display_mode_ = DisplayMode::SINGLE; - DisplayMode current_display_mode_ = DisplayMode::SINGLE; - - bool show_notifications_for_testing = true; - - DISALLOW_COPY_AND_ASSIGN(ScreenLayoutObserver); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SCREEN_LAYOUT_OBSERVER_H_
diff --git a/ash/system/screen_layout_observer_unittest.cc b/ash/system/screen_layout_observer_unittest.cc deleted file mode 100644 index a3c98f7..0000000 --- a/ash/system/screen_layout_observer_unittest.cc +++ /dev/null
@@ -1,443 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/screen_layout_observer.h" - -#include "ash/shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/devicetype_utils.h" -#include "ash/system/tray/system_tray.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/test_system_tray_delegate.h" -#include "base/strings/string16.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/display/display.h" -#include "ui/display/display_layout_builder.h" -#include "ui/display/manager/display_manager.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_list.h" -#include "ui/views/controls/label.h" - -namespace ash { - -class ScreenLayoutObserverTest : public test::AshTestBase { - public: - ScreenLayoutObserverTest(); - ~ScreenLayoutObserverTest() override; - - protected: - ScreenLayoutObserver* GetScreenLayoutObserver(); - void CheckUpdate(); - - void CloseNotification(); - base::string16 GetDisplayNotificationText() const; - base::string16 GetDisplayNotificationAdditionalText() const; - - base::string16 GetFirstDisplayName(); - - base::string16 GetSecondDisplayName(); - - base::string16 GetMirroringDisplayName(); - - private: - const message_center::Notification* GetDisplayNotification() const; - - DISALLOW_COPY_AND_ASSIGN(ScreenLayoutObserverTest); -}; - -ScreenLayoutObserverTest::ScreenLayoutObserverTest() {} - -ScreenLayoutObserverTest::~ScreenLayoutObserverTest() {} - -ScreenLayoutObserver* ScreenLayoutObserverTest::GetScreenLayoutObserver() { - return Shell::GetInstance()->screen_layout_observer(); -} - -void ScreenLayoutObserverTest::CloseNotification() { - message_center::MessageCenter::Get()->RemoveNotification( - ScreenLayoutObserver::kNotificationId, false); - RunAllPendingInMessageLoop(); -} - -base::string16 ScreenLayoutObserverTest::GetDisplayNotificationText() const { - const message_center::Notification* notification = GetDisplayNotification(); - return notification ? notification->title() : base::string16(); -} - -base::string16 ScreenLayoutObserverTest::GetDisplayNotificationAdditionalText() - const { - const message_center::Notification* notification = GetDisplayNotification(); - return notification ? notification->message() : base::string16(); -} - -base::string16 ScreenLayoutObserverTest::GetFirstDisplayName() { - return base::UTF8ToUTF16(display_manager()->GetDisplayNameForId( - display_manager()->first_display_id())); -} - -base::string16 ScreenLayoutObserverTest::GetSecondDisplayName() { - return base::UTF8ToUTF16(display_manager()->GetDisplayNameForId( - display_manager()->GetSecondaryDisplay().id())); -} - -base::string16 ScreenLayoutObserverTest::GetMirroringDisplayName() { - return base::UTF8ToUTF16(display_manager()->GetDisplayNameForId( - display_manager()->mirroring_display_id())); -} - -const message_center::Notification* -ScreenLayoutObserverTest::GetDisplayNotification() const { - const message_center::NotificationList::Notifications notifications = - message_center::MessageCenter::Get()->GetVisibleNotifications(); - for (const auto* notification : notifications) { - if (notification->id() == ScreenLayoutObserver::kNotificationId) - return notification; - } - - return nullptr; -} - -TEST_F(ScreenLayoutObserverTest, DisplayNotifications) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - - UpdateDisplay("400x400"); - display::Display::SetInternalDisplayId(display_manager()->first_display_id()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // rotation. - UpdateDisplay("400x400/r"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(), - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), - GetDisplayNotificationAdditionalText()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - CloseNotification(); - UpdateDisplay("400x400"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(), - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION)), - GetDisplayNotificationAdditionalText()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // UI-scale - CloseNotification(); - UpdateDisplay("400x400@1.5"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, - GetFirstDisplayName(), base::UTF8ToUTF16("600x600")), - GetDisplayNotificationAdditionalText()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // UI-scale to 1.0 - CloseNotification(); - UpdateDisplay("400x400"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, - GetFirstDisplayName(), base::UTF8ToUTF16("400x400")), - GetDisplayNotificationAdditionalText()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // No-update - CloseNotification(); - UpdateDisplay("400x400"); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); - - // Extended. - CloseNotification(); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, - GetSecondDisplayName()), - GetDisplayNotificationText()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); - - // Mirroring. - CloseNotification(); - display_manager()->SetSoftwareMirroring(true); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, - GetMirroringDisplayName()), - GetDisplayNotificationText()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); - - // Back to extended. - CloseNotification(); - display_manager()->SetSoftwareMirroring(false); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, - GetSecondDisplayName()), - GetDisplayNotificationText()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); - - // Resize the first display. - UpdateDisplay("400x400@1.5,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED, - GetFirstDisplayName(), base::UTF8ToUTF16("600x600")), - GetDisplayNotificationAdditionalText()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // Rotate the second. - UpdateDisplay("400x400@1.5,200x200/r"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetSecondDisplayName(), - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), - GetDisplayNotificationAdditionalText()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // Enters closed lid mode. - UpdateDisplay("400x400@1.5,200x200"); - display::Display::SetInternalDisplayId( - display_manager()->GetSecondaryDisplay().id()); - UpdateDisplay("400x400@1.5"); - EXPECT_TRUE(GetDisplayNotificationText().empty()); -} - -// Verify that notification shows up when display is switched from dock mode to -// extend mode. -TEST_F(ScreenLayoutObserverTest, DisplayConfigurationChangedTwice) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), - GetDisplayNotificationText()); - - // OnDisplayConfigurationChanged() may be called more than once for a single - // update display in case of primary is swapped or recovered from dock mode. - // Should not remove the notification in such case. - GetScreenLayoutObserver()->OnDisplayConfigurationChanged(); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), - GetDisplayNotificationText()); - - // Back to the single display. It should show that a display was removed. - UpdateDisplay("400x400"); - EXPECT_TRUE(base::StartsWith( - GetDisplayNotificationText(), - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED, - base::UTF8ToUTF16("")), - base::CompareCase::SENSITIVE)); -} - -// Verify the notification message content when one of the 2 displays that -// connected to the device is rotated. -TEST_F(ScreenLayoutObserverTest, UpdateAfterSuppressDisplayNotification) { - UpdateDisplay("400x400,200x200"); - - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - - // Rotate the second. - UpdateDisplay("400x400,200x200/r"); - EXPECT_EQ(l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetSecondDisplayName(), - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)), - GetDisplayNotificationAdditionalText()); -} - -// Verify that no notification is shown when overscan of a screen is changed. -TEST_F(ScreenLayoutObserverTest, OverscanDisplay) { - UpdateDisplay("400x400, 300x300"); - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - display::Display::SetInternalDisplayId(display_manager()->first_display_id()); - - // /o creates the default overscan. - UpdateDisplay("400x400, 300x300/o"); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); - - // Reset the overscan. - Shell::GetInstance()->display_manager()->SetOverscanInsets( - display_manager()->GetSecondaryDisplay().id(), gfx::Insets()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); -} - -// Tests that exiting mirror mode by closing the lid shows the correct "exiting -// mirror mode" message. -TEST_F(ScreenLayoutObserverTest, ExitMirrorModeBecauseOfDockedModeMessage) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400,200x200"); - display::Display::SetInternalDisplayId( - display_manager()->GetSecondaryDisplay().id()); - - // Mirroring. - display_manager()->SetSoftwareMirroring(true); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, - GetMirroringDisplayName()), - GetDisplayNotificationText()); - - // Docked. - CloseNotification(); - display_manager()->SetSoftwareMirroring(false); - display::Display::SetInternalDisplayId(display_manager()->first_display_id()); - UpdateDisplay("200x200"); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT), - GetDisplayNotificationText()); -} - -// Tests that exiting mirror mode because of adding a third display shows the -// correct "3+ displays mirror mode is not supported" message. -TEST_F(ScreenLayoutObserverTest, ExitMirrorModeBecauseOfThirdDisplayMessage) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400,200x200"); - display::Display::SetInternalDisplayId( - display_manager()->GetSecondaryDisplay().id()); - - // Mirroring. - display_manager()->SetSoftwareMirroring(true); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, - GetMirroringDisplayName()), - GetDisplayNotificationText()); - - // Adding a third display. Mirror mode for 3+ displays is not supported. - CloseNotification(); - display_manager()->SetSoftwareMirroring(false); - UpdateDisplay("400x400,200x200,100x100"); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_MIRRORING_NOT_SUPPORTED), - GetDisplayNotificationText()); -} - -// Special case: tests that exiting mirror mode by removing a display shows the -// correct message. -TEST_F(ScreenLayoutObserverTest, - ExitMirrorModeNoInternalDisplayBecauseOfDisplayRemovedMessage) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400,200x200"); - display::Display::SetInternalDisplayId( - display_manager()->GetSecondaryDisplay().id()); - - // Mirroring. - display_manager()->SetSoftwareMirroring(true); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, - GetMirroringDisplayName()), - GetDisplayNotificationText()); - - // Removing one of the displays. We show that we exited mirror mode. - CloseNotification(); - display_manager()->SetSoftwareMirroring(false); - UpdateDisplay("400x400"); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_MIRROR_EXIT), - GetDisplayNotificationText()); -} - -// Tests notification messages shown when adding and removing displays in -// extended mode. -TEST_F(ScreenLayoutObserverTest, AddingRemovingDisplayExtendedModeMessage) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400"); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // Adding a display in extended mode. - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), - GetDisplayNotificationText()); - - // Removing a display. - CloseNotification(); - UpdateDisplay("400x400"); - EXPECT_TRUE(base::StartsWith( - GetDisplayNotificationText(), - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_REMOVED, - base::UTF8ToUTF16("")), - base::CompareCase::SENSITIVE)); -} - -// Tests notification messages shown when entering and exiting unified desktop -// mode. -TEST_F(ScreenLayoutObserverTest, EnteringExitingUnifiedModeMessage) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400"); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // Adding a display in extended mode. - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), - GetDisplayNotificationText()); - - // Enter unified mode. - display_manager()->SetUnifiedDesktopEnabled(true); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED), - GetDisplayNotificationText()); - - // Exit unified mode. - display_manager()->SetUnifiedDesktopEnabled(false); - EXPECT_EQ( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING), - GetDisplayNotificationText()); - - // Enter unified mode again and exit via closing the lid. The message "Exiting - // unified mode" should be shown. - display_manager()->SetUnifiedDesktopEnabled(true); - EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED), - GetDisplayNotificationText()); - - // Close the lid. - display::Display::SetInternalDisplayId(display_manager()->first_display_id()); - UpdateDisplay("200x200"); - display_manager()->SetUnifiedDesktopEnabled(false); - EXPECT_EQ( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_UNIFIED_EXITING), - GetDisplayNotificationText()); -} - -// Special case: Tests notification messages shown when entering docked mode -// by closing the lid and the internal display is the secondary display. -TEST_F(ScreenLayoutObserverTest, DockedModeWithExternalPrimaryDisplayMessage) { - Shell::GetInstance() - ->screen_layout_observer() - ->set_show_notifications_for_testing(true); - UpdateDisplay("400x400,200x200"); - EXPECT_EQ(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL), - GetDisplayNotificationText()); - CloseNotification(); - - const int64_t primary_id = display_manager()->GetDisplayAt(0).id(); - const int64_t internal_secondary_id = display_manager()->GetDisplayAt(1).id(); - display::Display::SetInternalDisplayId(internal_secondary_id); - display::DisplayLayoutBuilder builder(primary_id); - builder.AddDisplayPlacement(internal_secondary_id, primary_id, - display::DisplayPlacement::LEFT, 0); - display_manager()->SetLayoutForCurrentDisplays(builder.Build()); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - - // Close the lid. We go to docked mode, but we show no notifications. - UpdateDisplay("400x400"); - EXPECT_TRUE(GetDisplayNotificationText().empty()); - EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty()); -} - -} // namespace ash
diff --git a/ash/system/screen_security/screen_capture_observer.h b/ash/system/screen_security/screen_capture_observer.h deleted file mode 100644 index 88760a16..0000000 --- a/ash/system/screen_security/screen_capture_observer.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SCREEN_SECURITY_SCREEN_CAPTURE_OBSERVER_H_ -#define ASH_SYSTEM_SCREEN_SECURITY_SCREEN_CAPTURE_OBSERVER_H_ - -#include "base/callback.h" -#include "base/strings/string16.h" - -namespace ash { - -class ScreenCaptureObserver { - public: - // Called when screen capture is started. - virtual void OnScreenCaptureStart( - const base::Closure& stop_callback, - const base::string16& screen_capture_status) = 0; - - // Called when screen capture is stopped. - virtual void OnScreenCaptureStop() = 0; - - protected: - virtual ~ScreenCaptureObserver() {} -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SCREEN_SECURITY_SCREEN_CAPTURE_OBSERVER_H_
diff --git a/ash/system/screen_security/screen_capture_tray_item.cc b/ash/system/screen_security/screen_capture_tray_item.cc deleted file mode 100644 index 8628676..0000000 --- a/ash/system/screen_security/screen_capture_tray_item.cc +++ /dev/null
@@ -1,108 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/screen_security/screen_capture_tray_item.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" - -using message_center::Notification; - -namespace ash { -namespace { - -const char kScreenCaptureNotificationId[] = "chrome://screen/capture"; - -} // namespace - -ScreenCaptureTrayItem::ScreenCaptureTrayItem(SystemTray* system_tray) - : ScreenTrayItem(system_tray, UMA_SCREEN_CAPTURE) { - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->system_tray_notifier()->AddScreenCaptureObserver(this); -} - -ScreenCaptureTrayItem::~ScreenCaptureTrayItem() { - WmShell::Get()->RemoveShellObserver(this); - WmShell::Get()->system_tray_notifier()->RemoveScreenCaptureObserver(this); -} - -views::View* ScreenCaptureTrayItem::CreateDefaultView(LoginStatus status) { - set_default_view(new tray::ScreenStatusView( - this, screen_capture_status_, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP))); - return default_view(); -} - -void ScreenCaptureTrayItem::CreateOrUpdateNotification() { - message_center::RichNotificationData data; - data.buttons.push_back(message_center::ButtonInfo( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP))); - ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kScreenCaptureNotificationId, - screen_capture_status_, base::string16() /* body is blank */, - resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE_DARK), - base::string16() /* display_source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierScreenCapture), - data, new tray::ScreenNotificationDelegate(this))); - notification->SetSystemPriority(); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -std::string ScreenCaptureTrayItem::GetNotificationId() { - return kScreenCaptureNotificationId; -} - -void ScreenCaptureTrayItem::RecordStoppedFromDefaultViewMetric() { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_SCREEN_CAPTURE_DEFAULT_STOP); -} - -void ScreenCaptureTrayItem::RecordStoppedFromNotificationViewMetric() { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_SCREEN_CAPTURE_NOTIFICATION_STOP); -} - -void ScreenCaptureTrayItem::OnScreenCaptureStart( - const base::Closure& stop_callback, - const base::string16& screen_capture_status) { - screen_capture_status_ = screen_capture_status; - - // We do not want to show the screen capture tray item and the chromecast - // casting tray item at the same time. We will hide this tray item. - // - // This suppression technique is currently dependent on the order - // that OnScreenCaptureStart and OnCastingSessionStartedOrStopped - // get invoked. OnCastingSessionStartedOrStopped currently gets - // called first. - if (is_casting_) - return; - - Start(stop_callback); -} - -void ScreenCaptureTrayItem::OnScreenCaptureStop() { - // We do not need to run the stop callback when - // screen capture is stopped externally. - set_is_started(false); - Update(); -} - -void ScreenCaptureTrayItem::OnCastingSessionStartedOrStopped(bool started) { - is_casting_ = started; -} - -} // namespace ash
diff --git a/ash/system/screen_security/screen_capture_tray_item.h b/ash/system/screen_security/screen_capture_tray_item.h deleted file mode 100644 index 9c6b58b7..0000000 --- a/ash/system/screen_security/screen_capture_tray_item.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SCREEN_SECURITY_SCREEN_CAPTURE_TRAY_ITEM_H_ -#define ASH_SYSTEM_SCREEN_SECURITY_SCREEN_CAPTURE_TRAY_ITEM_H_ - -#include "ash/common/shell_observer.h" -#include "ash/system/screen_security/screen_capture_observer.h" -#include "ash/system/screen_security/screen_tray_item.h" -#include "base/macros.h" - -namespace views { -class View; -} - -namespace ash { - -class ASH_EXPORT ScreenCaptureTrayItem : public ScreenTrayItem, - public ScreenCaptureObserver, - public ShellObserver { - public: - explicit ScreenCaptureTrayItem(SystemTray* system_tray); - ~ScreenCaptureTrayItem() override; - - private: - // Overridden from SystemTrayItem. - views::View* CreateDefaultView(LoginStatus status) override; - - // Overridden from ScreenTrayItem. - void CreateOrUpdateNotification() override; - std::string GetNotificationId() override; - void RecordStoppedFromDefaultViewMetric() override; - void RecordStoppedFromNotificationViewMetric() override; - - // Overridden from ScreenCaptureObserver. - void OnScreenCaptureStart( - const base::Closure& stop_callback, - const base::string16& screen_capture_status) override; - void OnScreenCaptureStop() override; - - // Overridden from ShellObserver. - void OnCastingSessionStartedOrStopped(bool started) override; - - base::string16 screen_capture_status_; - bool is_casting_ = false; - - DISALLOW_COPY_AND_ASSIGN(ScreenCaptureTrayItem); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SCREEN_SECURITY_SCREEN_CAPTURE_TRAY_ITEM_H_
diff --git a/ash/system/screen_security/screen_share_observer.h b/ash/system/screen_security/screen_share_observer.h deleted file mode 100644 index 99227b6..0000000 --- a/ash/system/screen_security/screen_share_observer.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SHARE_OBSERVER_H_ -#define ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SHARE_OBSERVER_H_ - -#include "base/callback.h" -#include "base/strings/string16.h" - -namespace ash { - -class ScreenShareObserver { - public: - // Called when screen share is started. - virtual void OnScreenShareStart(const base::Closure& stop_callback, - const base::string16& helper_name) = 0; - - // Called when screen share is stopped. - virtual void OnScreenShareStop() = 0; - - protected: - virtual ~ScreenShareObserver() {} -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SHARE_OBSERVER_H_
diff --git a/ash/system/screen_security/screen_share_tray_item.cc b/ash/system/screen_security/screen_share_tray_item.cc deleted file mode 100644 index dc06e7f..0000000 --- a/ash/system/screen_security/screen_share_tray_item.cc +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/screen_security/screen_share_tray_item.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" - -using message_center::Notification; - -namespace ash { -namespace { - -const char kScreenShareNotificationId[] = "chrome://screen/share"; -} - -ScreenShareTrayItem::ScreenShareTrayItem(SystemTray* system_tray) - : ScreenTrayItem(system_tray, UMA_SCREEN_SHARE) { - WmShell::Get()->system_tray_notifier()->AddScreenShareObserver(this); -} - -ScreenShareTrayItem::~ScreenShareTrayItem() { - WmShell::Get()->system_tray_notifier()->RemoveScreenShareObserver(this); -} - -views::View* ScreenShareTrayItem::CreateDefaultView(LoginStatus status) { - set_default_view(new tray::ScreenStatusView( - this, - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED), - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP))); - return default_view(); -} - -void ScreenShareTrayItem::CreateOrUpdateNotification() { - base::string16 help_label_text; - if (!helper_name_.empty()) { - help_label_text = l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED_NAME, helper_name_); - } else { - help_label_text = l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED); - } - - message_center::RichNotificationData data; - data.buttons.push_back(message_center::ButtonInfo( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP))); - ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); - std::unique_ptr<Notification> notification(new Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kScreenShareNotificationId, - help_label_text, base::string16() /* body is blank */, - resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE_DARK), - base::string16() /* display_source */, GURL(), - message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierScreenShare), - data, new tray::ScreenNotificationDelegate(this))); - notification->SetSystemPriority(); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -std::string ScreenShareTrayItem::GetNotificationId() { - return kScreenShareNotificationId; -} - -void ScreenShareTrayItem::RecordStoppedFromDefaultViewMetric() { - // Intentionally not recording a metric. -} - -void ScreenShareTrayItem::RecordStoppedFromNotificationViewMetric() { - // Intentionally not recording a metric. -} - -void ScreenShareTrayItem::OnScreenShareStart( - const base::Closure& stop_callback, - const base::string16& helper_name) { - helper_name_ = helper_name; - Start(stop_callback); -} - -void ScreenShareTrayItem::OnScreenShareStop() { - // We do not need to run the stop callback - // when screening is stopped externally. - set_is_started(false); - Update(); -} - -} // namespace ash
diff --git a/ash/system/screen_security/screen_share_tray_item.h b/ash/system/screen_security/screen_share_tray_item.h deleted file mode 100644 index 615fb649..0000000 --- a/ash/system/screen_security/screen_share_tray_item.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SHARE_TRAY_ITEM_H_ -#define ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SHARE_TRAY_ITEM_H_ - -#include "ash/system/screen_security/screen_share_observer.h" -#include "ash/system/screen_security/screen_tray_item.h" -#include "base/macros.h" - -namespace views { -class View; -} - -namespace ash { - -class ASH_EXPORT ScreenShareTrayItem : public ScreenTrayItem, - public ScreenShareObserver { - public: - explicit ScreenShareTrayItem(SystemTray* system_tray); - ~ScreenShareTrayItem() override; - - private: - // Overridden from SystemTrayItem. - views::View* CreateDefaultView(LoginStatus status) override; - - // Overridden from ScreenTrayItem. - void CreateOrUpdateNotification() override; - std::string GetNotificationId() override; - void RecordStoppedFromDefaultViewMetric() override; - void RecordStoppedFromNotificationViewMetric() override; - - // Overridden from ScreenShareObserver. - void OnScreenShareStart(const base::Closure& stop_callback, - const base::string16& helper_name) override; - void OnScreenShareStop() override; - - base::string16 helper_name_; - - DISALLOW_COPY_AND_ASSIGN(ScreenShareTrayItem); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SCREEN_SECURITY_SCREEN_SHARE_TRAY_ITEM_H_
diff --git a/ash/system/screen_security/screen_tray_item.cc b/ash/system/screen_security/screen_tray_item.cc deleted file mode 100644 index 9fe53499..0000000 --- a/ash/system/screen_security/screen_tray_item.cc +++ /dev/null
@@ -1,195 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/screen_security/screen_tray_item.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/message_center/message_center.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { -namespace tray { - -// ScreenTrayView implementations. -ScreenTrayView::ScreenTrayView(ScreenTrayItem* screen_tray_item) - : TrayItemView(screen_tray_item), screen_tray_item_(screen_tray_item) { - CreateImageView(); - if (MaterialDesignController::UseMaterialDesignSystemIcons()) { - image_view()->SetImage( - gfx::CreateVectorIcon(kSystemTrayScreenShareIcon, kTrayIconColor)); - } else { - image_view()->SetImage(ui::ResourceBundle::GetSharedInstance() - .GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE) - .ToImageSkia()); - } - Update(); -} - -ScreenTrayView::~ScreenTrayView() {} - -void ScreenTrayView::Update() { - SetVisible(screen_tray_item_->is_started()); -} - -// ScreenStatusView implementations. -ScreenStatusView::ScreenStatusView(ScreenTrayItem* screen_tray_item, - const base::string16& label_text, - const base::string16& stop_button_text) - : screen_tray_item_(screen_tray_item), - icon_(nullptr), - label_(nullptr), - stop_button_(nullptr), - label_text_(label_text), - stop_button_text_(stop_button_text) { - CreateItems(); - TriView* tri_view(TrayPopupUtils::CreateDefaultRowView()); - SetLayoutManager(new views::FillLayout); - AddChildView(tri_view); - tri_view->AddView(TriView::Container::START, icon_); - // TODO(bruthig): Multiline Labels don't lay out well with borders so we add - // the border to the Label's container instead. See https://crbug.com/678337 & - // https://crbug.com/682221. - tri_view->SetContainerBorder( - TriView::Container::CENTER, - views::CreateEmptyBorder(0, 0, 0, kTrayPopupLabelRightPadding)); - tri_view->AddView(TriView::Container::CENTER, label_); - tri_view->AddView(TriView::Container::END, stop_button_); - tri_view->SetContainerBorder( - TriView::Container::END, - views::CreateEmptyBorder(0, 0, 0, kTrayPopupButtonEndMargin)); - if (screen_tray_item_) - UpdateFromScreenTrayItem(); -} - -ScreenStatusView::~ScreenStatusView() {} - -void ScreenStatusView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK(sender == stop_button_); - screen_tray_item_->Stop(); - screen_tray_item_->RecordStoppedFromDefaultViewMetric(); -} - -void ScreenStatusView::CreateItems() { - const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial(); - icon_ = TrayPopupUtils::CreateMainImageView(); - icon_->SetImage(gfx::CreateVectorIcon( - kSystemMenuScreenShareIcon, TrayPopupItemStyle::GetIconColor( - TrayPopupItemStyle::ColorStyle::ACTIVE))); - if (!use_md) { - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - icon_->SetImage(bundle.GetImageNamed(IDR_AURA_UBER_TRAY_SCREENSHARE_DARK) - .ToImageSkia()); - } - - label_ = TrayPopupUtils::CreateDefaultLabel(); - label_->SetMultiLine(true); - label_->SetText(label_text_); - // TODO(bruthig): Multiline Labels don't lay out well with borders. - // See https://crbug.com/678337 & https://crbug.com/682221. - label_->SetBorder(nullptr); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - style.SetupLabel(label_); - - stop_button_ = TrayPopupUtils::CreateTrayPopupButton(this, stop_button_text_); -} - -void ScreenStatusView::UpdateFromScreenTrayItem() { - SetVisible(screen_tray_item_->is_started()); -} - -ScreenNotificationDelegate::ScreenNotificationDelegate( - ScreenTrayItem* screen_tray) - : screen_tray_(screen_tray) {} - -ScreenNotificationDelegate::~ScreenNotificationDelegate() {} - -void ScreenNotificationDelegate::ButtonClick(int button_index) { - DCHECK_EQ(0, button_index); - screen_tray_->Stop(); - screen_tray_->RecordStoppedFromNotificationViewMetric(); -} - -} // namespace tray - -ScreenTrayItem::ScreenTrayItem(SystemTray* system_tray, UmaType uma_type) - : SystemTrayItem(system_tray, uma_type), - tray_view_(nullptr), - default_view_(nullptr), - is_started_(false), - stop_callback_(base::Bind(&base::DoNothing)) {} - -ScreenTrayItem::~ScreenTrayItem() {} - -void ScreenTrayItem::Update() { - if (tray_view_) - tray_view_->Update(); - if (default_view_) - default_view_->UpdateFromScreenTrayItem(); - if (is_started_) { - CreateOrUpdateNotification(); - } else { - message_center::MessageCenter::Get()->RemoveNotification( - GetNotificationId(), false /* by_user */); - } -} - -void ScreenTrayItem::Start(const base::Closure& stop_callback) { - stop_callback_ = stop_callback; - is_started_ = true; - - if (tray_view_) - tray_view_->Update(); - - if (default_view_) - default_view_->UpdateFromScreenTrayItem(); - - if (!system_tray()->HasSystemBubbleType( - SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { - CreateOrUpdateNotification(); - } -} - -void ScreenTrayItem::Stop() { - is_started_ = false; - Update(); - - if (stop_callback_.is_null()) - return; - - base::Closure callback = stop_callback_; - stop_callback_.Reset(); - callback.Run(); -} - -views::View* ScreenTrayItem::CreateTrayView(LoginStatus status) { - tray_view_ = new tray::ScreenTrayView(this); - return tray_view_; -} - -void ScreenTrayItem::RecordStoppedFromDefaultViewMetric() {} - -void ScreenTrayItem::RecordStoppedFromNotificationViewMetric() {} - -void ScreenTrayItem::DestroyTrayView() { - tray_view_ = nullptr; -} - -void ScreenTrayItem::DestroyDefaultView() { - default_view_ = nullptr; -} - -} // namespace ash
diff --git a/ash/system/screen_security/screen_tray_item.h b/ash/system/screen_security/screen_tray_item.h deleted file mode 100644 index 14d658c8c..0000000 --- a/ash/system/screen_security/screen_tray_item.h +++ /dev/null
@@ -1,140 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SCREEN_SECURITY_SCREEN_TRAY_ITEM_H_ -#define ASH_SYSTEM_SCREEN_SECURITY_SCREEN_TRAY_ITEM_H_ - -#include <string> - -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_notification_view.h" -#include "base/macros.h" -#include "ui/message_center/notification_delegate.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/image_view.h" - -namespace views { -class View; -} - -namespace ash { -class ScreenTrayItem; - -namespace tray { - -class ScreenTrayView : public TrayItemView { - public: - explicit ScreenTrayView(ScreenTrayItem* screen_tray_item); - ~ScreenTrayView() override; - - void Update(); - - private: - ScreenTrayItem* screen_tray_item_; - - DISALLOW_COPY_AND_ASSIGN(ScreenTrayView); -}; - -class ScreenStatusView : public views::View, public views::ButtonListener { - public: - ScreenStatusView(ScreenTrayItem* screen_tray_item, - const base::string16& label_text, - const base::string16& stop_button_text); - ~ScreenStatusView() override; - - // Overridden from views::ButtonListener. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - void CreateItems(); - void UpdateFromScreenTrayItem(); - - protected: - views::ImageView* icon() { return icon_; } - views::Label* label() { return label_; } - views::Button* stop_button() { return stop_button_; } - - private: - // The controller for this view. May be null. - ScreenTrayItem* screen_tray_item_; - views::ImageView* icon_; - views::Label* label_; - views::Button* stop_button_; - base::string16 label_text_; - base::string16 stop_button_text_; - - DISALLOW_COPY_AND_ASSIGN(ScreenStatusView); -}; - -class ScreenNotificationDelegate : public message_center::NotificationDelegate { - public: - explicit ScreenNotificationDelegate(ScreenTrayItem* screen_tray); - - // message_center::NotificationDelegate overrides: - void ButtonClick(int button_index) override; - - protected: - ~ScreenNotificationDelegate() override; - - private: - ScreenTrayItem* screen_tray_; - - DISALLOW_COPY_AND_ASSIGN(ScreenNotificationDelegate); -}; - -} // namespace tray - -// The base tray item for screen capture and screen sharing. The -// Start method brings up a notification and a tray item, and the user -// can stop the screen capture/sharing by pressing the stop button. -class ASH_EXPORT ScreenTrayItem : public SystemTrayItem { - public: - ScreenTrayItem(SystemTray* system_tray, UmaType uma_type); - ~ScreenTrayItem() override; - - tray::ScreenTrayView* tray_view() { return tray_view_; } - - tray::ScreenStatusView* default_view() { return default_view_; } - void set_default_view(tray::ScreenStatusView* default_view) { - default_view_ = default_view; - } - - bool is_started() const { return is_started_; } - void set_is_started(bool is_started) { is_started_ = is_started; } - - void Update(); - void Start(const base::Closure& stop_callback); - void Stop(); - - // Creates or updates the notification for the tray item. - virtual void CreateOrUpdateNotification() = 0; - - // Returns the id of the notification for the tray item. - virtual std::string GetNotificationId() = 0; - - // Called after Stop() is invoked from the default view. - virtual void RecordStoppedFromDefaultViewMetric() = 0; - - // Called after Stop() is invoked from the notification view. - virtual void RecordStoppedFromNotificationViewMetric() = 0; - - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override = 0; - void DestroyTrayView() override; - void DestroyDefaultView() override; - - private: - tray::ScreenTrayView* tray_view_; - tray::ScreenStatusView* default_view_; - bool is_started_; - base::Closure stop_callback_; - - DISALLOW_COPY_AND_ASSIGN(ScreenTrayItem); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SCREEN_SECURITY_SCREEN_TRAY_ITEM_H_
diff --git a/ash/system/screen_security/screen_tray_item_unittest.cc b/ash/system/screen_security/screen_tray_item_unittest.cc deleted file mode 100644 index 4aa4ff17..0000000 --- a/ash/system/screen_security/screen_tray_item_unittest.cc +++ /dev/null
@@ -1,223 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/screen_security/screen_tray_item.h" - -#include "ash/common/wm_shell.h" -#include "ash/system/screen_security/screen_capture_tray_item.h" -#include "ash/system/screen_security/screen_share_tray_item.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/test/ash_test.h" -#include "base/callback.h" -#include "base/memory/ptr_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/events/event.h" -#include "ui/events/event_utils.h" -#include "ui/gfx/geometry/point.h" -#include "ui/message_center/message_center.h" -#include "ui/views/view.h" - -namespace ash { - -// Test with unicode strings. -const char kTestScreenCaptureAppName[] = - "\xE0\xB2\xA0\x5F\xE0\xB2\xA0 (Screen Capture Test)"; -const char kTestScreenShareHelperName[] = - "\xE5\xAE\x8B\xE8\x85\xBE (Screen Share Test)"; - -void ClickViewCenter(views::View* view) { - gfx::Point click_location_in_local = - gfx::Point(view->width() / 2, view->height() / 2); - view->OnMousePressed(ui::MouseEvent( - ui::ET_MOUSE_PRESSED, click_location_in_local, click_location_in_local, - ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE)); -} - -class ScreenTrayItemTest : public AshTest { - public: - ScreenTrayItemTest() : tray_item_(NULL), stop_callback_hit_count_(0) {} - ~ScreenTrayItemTest() override {} - - ScreenTrayItem* tray_item() { return tray_item_; } - void set_tray_item(ScreenTrayItem* tray_item) { tray_item_ = tray_item; } - - int stop_callback_hit_count() const { return stop_callback_hit_count_; } - - void SetUp() override { - AshTest::SetUp(); - TrayItemView::DisableAnimationsForTest(); - } - - void StartSession() { - tray_item_->Start( - base::Bind(&ScreenTrayItemTest::StopCallback, base::Unretained(this))); - } - - void StopSession() { tray_item_->Stop(); } - - void StopCallback() { stop_callback_hit_count_++; } - - private: - ScreenTrayItem* tray_item_; - int stop_callback_hit_count_; - - DISALLOW_COPY_AND_ASSIGN(ScreenTrayItemTest); -}; - -class ScreenCaptureTest : public ScreenTrayItemTest { - public: - ScreenCaptureTest() {} - ~ScreenCaptureTest() override {} - - void SetUp() override { - ScreenTrayItemTest::SetUp(); - // This tray item is owned by its parent system tray view and will - // be deleted automatically when its parent is destroyed in AshTestBase. - ScreenTrayItem* item = new ScreenCaptureTrayItem(GetPrimarySystemTray()); - GetPrimarySystemTray()->AddTrayItem(base::WrapUnique(item)); - set_tray_item(item); - } - - private: - DISALLOW_COPY_AND_ASSIGN(ScreenCaptureTest); -}; - -class ScreenShareTest : public ScreenTrayItemTest { - public: - ScreenShareTest() {} - ~ScreenShareTest() override {} - - void SetUp() override { - ScreenTrayItemTest::SetUp(); - // This tray item is owned by its parent system tray view and will - // be deleted automatically when its parent is destroyed in AshTestBase. - ScreenTrayItem* item = new ScreenShareTrayItem(GetPrimarySystemTray()); - GetPrimarySystemTray()->AddTrayItem(base::WrapUnique(item)); - set_tray_item(item); - } - - DISALLOW_COPY_AND_ASSIGN(ScreenShareTest); -}; - -void TestStartAndStop(ScreenTrayItemTest* test) { - ScreenTrayItem* tray_item = test->tray_item(); - - EXPECT_FALSE(tray_item->is_started()); - EXPECT_EQ(0, test->stop_callback_hit_count()); - - test->StartSession(); - EXPECT_TRUE(tray_item->is_started()); - - test->StopSession(); - EXPECT_FALSE(tray_item->is_started()); - EXPECT_EQ(1, test->stop_callback_hit_count()); -} - -TEST_F(ScreenCaptureTest, StartAndStop) { - TestStartAndStop(this); -} - -TEST_F(ScreenShareTest, StartAndStop) { - TestStartAndStop(this); -} - -void TestNotificationStartAndStop(ScreenTrayItemTest* test, - const base::Closure& start_function, - const base::Closure& stop_function) { - ScreenTrayItem* tray_item = test->tray_item(); - EXPECT_FALSE(tray_item->is_started()); - - start_function.Run(); - EXPECT_TRUE(tray_item->is_started()); - - // The stop callback shouldn't be called because we stopped - // through the notification system. - stop_function.Run(); - EXPECT_FALSE(tray_item->is_started()); - EXPECT_EQ(0, test->stop_callback_hit_count()); -} - -TEST_F(ScreenCaptureTest, NotificationStartAndStop) { - base::Closure start_function = base::Bind( - &SystemTrayNotifier::NotifyScreenCaptureStart, - base::Unretained(WmShell::Get()->system_tray_notifier()), - base::Bind(&ScreenTrayItemTest::StopCallback, base::Unretained(this)), - base::UTF8ToUTF16(kTestScreenCaptureAppName)); - - base::Closure stop_function = - base::Bind(&SystemTrayNotifier::NotifyScreenCaptureStop, - base::Unretained(WmShell::Get()->system_tray_notifier())); - - TestNotificationStartAndStop(this, start_function, stop_function); -} - -TEST_F(ScreenShareTest, NotificationStartAndStop) { - base::Closure start_func = base::Bind( - &SystemTrayNotifier::NotifyScreenShareStart, - base::Unretained(WmShell::Get()->system_tray_notifier()), - base::Bind(&ScreenTrayItemTest::StopCallback, base::Unretained(this)), - base::UTF8ToUTF16(kTestScreenShareHelperName)); - - base::Closure stop_func = - base::Bind(&SystemTrayNotifier::NotifyScreenShareStop, - base::Unretained(WmShell::Get()->system_tray_notifier())); - - TestNotificationStartAndStop(this, start_func, stop_func); -} - -void TestNotificationView(ScreenTrayItemTest* test) { - ScreenTrayItem* tray_item = test->tray_item(); - - test->StartSession(); - message_center::MessageCenter* message_center = - message_center::MessageCenter::Get(); - EXPECT_TRUE(message_center->FindVisibleNotificationById( - tray_item->GetNotificationId())); - test->StopSession(); -} - -TEST_F(ScreenCaptureTest, NotificationView) { - TestNotificationView(this); -} - -TEST_F(ScreenShareTest, NotificationView) { - TestNotificationView(this); -} - -void TestSystemTrayInteraction(ScreenTrayItemTest* test) { - ScreenTrayItem* tray_item = test->tray_item(); - EXPECT_FALSE(tray_item->tray_view()->visible()); - - std::vector<SystemTrayItem*> tray_items = - AshTest::GetPrimarySystemTray()->GetTrayItems(); - EXPECT_NE(std::find(tray_items.begin(), tray_items.end(), tray_item), - tray_items.end()); - - test->StartSession(); - EXPECT_TRUE(tray_item->tray_view()->visible()); - - // The default view should be created in a new bubble. - AshTest::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); - EXPECT_TRUE(tray_item->default_view()); - AshTest::GetPrimarySystemTray()->CloseSystemBubble(); - EXPECT_FALSE(tray_item->default_view()); - - test->StopSession(); - EXPECT_FALSE(tray_item->tray_view()->visible()); - - // The default view should not be visible because session is stopped. - AshTest::GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); - EXPECT_FALSE(tray_item->default_view()->visible()); -} - -TEST_F(ScreenCaptureTest, SystemTrayInteraction) { - TestSystemTrayInteraction(this); -} - -TEST_F(ScreenShareTest, SystemTrayInteraction) { - TestSystemTrayInteraction(this); -} - -} // namespace ash
diff --git a/ash/system/session/last_window_closed_observer.h b/ash/system/session/last_window_closed_observer.h deleted file mode 100644 index e23e5da..0000000 --- a/ash/system/session/last_window_closed_observer.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_LAST_WINDOW_CLOSED_OBSERVER_H_ -#define ASH_SYSTEM_SESSION_LAST_WINDOW_CLOSED_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -class ASH_EXPORT LastWindowClosedObserver { - public: - virtual void OnLastWindowClosed() = 0; - - protected: - virtual ~LastWindowClosedObserver() {} -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_LAST_WINDOW_CLOSED_OBSERVER_H_
diff --git a/ash/system/session/logout_button_observer.h b/ash/system/session/logout_button_observer.h deleted file mode 100644 index 3e20cec..0000000 --- a/ash/system/session/logout_button_observer.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_LOGOUT_BUTTON_OBSERVER_H_ -#define ASH_SYSTEM_SESSION_LOGOUT_BUTTON_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "base/time/time.h" - -namespace ash { - -class ASH_EXPORT LogoutButtonObserver { - public: - virtual ~LogoutButtonObserver() {} - - // Called when the value of the kShowLogoutButtonInTray pref changes, which - // determines whether a logout button should be shown in the system tray - // during a session. - virtual void OnShowLogoutButtonInTrayChanged(bool show) = 0; - - // Called when the value of the kLogoutDialogDurationMs pref changes. - // |duration| is the duration for which the logout confirmation dialog is - // shown after the user has pressed the logout button. - virtual void OnLogoutDialogDurationChanged(base::TimeDelta duration) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_LOGOUT_BUTTON_OBSERVER_H_
diff --git a/ash/system/session/logout_button_tray.cc b/ash/system/session/logout_button_tray.cc deleted file mode 100644 index ee69fc4..0000000 --- a/ash/system/session/logout_button_tray.cc +++ /dev/null
@@ -1,132 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/session/logout_button_tray.h" - -#include <memory> -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/session/logout_confirmation_controller.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_utils.h" -#include "ash/system/user/login_status.h" -#include "base/logging.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/events/event.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/bubble/tray_bubble_view.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/button/label_button_border.h" -#include "ui/views/controls/button/md_text_button.h" -#include "ui/views/painter.h" - -namespace ash { - -LogoutButtonTray::LogoutButtonTray(WmShelf* wm_shelf) - : TrayBackgroundView(wm_shelf), - button_(nullptr), - login_status_(LoginStatus::NOT_LOGGED_IN), - show_logout_button_in_tray_(false) { - views::MdTextButton* button = - views::MdTextButton::Create(this, base::string16()); - button->SetProminent(true); - button->SetBgColorOverride(gfx::kGoogleRed700); - // Base font size + 2 = 14. - // TODO(estade): should this 2 be shared with other tray views? See - // crbug.com/623987 - button->AdjustFontSize(2); - button_ = button; - - // Since LogoutButtonTray has a red background and it is distinguished - // by itself, no separator is needed on its right side. - set_separator_visibility(false); - tray_container()->AddChildView(button_); - WmShell::Get()->system_tray_notifier()->AddLogoutButtonObserver(this); -} - -LogoutButtonTray::~LogoutButtonTray() { - WmShell::Get()->system_tray_notifier()->RemoveLogoutButtonObserver(this); -} - -void LogoutButtonTray::SetShelfAlignment(ShelfAlignment alignment) { - // We must first update the button so that - // TrayBackgroundView::SetShelfAlignment() can lay it out correctly. - UpdateButtonTextAndImage(login_status_, alignment); - TrayBackgroundView::SetShelfAlignment(alignment); -} - -base::string16 LogoutButtonTray::GetAccessibleNameForTray() { - return button_->GetText(); -} - -void LogoutButtonTray::HideBubbleWithView( - const views::TrayBubbleView* bubble_view) {} - -void LogoutButtonTray::ClickedOutsideBubble() {} - -void LogoutButtonTray::ButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender != button_) { - TrayBackgroundView::ButtonPressed(sender, event); - return; - } - - if (dialog_duration_ <= base::TimeDelta()) { - // Sign out immediately if |dialog_duration_| is non-positive. - WmShell::Get()->system_tray_controller()->SignOut(); - } else if (WmShell::Get()->logout_confirmation_controller()) { - WmShell::Get()->logout_confirmation_controller()->ConfirmLogout( - base::TimeTicks::Now() + dialog_duration_); - } -} - -void LogoutButtonTray::OnShowLogoutButtonInTrayChanged(bool show) { - show_logout_button_in_tray_ = show; - UpdateVisibility(); -} - -void LogoutButtonTray::OnLogoutDialogDurationChanged(base::TimeDelta duration) { - dialog_duration_ = duration; -} - -void LogoutButtonTray::UpdateAfterLoginStatusChange(LoginStatus login_status) { - UpdateButtonTextAndImage(login_status, shelf_alignment()); -} - -void LogoutButtonTray::UpdateVisibility() { - SetVisible(show_logout_button_in_tray_ && - login_status_ != LoginStatus::NOT_LOGGED_IN && - login_status_ != LoginStatus::LOCKED); -} - -void LogoutButtonTray::UpdateButtonTextAndImage(LoginStatus login_status, - ShelfAlignment alignment) { - login_status_ = login_status; - const base::string16 title = - user::GetLocalizedSignOutStringForStatus(login_status, false); - if (IsHorizontalAlignment(alignment)) { - button_->SetText(title); - button_->SetImage(views::LabelButton::STATE_NORMAL, gfx::ImageSkia()); - button_->SetMinSize(gfx::Size(0, kTrayItemSize)); - } else { - button_->SetText(base::string16()); - button_->SetAccessibleName(title); - button_->SetImage(views::LabelButton::STATE_NORMAL, - gfx::CreateVectorIcon(kShelfLogoutIcon, kTrayIconColor)); - button_->SetMinSize(gfx::Size(kTrayItemSize, kTrayItemSize)); - } - UpdateVisibility(); -} - -} // namespace ash
diff --git a/ash/system/session/logout_button_tray.h b/ash/system/session/logout_button_tray.h deleted file mode 100644 index af3d0e6..0000000 --- a/ash/system/session/logout_button_tray.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_LOGOUT_BUTTON_TRAY_H_ -#define ASH_SYSTEM_SESSION_LOGOUT_BUTTON_TRAY_H_ - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/system/session/logout_button_observer.h" -#include "ash/system/tray/tray_background_view.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "ui/views/controls/button/button.h" - -namespace views { -class LabelButton; -} - -namespace ash { - -// Adds a logout button to the launcher's status area if enabled by the -// kShowLogoutButtonInTray pref. -class ASH_EXPORT LogoutButtonTray : public TrayBackgroundView, - public LogoutButtonObserver { - public: - explicit LogoutButtonTray(WmShelf* wm_shelf); - ~LogoutButtonTray() override; - - // TrayBackgroundView: - void SetShelfAlignment(ShelfAlignment alignment) override; - base::string16 GetAccessibleNameForTray() override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void ClickedOutsideBubble() override; - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // LogoutButtonObserver: - void OnShowLogoutButtonInTrayChanged(bool show) override; - void OnLogoutDialogDurationChanged(base::TimeDelta duration) override; - - void UpdateAfterLoginStatusChange(LoginStatus login_status); - - private: - void UpdateVisibility(); - void UpdateButtonTextAndImage(LoginStatus login_status, - ShelfAlignment alignment); - - views::LabelButton* button_; - LoginStatus login_status_; - bool show_logout_button_in_tray_; - base::TimeDelta dialog_duration_; - - DISALLOW_COPY_AND_ASSIGN(LogoutButtonTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_LOGOUT_BUTTON_TRAY_H_
diff --git a/ash/system/session/logout_confirmation_controller.cc b/ash/system/session/logout_confirmation_controller.cc deleted file mode 100644 index 61bddf76..0000000 --- a/ash/system/session/logout_confirmation_controller.cc +++ /dev/null
@@ -1,108 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/session/logout_confirmation_controller.h" - -#include <utility> - -#include "ash/common/login_status.h" -#include "ash/common/wm_shell.h" -#include "ash/system/session/logout_confirmation_dialog.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "base/location.h" -#include "base/time/default_tick_clock.h" -#include "base/time/tick_clock.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { -const int kLogoutConfirmationDelayInSeconds = 20; -} - -LogoutConfirmationController::LogoutConfirmationController( - const base::Closure& logout_closure) - : clock_(new base::DefaultTickClock), - logout_closure_(logout_closure), - dialog_(NULL), - logout_timer_(false, false) { - if (WmShell::HasInstance()) { - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->system_tray_notifier()->AddLastWindowClosedObserver(this); - } -} - -LogoutConfirmationController::~LogoutConfirmationController() { - if (WmShell::HasInstance()) { - WmShell::Get()->RemoveShellObserver(this); - WmShell::Get()->system_tray_notifier()->RemoveLastWindowClosedObserver( - this); - } - if (dialog_) - dialog_->ControllerGone(); -} - -void LogoutConfirmationController::ConfirmLogout(base::TimeTicks logout_time) { - if (!logout_time_.is_null() && logout_time >= logout_time_) { - // If a confirmation dialog is already being shown and its countdown expires - // no later than the |logout_time| requested now, keep the current dialog - // open. - return; - } - logout_time_ = logout_time; - - if (!dialog_) { - // Show confirmation dialog unless this is a unit test without a Shell. - if (WmShell::HasInstance()) - dialog_ = new LogoutConfirmationDialog(this, logout_time_); - } else { - dialog_->Update(logout_time_); - } - - logout_timer_.Start(FROM_HERE, logout_time_ - clock_->NowTicks(), - logout_closure_); -} - -void LogoutConfirmationController::SetClockForTesting( - std::unique_ptr<base::TickClock> clock) { - clock_ = std::move(clock); -} - -void LogoutConfirmationController::OnLockStateChanged(bool locked) { - if (!locked || logout_time_.is_null()) - return; - - // If the screen is locked while a confirmation dialog is being shown, close - // the dialog. - logout_time_ = base::TimeTicks(); - if (dialog_) - dialog_->GetWidget()->Close(); - logout_timer_.Stop(); -} - -void LogoutConfirmationController::OnLogoutConfirmed() { - logout_timer_.Stop(); - logout_closure_.Run(); -} - -void LogoutConfirmationController::OnDialogClosed() { - logout_time_ = base::TimeTicks(); - dialog_ = NULL; - logout_timer_.Stop(); -} - -void LogoutConfirmationController::OnLastWindowClosed() { - if (WmShell::Get()->system_tray_delegate()->GetUserLoginStatus() != - LoginStatus::PUBLIC) { - return; - } - - // Ask the user to confirm logout if a public session is in progress and the - // screen is not locked. - ConfirmLogout( - base::TimeTicks::Now() + - base::TimeDelta::FromSeconds(kLogoutConfirmationDelayInSeconds)); -} - -} // namespace ash
diff --git a/ash/system/session/logout_confirmation_controller.h b/ash/system/session/logout_confirmation_controller.h deleted file mode 100644 index 1d531a89..0000000 --- a/ash/system/session/logout_confirmation_controller.h +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_LOGOUT_CONFIRMATION_CONTROLLER_H_ -#define ASH_SYSTEM_SESSION_LOGOUT_CONFIRMATION_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/system/session/last_window_closed_observer.h" -#include "base/callback.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "base/timer/timer.h" - -namespace base { -class TickClock; -} - -namespace ash { - -class LogoutConfirmationDialog; - -// This class shows a dialog asking the user to confirm or deny logout and -// terminates the session if the user either confirms or allows the countdown -// shown in the dialog to expire. -// -// It is guaranteed that no more than one confirmation dialog will be visible at -// any given time. If there are multiple requests to show a confirmation dialog -// at the same time, the dialog whose countdown expires first is shown. -// -// In public sessions, asks the user to end the session when the last window is -// closed. -class ASH_EXPORT LogoutConfirmationController - : public ShellObserver, - public LastWindowClosedObserver { - public: - // The |logout_closure| must be safe to call as long as |this| is alive. - explicit LogoutConfirmationController(const base::Closure& logout_closure); - ~LogoutConfirmationController() override; - - base::TickClock* clock() const { return clock_.get(); } - - // Shows a LogoutConfirmationDialog. If a confirmation dialog is already being - // shown, it is closed and a new one opened if |logout_time| is earlier than - // the current dialog's |logout_time_|. - void ConfirmLogout(base::TimeTicks logout_time); - - void SetClockForTesting(std::unique_ptr<base::TickClock> clock); - - // ShellObserver: - void OnLockStateChanged(bool locked) override; - - // Called by the |dialog_| when the user confirms logout. - void OnLogoutConfirmed(); - - // Called by the |dialog_| when it is closed. - void OnDialogClosed(); - - LogoutConfirmationDialog* dialog_for_testing() const { return dialog_; } - - private: - // LastWindowClosedObserver: - void OnLastWindowClosed() override; - - std::unique_ptr<base::TickClock> clock_; - base::Closure logout_closure_; - - base::TimeTicks logout_time_; - LogoutConfirmationDialog* dialog_; // Owned by the Views hierarchy. - base::Timer logout_timer_; - - DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationController); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_LOGOUT_CONFIRMATION_CONTROLLER_H_
diff --git a/ash/system/session/logout_confirmation_controller_unittest.cc b/ash/system/session/logout_confirmation_controller_unittest.cc deleted file mode 100644 index 70ebeb5..0000000 --- a/ash/system/session/logout_confirmation_controller_unittest.cc +++ /dev/null
@@ -1,154 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/session/logout_confirmation_controller.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/memory/ref_counted.h" -#include "base/test/test_mock_time_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/tick_clock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace ash { - -class LogoutConfirmationControllerTest : public testing::Test { - protected: - LogoutConfirmationControllerTest(); - ~LogoutConfirmationControllerTest() override; - - void LogOut(); - - bool log_out_called_; - - scoped_refptr<base::TestMockTimeTaskRunner> runner_; - base::ThreadTaskRunnerHandle runner_handle_; - - LogoutConfirmationController controller_; - - private: - DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationControllerTest); -}; - -LogoutConfirmationControllerTest::LogoutConfirmationControllerTest() - : log_out_called_(false), - runner_(new base::TestMockTimeTaskRunner), - runner_handle_(runner_), - controller_(base::Bind(&LogoutConfirmationControllerTest::LogOut, - base::Unretained(this))) { - controller_.SetClockForTesting(runner_->GetMockTickClock()); -} - -LogoutConfirmationControllerTest::~LogoutConfirmationControllerTest() {} - -void LogoutConfirmationControllerTest::LogOut() { - log_out_called_ = true; -} - -// Verifies that the user is logged out immediately if logout confirmation with -// a zero-length countdown is requested. -TEST_F(LogoutConfirmationControllerTest, ZeroDuration) { - controller_.ConfirmLogout(runner_->NowTicks()); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta()); - EXPECT_TRUE(log_out_called_); -} - -// Verifies that the user is logged out when the countdown expires. -TEST_F(LogoutConfirmationControllerTest, DurationExpired) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); - EXPECT_TRUE(log_out_called_); -} - -// Verifies that when a second request to confirm logout is made and the second -// request's countdown ends before the original request's, the user is logged -// out when the new countdown expires. -TEST_F(LogoutConfirmationControllerTest, DurationShortened) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(30)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); - EXPECT_FALSE(log_out_called_); - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); - EXPECT_TRUE(log_out_called_); -} - -// Verifies that when a second request to confirm logout is made and the second -// request's countdown ends after the original request's, the user is logged -// out when the original countdown expires. -TEST_F(LogoutConfirmationControllerTest, DurationExtended) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); - EXPECT_FALSE(log_out_called_); - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); - EXPECT_TRUE(log_out_called_); -} - -// Verifies that when the screen is locked while the countdown is running, the -// user is not logged out, even when the original countdown expires. -TEST_F(LogoutConfirmationControllerTest, Lock) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - controller_.OnLockStateChanged(true); - runner_->FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(log_out_called_); -} - -// Verifies that when the user confirms the logout request, the user is logged -// out immediately. -TEST_F(LogoutConfirmationControllerTest, UserAccepted) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - controller_.OnLogoutConfirmed(); - EXPECT_TRUE(log_out_called_); -} - -// Verifies that when the user denies the logout request, the user is not logged -// out, even when the original countdown expires. -TEST_F(LogoutConfirmationControllerTest, UserDenied) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - controller_.OnDialogClosed(); - runner_->FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(log_out_called_); -} - -// Verifies that after the user has denied a logout request, a subsequent logout -// request is handled correctly and the user is logged out when the countdown -// expires. -TEST_F(LogoutConfirmationControllerTest, DurationExpiredAfterDeniedRequest) { - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - controller_.OnDialogClosed(); - runner_->FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(log_out_called_); - - controller_.ConfirmLogout(runner_->NowTicks() + - base::TimeDelta::FromSeconds(10)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); - EXPECT_FALSE(log_out_called_); - runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); - EXPECT_TRUE(log_out_called_); -} - -} // namespace ash
diff --git a/ash/system/session/logout_confirmation_dialog.cc b/ash/system/session/logout_confirmation_dialog.cc deleted file mode 100644 index 2eaaef2..0000000 --- a/ash/system/session/logout_confirmation_dialog.cc +++ /dev/null
@@ -1,122 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/session/logout_confirmation_dialog.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/session/logout_confirmation_controller.h" -#include "ash/system/tray/tray_constants.h" -#include "base/location.h" -#include "base/time/tick_clock.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/base/ui_base_types.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/text_constants.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -const int kCountdownUpdateIntervalMs = 1000; // 1 second. - -const int kHalfSecondInMs = 500; // Half a second. - -} // namespace - -LogoutConfirmationDialog::LogoutConfirmationDialog( - LogoutConfirmationController* controller, - base::TimeTicks logout_time) - : controller_(controller), logout_time_(logout_time) { - SetLayoutManager(new views::FillLayout()); - - label_ = new views::Label; - label_->SetBorder(views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, - kTrayPopupPaddingHorizontal)); - label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - label_->SetMultiLine(true); - AddChildView(label_); - - UpdateLabel(); - - views::Widget* widget = new views::Widget; - views::Widget::InitParams params = - GetDialogWidgetInitParams(this, nullptr, nullptr, gfx::Rect()); - WmShell::Get() - ->GetPrimaryRootWindow() - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - widget, kShellWindowId_SystemModalContainer, ¶ms); - widget->Init(params); - widget->Show(); - - update_timer_.Start( - FROM_HERE, base::TimeDelta::FromMilliseconds(kCountdownUpdateIntervalMs), - this, &LogoutConfirmationDialog::UpdateLabel); -} - -LogoutConfirmationDialog::~LogoutConfirmationDialog() {} - -void LogoutConfirmationDialog::Update(base::TimeTicks logout_time) { - logout_time_ = logout_time; - UpdateLabel(); -} - -void LogoutConfirmationDialog::ControllerGone() { - controller_ = nullptr; - GetWidget()->Close(); -} - -bool LogoutConfirmationDialog::Accept() { - logout_time_ = controller_->clock()->NowTicks(); - UpdateLabel(); - controller_->OnLogoutConfirmed(); - return true; -} - -ui::ModalType LogoutConfirmationDialog::GetModalType() const { - return ui::MODAL_TYPE_SYSTEM; -} - -base::string16 LogoutConfirmationDialog::GetWindowTitle() const { - return l10n_util::GetStringUTF16(IDS_ASH_LOGOUT_CONFIRMATION_TITLE); -} - -base::string16 LogoutConfirmationDialog::GetDialogButtonLabel( - ui::DialogButton button) const { - if (button == ui::DIALOG_BUTTON_OK) - return l10n_util::GetStringUTF16(IDS_ASH_LOGOUT_CONFIRMATION_BUTTON); - return views::DialogDelegateView::GetDialogButtonLabel(button); -} - -void LogoutConfirmationDialog::WindowClosing() { - update_timer_.Stop(); - if (controller_) - controller_->OnDialogClosed(); -} - -void LogoutConfirmationDialog::UpdateLabel() { - const base::TimeDelta time_remaining = - logout_time_ - controller_->clock()->NowTicks(); - if (time_remaining >= base::TimeDelta::FromMilliseconds(kHalfSecondInMs)) { - label_->SetText(l10n_util::GetStringFUTF16( - IDS_ASH_LOGOUT_CONFIRMATION_WARNING, - ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, 10, - time_remaining))); - } else { - label_->SetText( - l10n_util::GetStringUTF16(IDS_ASH_LOGOUT_CONFIRMATION_WARNING_NOW)); - update_timer_.Stop(); - } -} - -} // namespace ash
diff --git a/ash/system/session/logout_confirmation_dialog.h b/ash/system/session/logout_confirmation_dialog.h deleted file mode 100644 index 04c07d0..0000000 --- a/ash/system/session/logout_confirmation_dialog.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_LOGOUT_CONFIRMATION_DIALOG_H_ -#define ASH_SYSTEM_SESSION_LOGOUT_CONFIRMATION_DIALOG_H_ - -#include "base/macros.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "ui/views/window/dialog_delegate.h" - -namespace views { -class Label; -} - -namespace ash { - -class LogoutConfirmationController; - -// A dialog that asks the user to confirm or deny logout. The dialog shows a -// countdown and informs the user that a logout will happen automatically if no -// choice is made before the countdown has expired. -class LogoutConfirmationDialog : public views::DialogDelegateView { - public: - LogoutConfirmationDialog(LogoutConfirmationController* controller, - base::TimeTicks logout_time); - ~LogoutConfirmationDialog() override; - - void Update(base::TimeTicks logout_time); - - // Called when |controller_| is no longer valid. - void ControllerGone(); - - // views::DialogDelegateView: - bool Accept() override; - ui::ModalType GetModalType() const override; - base::string16 GetWindowTitle() const override; - base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; - void WindowClosing() override; - - private: - void UpdateLabel(); - - LogoutConfirmationController* controller_; - base::TimeTicks logout_time_; - - views::Label* label_; - - base::RepeatingTimer update_timer_; - - DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationDialog); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_LOGOUT_CONFIRMATION_DIALOG_H_
diff --git a/ash/system/session/session_length_limit_observer.h b/ash/system/session/session_length_limit_observer.h deleted file mode 100644 index 610feb4..0000000 --- a/ash/system/session/session_length_limit_observer.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_SESSION_LENGTH_LIMIT_OBSERVER_H_ -#define ASH_SYSTEM_SESSION_SESSION_LENGTH_LIMIT_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -// Observer for the session length limit. -class ASH_EXPORT SessionLengthLimitObserver { - public: - virtual ~SessionLengthLimitObserver() {} - - // Called when the session start time is updated. - virtual void OnSessionStartTimeChanged() = 0; - - // Called when the session length limit is updated. - virtual void OnSessionLengthLimitChanged() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_SESSION_LENGTH_LIMIT_OBSERVER_H_
diff --git a/ash/system/session/tray_session_length_limit.cc b/ash/system/session/tray_session_length_limit.cc deleted file mode 100644 index 2f5e14d..0000000 --- a/ash/system/session/tray_session_length_limit.cc +++ /dev/null
@@ -1,196 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/session/tray_session_length_limit.h" - -#include <algorithm> -#include <memory> -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/label_tray_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/l10n/time_format.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/views/view.h" - -namespace ash { -namespace { - -// If the remaining session time falls below this threshold, the user should be -// informed that the session is about to expire. -const int kExpiringSoonThresholdInMinutes = 5; - -// Use 500ms interval for updates to notification and tray bubble to reduce the -// likelihood of a user-visible skip in high load situations (as might happen -// with 1000ms). -const int kTimerIntervalInMilliseconds = 500; - -} // namespace - -// static -const char TraySessionLengthLimit::kNotificationId[] = - "chrome://session/timeout"; - -TraySessionLengthLimit::TraySessionLengthLimit(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_SESSION_LENGTH_LIMIT), - limit_state_(LIMIT_NONE), - last_limit_state_(LIMIT_NONE), - tray_bubble_view_(NULL) { - WmShell::Get()->system_tray_notifier()->AddSessionLengthLimitObserver(this); - Update(); -} - -TraySessionLengthLimit::~TraySessionLengthLimit() { - WmShell::Get()->system_tray_notifier()->RemoveSessionLengthLimitObserver( - this); -} - -// Add view to tray bubble. -views::View* TraySessionLengthLimit::CreateDefaultView(LoginStatus status) { - CHECK(!tray_bubble_view_); - UpdateState(); - if (limit_state_ == LIMIT_NONE) - return NULL; - tray_bubble_view_ = - new LabelTrayView(NULL /* click_listener */, - IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT); - tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage()); - return tray_bubble_view_; -} - -// View has been removed from tray bubble. -void TraySessionLengthLimit::DestroyDefaultView() { - tray_bubble_view_ = NULL; -} - -void TraySessionLengthLimit::OnSessionStartTimeChanged() { - Update(); -} - -void TraySessionLengthLimit::OnSessionLengthLimitChanged() { - Update(); -} - -void TraySessionLengthLimit::Update() { - UpdateState(); - UpdateNotification(); - UpdateTrayBubbleView(); -} - -void TraySessionLengthLimit::UpdateState() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (delegate->GetSessionStartTime(&session_start_time_) && - delegate->GetSessionLengthLimit(&time_limit_)) { - const base::TimeDelta expiring_soon_threshold( - base::TimeDelta::FromMinutes(kExpiringSoonThresholdInMinutes)); - remaining_session_time_ = - std::max(time_limit_ - (base::TimeTicks::Now() - session_start_time_), - base::TimeDelta()); - limit_state_ = remaining_session_time_ <= expiring_soon_threshold - ? LIMIT_EXPIRING_SOON - : LIMIT_SET; - if (!timer_) - timer_.reset(new base::RepeatingTimer); - if (!timer_->IsRunning()) { - timer_->Start(FROM_HERE, base::TimeDelta::FromMilliseconds( - kTimerIntervalInMilliseconds), - this, &TraySessionLengthLimit::Update); - } - } else { - remaining_session_time_ = base::TimeDelta(); - limit_state_ = LIMIT_NONE; - timer_.reset(); - } -} - -void TraySessionLengthLimit::UpdateNotification() { - message_center::MessageCenter* message_center = - message_center::MessageCenter::Get(); - - // If state hasn't changed and the notification has already been acknowledged, - // we won't re-create it. - if (limit_state_ == last_limit_state_ && - !message_center->FindVisibleNotificationById(kNotificationId)) { - return; - } - - // After state change, any possibly existing notification is removed to make - // sure it is re-shown even if it had been acknowledged by the user before - // (and in the rare case of state change towards LIMIT_NONE to make the - // notification disappear). - if (limit_state_ != last_limit_state_ && - message_center->FindVisibleNotificationById(kNotificationId)) { - message_center::MessageCenter::Get()->RemoveNotification( - kNotificationId, false /* by_user */); - } - - // For LIMIT_NONE, there's nothing more to do. - if (limit_state_ == LIMIT_NONE) { - last_limit_state_ = limit_state_; - return; - } - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - message_center::RichNotificationData data; - data.should_make_spoken_feedback_for_popup_updates = - (limit_state_ != last_limit_state_); - std::unique_ptr<message_center::Notification> notification( - new message_center::Notification( - message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, - base::string16() /* title */, - ComposeNotificationMessage() /* message */, - bundle.GetImageNamed( - IDR_AURA_UBER_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT), - base::string16() /* display_source */, GURL(), - message_center::NotifierId( - message_center::NotifierId::SYSTEM_COMPONENT, - system_notifier::kNotifierSessionLengthTimeout), - data, NULL /* delegate */)); - notification->SetSystemPriority(); - if (message_center->FindVisibleNotificationById(kNotificationId)) - message_center->UpdateNotification(kNotificationId, - std::move(notification)); - else - message_center->AddNotification(std::move(notification)); - last_limit_state_ = limit_state_; -} - -void TraySessionLengthLimit::UpdateTrayBubbleView() const { - if (!tray_bubble_view_) - return; - if (limit_state_ == LIMIT_NONE) - tray_bubble_view_->SetMessage(base::string16()); - else - tray_bubble_view_->SetMessage(ComposeTrayBubbleMessage()); - tray_bubble_view_->Layout(); -} - -base::string16 TraySessionLengthLimit::ComposeNotificationMessage() const { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_NOTIFICATION_SESSION_LENGTH_LIMIT, - ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, 10, - remaining_session_time_)); -} - -base::string16 TraySessionLengthLimit::ComposeTrayBubbleMessage() const { - return l10n_util::GetStringFUTF16( - IDS_ASH_STATUS_TRAY_BUBBLE_SESSION_LENGTH_LIMIT, - ui::TimeFormat::Detailed(ui::TimeFormat::FORMAT_DURATION, - ui::TimeFormat::LENGTH_LONG, 10, - remaining_session_time_)); -} - -} // namespace ash
diff --git a/ash/system/session/tray_session_length_limit.h b/ash/system/session/tray_session_length_limit.h deleted file mode 100644 index fef3b4f0..0000000 --- a/ash/system/session/tray_session_length_limit.h +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SESSION_TRAY_SESSION_LENGTH_LIMIT_H_ -#define ASH_SYSTEM_SESSION_TRAY_SESSION_LENGTH_LIMIT_H_ - -#include <memory> - -#include "ash/system/session/session_length_limit_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" -#include "base/strings/string16.h" -#include "base/time/time.h" -#include "base/timer/timer.h" - -namespace ash { -namespace test { -class TraySessionLengthLimitTest; -} - -class LabelTrayView; - -// Adds a countdown timer to the system tray if the session length is limited. -class ASH_EXPORT TraySessionLengthLimit : public SystemTrayItem, - public SessionLengthLimitObserver { - public: - enum LimitState { LIMIT_NONE, LIMIT_SET, LIMIT_EXPIRING_SOON }; - - explicit TraySessionLengthLimit(SystemTray* system_tray); - ~TraySessionLengthLimit() override; - - // SystemTrayItem: - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyDefaultView() override; - - // SessionLengthLimitObserver: - void OnSessionStartTimeChanged() override; - void OnSessionLengthLimitChanged() override; - - private: - friend class test::TraySessionLengthLimitTest; - - static const char kNotificationId[]; - - // Update state, notification and tray bubble view. Called by the - // RepeatingTimer in regular intervals and also by OnSession*Changed(). - void Update(); - - // Recalculate |limit_state_| and |remaining_session_time_|. - void UpdateState(); - - void UpdateNotification(); - void UpdateTrayBubbleView() const; - - // These require that the state has been updated before. - base::string16 ComposeNotificationMessage() const; - base::string16 ComposeTrayBubbleMessage() const; - - base::TimeTicks session_start_time_; - base::TimeDelta time_limit_; - base::TimeDelta remaining_session_time_; - - LimitState limit_state_; // Current state. - LimitState last_limit_state_; // State of last notification update. - - LabelTrayView* tray_bubble_view_; - std::unique_ptr<base::RepeatingTimer> timer_; - - DISALLOW_COPY_AND_ASSIGN(TraySessionLengthLimit); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SESSION_TRAY_SESSION_LENGTH_LIMIT_H_
diff --git a/ash/system/session/tray_session_length_limit_unittest.cc b/ash/system/session/tray_session_length_limit_unittest.cc deleted file mode 100644 index 19df0cc..0000000 --- a/ash/system/session/tray_session_length_limit_unittest.cc +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/session/tray_session_length_limit.h" - -#include "ash/system/tray/system_tray.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/test_system_tray_delegate.h" -#include "base/memory/ptr_util.h" -#include "base/time/time.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_types.h" - -namespace ash { -namespace test { - -class TraySessionLengthLimitTest : public AshTestBase { - public: - TraySessionLengthLimitTest() {} - ~TraySessionLengthLimitTest() override {} - - void SetUp() override { - AshTestBase::SetUp(); - SystemTray* system_tray = GetPrimarySystemTray(); - tray_session_length_limit_ = new TraySessionLengthLimit(system_tray); - system_tray->AddTrayItem(base::WrapUnique(tray_session_length_limit_)); - } - - void TearDown() override { - ClearSessionLengthLimit(); - AshTestBase::TearDown(); - } - - protected: - void UpdateSessionLengthLimitInMin(int mins) { - GetSystemTrayDelegate()->SetSessionLengthLimitForTest( - base::TimeDelta::FromMinutes(mins)); - tray_session_length_limit_->OnSessionLengthLimitChanged(); - } - - message_center::Notification* GetNotification() { - const message_center::NotificationList::Notifications& notifications = - message_center::MessageCenter::Get()->GetVisibleNotifications(); - for (message_center::NotificationList::Notifications::const_iterator iter = - notifications.begin(); - iter != notifications.end(); ++iter) { - if ((*iter)->id() == TraySessionLengthLimit::kNotificationId) - return *iter; - } - return nullptr; - } - - void ClearSessionLengthLimit() { - GetSystemTrayDelegate()->ClearSessionLengthLimit(); - tray_session_length_limit_->OnSessionLengthLimitChanged(); - } - - void RemoveNotification() { - message_center::MessageCenter::Get()->RemoveNotification( - TraySessionLengthLimit::kNotificationId, false /* by_user */); - } - - TraySessionLengthLimit* tray_session_length_limit() { - return tray_session_length_limit_; - } - - private: - // Weak reference, owned by the SystemTray. - TraySessionLengthLimit* tray_session_length_limit_; - - DISALLOW_COPY_AND_ASSIGN(TraySessionLengthLimitTest); -}; - -TEST_F(TraySessionLengthLimitTest, Notification) { - // No notifications when no session limit. - EXPECT_FALSE(GetNotification()); - - // Limit is 15 min. - UpdateSessionLengthLimitInMin(15); - message_center::Notification* notification = GetNotification(); - EXPECT_TRUE(notification); - EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); - base::string16 first_content = notification->message(); - // Should read the content. - EXPECT_TRUE(notification->rich_notification_data() - .should_make_spoken_feedback_for_popup_updates); - - // Limit is 10 min. - UpdateSessionLengthLimitInMin(10); - notification = GetNotification(); - EXPECT_TRUE(notification); - EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); - // The content should be updated. - EXPECT_NE(first_content, notification->message()); - // Should NOT read, because just update the remaining time. - EXPECT_FALSE(notification->rich_notification_data() - .should_make_spoken_feedback_for_popup_updates); - - // Limit is 3 min. - UpdateSessionLengthLimitInMin(3); - notification = GetNotification(); - EXPECT_TRUE(notification); - EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); - // Should read the content again because the state has changed. - EXPECT_TRUE(notification->rich_notification_data() - .should_make_spoken_feedback_for_popup_updates); - - // Session length limit is updated to longer: 15 min. - UpdateSessionLengthLimitInMin(15); - notification = GetNotification(); - EXPECT_TRUE(notification); - EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority()); - // Should read again because an increase of the remaining time is noteworthy. - EXPECT_TRUE(notification->rich_notification_data() - .should_make_spoken_feedback_for_popup_updates); - - // Clears the limit: the notification should be gone. - ClearSessionLengthLimit(); - EXPECT_FALSE(GetNotification()); -} - -TEST_F(TraySessionLengthLimitTest, RemoveNotification) { - // Limit is 15 min. - UpdateSessionLengthLimitInMin(15); - EXPECT_TRUE(GetNotification()); - - // Removes the notification. - RemoveNotification(); - EXPECT_FALSE(GetNotification()); - - // Limit is 10 min. The notification should not re-appear. - UpdateSessionLengthLimitInMin(10); - EXPECT_FALSE(GetNotification()); - - // Limit is 3 min. The notification should re-appear and should be re-read - // because of state change. - UpdateSessionLengthLimitInMin(3); - message_center::Notification* notification = GetNotification(); - EXPECT_TRUE(notification); - EXPECT_TRUE(notification->rich_notification_data() - .should_make_spoken_feedback_for_popup_updates); - - RemoveNotification(); - - // Session length limit is updated to longer state. Notification should - // re-appear and be re-read. - UpdateSessionLengthLimitInMin(15); - notification = GetNotification(); - EXPECT_TRUE(notification); - EXPECT_TRUE(notification->rich_notification_data() - .should_make_spoken_feedback_for_popup_updates); -} - -} // namespace test -} // namespace ash
diff --git a/ash/system/settings/tray_settings.cc b/ash/system/settings/tray_settings.cc deleted file mode 100644 index 6678414..0000000 --- a/ash/system/settings/tray_settings.cc +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/settings/tray_settings.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/power/power_status.h" -#include "ash/system/power/power_status_view.h" -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "base/logging.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/image/image.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/view.h" - -namespace ash { -namespace tray { - -// TODO(tdanderson): Remove this class once material design is enabled by -// default. See crbug.com/614453. -class SettingsDefaultView : public ActionableView, - public PowerStatus::Observer { - public: - SettingsDefaultView(SystemTrayItem* owner, LoginStatus status) - : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), - login_status_(status), - label_(nullptr), - power_status_view_(nullptr) { - PowerStatus::Get()->AddObserver(this); - SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, - ash::kTrayPopupPaddingHorizontal, 0, - ash::kTrayPopupPaddingBetweenItems)); - - bool power_view_right_align = false; - if (login_status_ != LoginStatus::NOT_LOGGED_IN && - login_status_ != LoginStatus::LOCKED && - !WmShell::Get() - ->GetSessionStateDelegate() - ->IsInSecondaryLoginScreen()) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - views::ImageView* icon = TrayPopupUtils::CreateMainImageView(); - - icon->SetImage( - rb.GetImageNamed(IDR_AURA_UBER_TRAY_SETTINGS).ToImageSkia()); - icon->set_id(test::kSettingsTrayItemViewId); - AddChildView(icon); - - base::string16 text = rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_SETTINGS); - label_ = TrayPopupUtils::CreateDefaultLabel(); - label_->SetText(text); - AddChildView(label_); - SetAccessibleName(text); - - power_view_right_align = true; - } - - if (PowerStatus::Get()->IsBatteryPresent()) { - power_status_view_ = new ash::PowerStatusView(power_view_right_align); - AddChildView(power_status_view_); - OnPowerStatusChanged(); - } - - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - SetInkDropMode(InkDropHostView::InkDropMode::ON); - } - - ~SettingsDefaultView() override { PowerStatus::Get()->RemoveObserver(this); } - - // Overridden from ash::ActionableView. - bool PerformAction(const ui::Event& event) override { - if (login_status_ == LoginStatus::NOT_LOGGED_IN || - login_status_ == LoginStatus::LOCKED || - WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen()) { - return false; - } - - WmShell::Get()->system_tray_controller()->ShowSettings(); - CloseSystemBubble(); - return true; - } - - // Overridden from views::View. - void Layout() override { - views::View::Layout(); - - if (label_ && power_status_view_) { - // Let the box-layout do the layout first. Then move power_status_view_ - // to right align if it is created. - gfx::Size size = power_status_view_->GetPreferredSize(); - gfx::Rect bounds(size); - bounds.set_x(width() - size.width() - ash::kTrayPopupPaddingBetweenItems); - bounds.set_y((height() - size.height()) / 2); - power_status_view_->SetBoundsRect(bounds); - } - } - - // Overridden from views::View. - void ChildPreferredSizeChanged(views::View* child) override { - views::View::ChildPreferredSizeChanged(child); - Layout(); - } - - // Overridden from PowerStatus::Observer. - void OnPowerStatusChanged() override { - if (!PowerStatus::Get()->IsBatteryPresent()) - return; - - base::string16 accessible_name = - label_ - ? label_->text() + base::ASCIIToUTF16(", ") + - PowerStatus::Get()->GetAccessibleNameString(true) - : PowerStatus::Get()->GetAccessibleNameString(true); - SetAccessibleName(accessible_name); - } - - private: - LoginStatus login_status_; - views::Label* label_; - ash::PowerStatusView* power_status_view_; - - DISALLOW_COPY_AND_ASSIGN(SettingsDefaultView); -}; - -} // namespace tray - -TraySettings::TraySettings(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_SETTINGS), default_view_(nullptr) {} - -TraySettings::~TraySettings() {} - -views::View* TraySettings::CreateTrayView(LoginStatus status) { - return nullptr; -} - -views::View* TraySettings::CreateDefaultView(LoginStatus status) { - if ((status == LoginStatus::NOT_LOGGED_IN || status == LoginStatus::LOCKED) && - !PowerStatus::Get()->IsBatteryPresent()) - return nullptr; - if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings()) - return nullptr; - CHECK(default_view_ == nullptr); - default_view_ = new tray::SettingsDefaultView(this, status); - return default_view_; -} - -views::View* TraySettings::CreateDetailedView(LoginStatus status) { - NOTIMPLEMENTED(); - return nullptr; -} - -void TraySettings::DestroyTrayView() {} - -void TraySettings::DestroyDefaultView() { - default_view_ = nullptr; -} - -void TraySettings::DestroyDetailedView() {} - -void TraySettings::UpdateAfterLoginStatusChange(LoginStatus status) {} - -} // namespace ash
diff --git a/ash/system/settings/tray_settings.h b/ash/system/settings/tray_settings.h deleted file mode 100644 index 8d01656..0000000 --- a/ash/system/settings/tray_settings.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SETTINGS_TRAY_SETTINGS_H_ -#define ASH_SYSTEM_SETTINGS_TRAY_SETTINGS_H_ - -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { -namespace tray { -class SettingsDefaultView; -} - -// TODO(tdanderson): Remove this class once material design is enabled by -// default. See crbug.com/614453. -class TraySettings : public SystemTrayItem { - public: - explicit TraySettings(SystemTray* system_tray); - ~TraySettings() override; - - private: - // Overridden from SystemTrayItem - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - - tray::SettingsDefaultView* default_view_; - - DISALLOW_COPY_AND_ASSIGN(TraySettings); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SETTINGS_TRAY_SETTINGS_H_
diff --git a/ash/system/status_area_layout_manager.cc b/ash/system/status_area_layout_manager.cc deleted file mode 100644 index ec65ee2..0000000 --- a/ash/system/status_area_layout_manager.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/status_area_layout_manager.h" - -#include "ash/common/wm_window.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/system/status_area_widget.h" -#include "base/auto_reset.h" - -namespace ash { - -//////////////////////////////////////////////////////////////////////////////// -// StatusAreaLayoutManager, public: - -StatusAreaLayoutManager::StatusAreaLayoutManager(ShelfWidget* shelf_widget) - : in_layout_(false), shelf_widget_(shelf_widget) {} - -StatusAreaLayoutManager::~StatusAreaLayoutManager() {} - -//////////////////////////////////////////////////////////////////////////////// -// StatusAreaLayoutManager, aura::LayoutManager implementation: - -void StatusAreaLayoutManager::OnWindowResized() { - LayoutStatusArea(); -} - -void StatusAreaLayoutManager::SetChildBounds( - WmWindow* child, - const gfx::Rect& requested_bounds) { - // Only need to have the shelf do a layout if the child changing is the status - // area and the shelf isn't in the process of doing a layout. - if (child != WmWindow::Get( - shelf_widget_->status_area_widget()->GetNativeWindow()) || - in_layout_) { - wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); - return; - } - - // If the bounds match, no need to do anything. Check for target bounds to - // ensure any active animation is retargeted. - if (requested_bounds == child->GetTargetBounds()) - return; - - wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); - LayoutStatusArea(); -} - -//////////////////////////////////////////////////////////////////////////////// -// StatusAreaLayoutManager, private: - -void StatusAreaLayoutManager::LayoutStatusArea() { - // Shelf layout manager may be already doing layout. - if (shelf_widget_->shelf_layout_manager()->updating_bounds()) - return; - - base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); - shelf_widget_->shelf_layout_manager()->LayoutShelf(); -} - -} // namespace ash
diff --git a/ash/system/status_area_layout_manager.h b/ash/system/status_area_layout_manager.h deleted file mode 100644 index 2d1fecb..0000000 --- a/ash/system/status_area_layout_manager.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_STATUS_AREA_LAYOUT_MANAGER_H_ -#define ASH_SYSTEM_STATUS_AREA_LAYOUT_MANAGER_H_ - -#include "ash/wm/wm_snap_to_pixel_layout_manager.h" -#include "base/macros.h" - -namespace ash { - -class ShelfWidget; - -// StatusAreaLayoutManager is a layout manager responsible for the status area. -// In any case when status area needs relayout it redirects this call to -// ShelfLayoutManager. -class StatusAreaLayoutManager : public wm::WmSnapToPixelLayoutManager { - public: - explicit StatusAreaLayoutManager(ShelfWidget* shelf_widget); - ~StatusAreaLayoutManager() override; - - // Overridden from wm::WmSnapToPixelLayoutManager: - void OnWindowResized() override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - private: - // Updates layout of the status area. Effectively calls ShelfLayoutManager - // to update layout of the shelf. - void LayoutStatusArea(); - - // True when inside LayoutStatusArea method. - // Used to prevent calling itself again from SetChildBounds(). - bool in_layout_; - - ShelfWidget* shelf_widget_; - - DISALLOW_COPY_AND_ASSIGN(StatusAreaLayoutManager); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_STATUS_AREA_LAYOUT_MANAGER_H_
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc deleted file mode 100644 index dd27eae..0000000 --- a/ash/system/status_area_widget.cc +++ /dev/null
@@ -1,234 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/status_area_widget.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/ime_menu/ime_menu_tray.h" -#include "ash/system/overview/overview_button_tray.h" -#include "ash/system/palette/palette_tray.h" -#include "ash/system/palette/palette_utils.h" -#include "ash/system/session/logout_button_tray.h" -#include "ash/system/status_area_widget_delegate.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/virtual_keyboard/virtual_keyboard_tray.h" -#include "ash/system/web_notification/web_notification_tray.h" -#include "base/i18n/time_formatting.h" -#include "ui/display/display.h" -#include "ui/native_theme/native_theme_dark_aura.h" - -namespace ash { - -StatusAreaWidget::StatusAreaWidget(WmWindow* status_container, - WmShelf* wm_shelf) - : status_area_widget_delegate_(new StatusAreaWidgetDelegate), - overview_button_tray_(nullptr), - system_tray_(nullptr), - web_notification_tray_(nullptr), - logout_button_tray_(nullptr), - palette_tray_(nullptr), - virtual_keyboard_tray_(nullptr), - ime_menu_tray_(nullptr), - login_status_(LoginStatus::NOT_LOGGED_IN), - wm_shelf_(wm_shelf) { - views::Widget::InitParams params( - views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.delegate = status_area_widget_delegate_; - params.name = "StatusAreaWidget"; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - status_container->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - this, status_container->GetShellWindowId(), ¶ms); - Init(params); - set_focus_on_creation(false); - SetContentsView(status_area_widget_delegate_); -} - -StatusAreaWidget::~StatusAreaWidget() {} - -void StatusAreaWidget::CreateTrayViews() { - AddOverviewButtonTray(); - AddSystemTray(); - AddWebNotificationTray(); - AddPaletteTray(); - AddVirtualKeyboardTray(); - AddImeMenuTray(); - AddLogoutButtonTray(); - - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - DCHECK(delegate); - // Initialize after all trays have been created. - system_tray_->InitializeTrayItems(delegate, web_notification_tray_); - web_notification_tray_->Initialize(); - logout_button_tray_->Initialize(); - if (palette_tray_) - palette_tray_->Initialize(); - virtual_keyboard_tray_->Initialize(); - ime_menu_tray_->Initialize(); - overview_button_tray_->Initialize(); - SetShelfAlignment(system_tray_->shelf_alignment()); - UpdateAfterLoginStatusChange(delegate->GetUserLoginStatus()); -} - -void StatusAreaWidget::Shutdown() { - system_tray_->Shutdown(); - // Destroy the trays early, causing them to be removed from the view - // hierarchy. Do not used scoped pointers since we don't want to destroy them - // in the destructor if Shutdown() is not called (e.g. in tests). - delete web_notification_tray_; - web_notification_tray_ = nullptr; - // Must be destroyed after |web_notification_tray_|. - delete system_tray_; - system_tray_ = nullptr; - delete ime_menu_tray_; - ime_menu_tray_ = nullptr; - delete virtual_keyboard_tray_; - virtual_keyboard_tray_ = nullptr; - delete logout_button_tray_; - logout_button_tray_ = nullptr; - delete overview_button_tray_; - overview_button_tray_ = nullptr; -} - -void StatusAreaWidget::SetShelfAlignment(ShelfAlignment alignment) { - status_area_widget_delegate_->set_alignment(alignment); - if (system_tray_) - system_tray_->SetShelfAlignment(alignment); - if (web_notification_tray_) - web_notification_tray_->SetShelfAlignment(alignment); - if (logout_button_tray_) - logout_button_tray_->SetShelfAlignment(alignment); - if (virtual_keyboard_tray_) - virtual_keyboard_tray_->SetShelfAlignment(alignment); - if (ime_menu_tray_) - ime_menu_tray_->SetShelfAlignment(alignment); - if (palette_tray_) - palette_tray_->SetShelfAlignment(alignment); - if (overview_button_tray_) - overview_button_tray_->SetShelfAlignment(alignment); - status_area_widget_delegate_->UpdateLayout(); -} - -void StatusAreaWidget::UpdateAfterLoginStatusChange(LoginStatus login_status) { - if (login_status_ == login_status) - return; - login_status_ = login_status; - if (system_tray_) - system_tray_->UpdateAfterLoginStatusChange(login_status); - if (web_notification_tray_) - web_notification_tray_->UpdateAfterLoginStatusChange(login_status); - if (logout_button_tray_) - logout_button_tray_->UpdateAfterLoginStatusChange(login_status); - if (overview_button_tray_) - overview_button_tray_->UpdateAfterLoginStatusChange(login_status); -} - -bool StatusAreaWidget::ShouldShowShelf() const { - if ((system_tray_ && system_tray_->ShouldShowShelf()) || - (web_notification_tray_ && - web_notification_tray_->ShouldBlockShelfAutoHide())) - return true; - - if (palette_tray_ && palette_tray_->ShouldBlockShelfAutoHide()) - return true; - - if (ime_menu_tray_ && ime_menu_tray_->ShouldBlockShelfAutoHide()) - return true; - - return false; -} - -bool StatusAreaWidget::IsMessageBubbleShown() const { - return ((system_tray_ && system_tray_->IsSystemBubbleVisible()) || - (web_notification_tray_ && - web_notification_tray_->IsMessageCenterBubbleVisible())); -} - -void StatusAreaWidget::SchedulePaint() { - status_area_widget_delegate_->SchedulePaint(); - web_notification_tray_->SchedulePaint(); - system_tray_->SchedulePaint(); - virtual_keyboard_tray_->SchedulePaint(); - logout_button_tray_->SchedulePaint(); - ime_menu_tray_->SchedulePaint(); - if (palette_tray_) - palette_tray_->SchedulePaint(); - overview_button_tray_->SchedulePaint(); -} - -const ui::NativeTheme* StatusAreaWidget::GetNativeTheme() const { - return MaterialDesignController::IsShelfMaterial() - ? ui::NativeThemeDarkAura::instance() - : Widget::GetNativeTheme(); -} - -void StatusAreaWidget::OnNativeWidgetActivationChanged(bool active) { - Widget::OnNativeWidgetActivationChanged(active); - if (active) - status_area_widget_delegate_->SetPaneFocusAndFocusDefault(); -} - -void StatusAreaWidget::UpdateShelfItemBackground(SkColor color) { - web_notification_tray_->UpdateShelfItemBackground(color); - system_tray_->UpdateShelfItemBackground(color); - virtual_keyboard_tray_->UpdateShelfItemBackground(color); - logout_button_tray_->UpdateShelfItemBackground(color); - ime_menu_tray_->UpdateShelfItemBackground(color); - if (palette_tray_) - palette_tray_->UpdateShelfItemBackground(color); - overview_button_tray_->UpdateShelfItemBackground(color); -} - -void StatusAreaWidget::AddSystemTray() { - system_tray_ = new SystemTray(wm_shelf_); - status_area_widget_delegate_->AddTray(system_tray_); -} - -void StatusAreaWidget::AddWebNotificationTray() { - DCHECK(system_tray_); - web_notification_tray_ = new WebNotificationTray( - wm_shelf_, WmWindow::Get(this->GetNativeWindow()), system_tray_); - status_area_widget_delegate_->AddTray(web_notification_tray_); -} - -void StatusAreaWidget::AddLogoutButtonTray() { - logout_button_tray_ = new LogoutButtonTray(wm_shelf_); - status_area_widget_delegate_->AddTray(logout_button_tray_); -} - -void StatusAreaWidget::AddPaletteTray() { - const display::Display& display = - WmWindow::Get(this->GetNativeWindow())->GetDisplayNearestWindow(); - - // Create the palette only on the internal display, where the stylus is - // available. We also create a palette on every display if requested from the - // command line. - if (display.IsInternal() || palette_utils::IsPaletteEnabledOnEveryDisplay()) { - palette_tray_ = new PaletteTray(wm_shelf_); - status_area_widget_delegate_->AddTray(palette_tray_); - } -} - -void StatusAreaWidget::AddVirtualKeyboardTray() { - virtual_keyboard_tray_ = new VirtualKeyboardTray(wm_shelf_); - status_area_widget_delegate_->AddTray(virtual_keyboard_tray_); -} - -void StatusAreaWidget::AddImeMenuTray() { - ime_menu_tray_ = new ImeMenuTray(wm_shelf_); - status_area_widget_delegate_->AddTray(ime_menu_tray_); -} - -void StatusAreaWidget::AddOverviewButtonTray() { - overview_button_tray_ = new OverviewButtonTray(wm_shelf_); - status_area_widget_delegate_->AddTray(overview_button_tray_); -} - -} // namespace ash
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h deleted file mode 100644 index dcdb5bf..0000000 --- a/ash/system/status_area_widget.h +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_STATUS_AREA_WIDGET_H_ -#define ASH_SYSTEM_STATUS_AREA_WIDGET_H_ - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "base/macros.h" -#include "ui/views/widget/widget.h" - -namespace ash { -class ImeMenuTray; -class LogoutButtonTray; -class OverviewButtonTray; -class PaletteTray; -class StatusAreaWidgetDelegate; -class SystemTray; -class VirtualKeyboardTray; -class WebNotificationTray; -class WmShelf; -class WmWindow; - -class ASH_EXPORT StatusAreaWidget : public views::Widget, - public ShelfBackgroundAnimatorObserver { - public: - StatusAreaWidget(WmWindow* status_container, WmShelf* wm_shelf); - ~StatusAreaWidget() override; - - // Creates the SystemTray, WebNotificationTray and LogoutButtonTray. - void CreateTrayViews(); - - // Destroys the system tray and web notification tray. Called before - // tearing down the windows to avoid shutdown ordering issues. - void Shutdown(); - - // Update the alignment of the widget and tray views. - void SetShelfAlignment(ShelfAlignment alignment); - - // Called by the client when the login status changes. Caches login_status - // and calls UpdateAfterLoginStatusChange for the system tray and the web - // notification tray. - void UpdateAfterLoginStatusChange(LoginStatus login_status); - - StatusAreaWidgetDelegate* status_area_widget_delegate() { - return status_area_widget_delegate_; - } - SystemTray* system_tray() { return system_tray_; } - WebNotificationTray* web_notification_tray() { - return web_notification_tray_; - } - OverviewButtonTray* overview_button_tray() { return overview_button_tray_; } - - PaletteTray* palette_tray() { return palette_tray_; } - - ImeMenuTray* ime_menu_tray() { return ime_menu_tray_; } - - WmShelf* wm_shelf() { return wm_shelf_; } - - LoginStatus login_status() const { return login_status_; } - - // Returns true if the shelf should be visible. This is used when the - // shelf is configured to auto-hide and test if the shelf should force - // the shelf to remain visible. - bool ShouldShowShelf() const; - - // True if any message bubble is shown. - bool IsMessageBubbleShown() const; - - // Notifies child trays, and the |status_area_widget_delegate_| to schedule a - // paint. - void SchedulePaint(); - - // Overridden from views::Widget: - const ui::NativeTheme* GetNativeTheme() const override; - void OnNativeWidgetActivationChanged(bool active) override; - - // ShelfBackgroundAnimatorObserver: - void UpdateShelfItemBackground(SkColor color) override; - - private: - void AddSystemTray(); - void AddWebNotificationTray(); - void AddLogoutButtonTray(); - void AddPaletteTray(); - void AddVirtualKeyboardTray(); - void AddImeMenuTray(); - void AddOverviewButtonTray(); - - // Weak pointers to View classes that are parented to StatusAreaWidget: - StatusAreaWidgetDelegate* status_area_widget_delegate_; - OverviewButtonTray* overview_button_tray_; - SystemTray* system_tray_; - WebNotificationTray* web_notification_tray_; - LogoutButtonTray* logout_button_tray_; - PaletteTray* palette_tray_; - VirtualKeyboardTray* virtual_keyboard_tray_; - ImeMenuTray* ime_menu_tray_; - LoginStatus login_status_; - - WmShelf* wm_shelf_; - - DISALLOW_COPY_AND_ASSIGN(StatusAreaWidget); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_STATUS_AREA_WIDGET_H_
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc deleted file mode 100644 index 21c942e..0000000 --- a/ash/system/status_area_widget_delegate.cc +++ /dev/null
@@ -1,199 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/status_area_widget_delegate.h" - -#include "ash/common/focus_cycler.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/tray/tray_constants.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/animation/tween.h" -#include "ui/views/accessible_pane_view.h" -#include "ui/views/border.h" -#include "ui/views/layout/grid_layout.h" - -namespace { - -constexpr int kAnimationDurationMs = 250; - -constexpr int kPaddingFromEdgeOfShelf = 3; - -class StatusAreaWidgetDelegateAnimationSettings - : public ui::ScopedLayerAnimationSettings { - public: - explicit StatusAreaWidgetDelegateAnimationSettings(ui::Layer* layer) - : ui::ScopedLayerAnimationSettings(layer->GetAnimator()) { - SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); - SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - SetTweenType(gfx::Tween::EASE_IN_OUT); - } - - ~StatusAreaWidgetDelegateAnimationSettings() override {} - - private: - DISALLOW_COPY_AND_ASSIGN(StatusAreaWidgetDelegateAnimationSettings); -}; - -} // namespace - -namespace ash { - -StatusAreaWidgetDelegate::StatusAreaWidgetDelegate() - : focus_cycler_for_testing_(nullptr), alignment_(SHELF_ALIGNMENT_BOTTOM) { - // Allow the launcher to surrender the focus to another window upon - // navigation completion by the user. - set_allow_deactivate_on_esc(true); - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); -} - -StatusAreaWidgetDelegate::~StatusAreaWidgetDelegate() {} - -void StatusAreaWidgetDelegate::SetFocusCyclerForTesting( - const FocusCycler* focus_cycler) { - focus_cycler_for_testing_ = focus_cycler; -} - -views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() { - return child_at(0); -} - -views::Widget* StatusAreaWidgetDelegate::GetWidget() { - return View::GetWidget(); -} - -const views::Widget* StatusAreaWidgetDelegate::GetWidget() const { - return View::GetWidget(); -} - -void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) { - views::Widget* target_widget = - static_cast<views::View*>(event->target())->GetWidget(); - WmWindow* target_window = WmWindow::Get(target_widget->GetNativeWindow()); - WmShelf* shelf = target_window->GetRootWindowController()->GetShelf(); - if (shelf->ProcessGestureEvent(*event)) - event->StopPropagation(); - else - views::AccessiblePaneView::OnGestureEvent(event); -} - -bool StatusAreaWidgetDelegate::CanActivate() const { - // We don't want mouse clicks to activate us, but we need to allow - // activation when the user is using the keyboard (FocusCycler). - const FocusCycler* focus_cycler = focus_cycler_for_testing_ - ? focus_cycler_for_testing_ - : WmShell::Get()->focus_cycler(); - return focus_cycler->widget_activating() == GetWidget(); -} - -void StatusAreaWidgetDelegate::DeleteDelegate() {} - -void StatusAreaWidgetDelegate::AddTray(views::View* tray) { - SetLayoutManager(NULL); // Reset layout manager before adding a child. - AddChildView(tray); - // Set the layout manager with the new list of children. - UpdateLayout(); -} - -void StatusAreaWidgetDelegate::UpdateLayout() { - // Use a grid layout so that the trays can be centered in each cell, and - // so that the widget gets laid out correctly when tray sizes change. - views::GridLayout* layout = new views::GridLayout(this); - SetLayoutManager(layout); - - // Update tray border based on layout. - bool is_child_on_edge = true; - for (int c = 0; c < child_count(); ++c) { - views::View* child = child_at(c); - if (!child->visible()) - continue; - SetBorderOnChild(child, is_child_on_edge); - is_child_on_edge = false; - } - - views::ColumnSet* columns = layout->AddColumnSet(0); - - if (IsHorizontalAlignment(alignment_)) { - for (int c = child_count() - 1; c >= 0; --c) { - views::View* child = child_at(c); - if (!child->visible()) - continue; - columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, - 0, /* resize percent */ - views::GridLayout::USE_PREF, 0, 0); - } - layout->StartRow(0, 0); - for (int c = child_count() - 1; c >= 0; --c) { - views::View* child = child_at(c); - if (child->visible()) - layout->AddView(child); - } - } else { - columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, - 0, /* resize percent */ - views::GridLayout::USE_PREF, 0, 0); - for (int c = child_count() - 1; c >= 0; --c) { - views::View* child = child_at(c); - if (!child->visible()) - continue; - layout->StartRow(0, 0); - layout->AddView(child); - } - } - - layer()->GetAnimator()->StopAnimating(); - StatusAreaWidgetDelegateAnimationSettings settings(layer()); - - Layout(); - UpdateWidgetSize(); -} - -void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) { - // Need to resize the window when trays or items are added/removed. - StatusAreaWidgetDelegateAnimationSettings settings(layer()); - UpdateWidgetSize(); -} - -void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) { - UpdateLayout(); -} - -void StatusAreaWidgetDelegate::UpdateWidgetSize() { - if (GetWidget()) - GetWidget()->SetSize(GetPreferredSize()); -} - -void StatusAreaWidgetDelegate::SetBorderOnChild(views::View* child, - bool extend_border_to_edge) { - // Tray views are laid out right-to-left or bottom-to-top. - const bool horizontal_alignment = IsHorizontalAlignment(alignment_); - const int padding = (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2; - - const int top_edge = horizontal_alignment ? padding : 0; - const int left_edge = horizontal_alignment ? 0 : padding; - const int bottom_edge = - horizontal_alignment - ? padding - : (extend_border_to_edge ? kPaddingFromEdgeOfShelf : 0); - const int right_edge = - horizontal_alignment - ? (extend_border_to_edge ? kPaddingFromEdgeOfShelf : 0) - : padding; - child->SetBorder( - views::CreateEmptyBorder(top_edge, left_edge, bottom_edge, right_edge)); - - // Layout on |child| needs to be updated based on new border value before - // displaying; otherwise |child| will be showing with old border size. - // Fix for crbug.com/623438. - child->Layout(); -} - -} // namespace ash
diff --git a/ash/system/status_area_widget_delegate.h b/ash/system/status_area_widget_delegate.h deleted file mode 100644 index c60df6a..0000000 --- a/ash/system/status_area_widget_delegate.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_STATUS_AREA_WIDGET_DELEGATE_H_ -#define ASH_SYSTEM_STATUS_AREA_WIDGET_DELEGATE_H_ - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" -#include "base/macros.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/accessible_pane_view.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { -class FocusCycler; - -// The View for the status area widget. -class ASH_EXPORT StatusAreaWidgetDelegate : public views::AccessiblePaneView, - public views::WidgetDelegate { - public: - StatusAreaWidgetDelegate(); - ~StatusAreaWidgetDelegate() override; - - // Add a tray view to the widget (e.g. system tray, web notifications). - void AddTray(views::View* tray); - - // Called whenever layout might change (e.g. alignment changed). - void UpdateLayout(); - - // Sets the focus cycler. - void SetFocusCyclerForTesting(const FocusCycler* focus_cycler); - - void set_alignment(ShelfAlignment alignment) { alignment_ = alignment; } - - // Overridden from views::AccessiblePaneView. - View* GetDefaultFocusableChild() override; - - // Overridden from views::View: - views::Widget* GetWidget() override; - const views::Widget* GetWidget() const override; - - // Overridden from ui::EventHandler: - void OnGestureEvent(ui::GestureEvent* event) override; - - // views::WidgetDelegate overrides: - bool CanActivate() const override; - void DeleteDelegate() override; - - protected: - // Overridden from views::View: - void ChildPreferredSizeChanged(views::View* child) override; - void ChildVisibilityChanged(views::View* child) override; - - private: - void UpdateWidgetSize(); - - // Sets a border on |child|. If |extend_border_to_edge| is true, then an extra - // wide border is added to extend the view's hit region to the edge of the - // screen. - void SetBorderOnChild(views::View* child, bool extend_border_to_edge); - - const FocusCycler* focus_cycler_for_testing_; - - // TODO(jamescook): Get this from WmShelf. - ShelfAlignment alignment_; - - DISALLOW_COPY_AND_ASSIGN(StatusAreaWidgetDelegate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_STATUS_AREA_WIDGET_DELEGATE_H_
diff --git a/ash/system/supervised/custodian_info_tray_observer.h b/ash/system/supervised/custodian_info_tray_observer.h deleted file mode 100644 index fa27f151..0000000 --- a/ash/system/supervised/custodian_info_tray_observer.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SUPERVISED_CUSTODIAN_INFO_TRAY_OBSERVER_H_ -#define ASH_SYSTEM_SUPERVISED_CUSTODIAN_INFO_TRAY_OBSERVER_H_ - -namespace ash { - -// Used to observe SystemTrayDelegate. -class CustodianInfoTrayObserver { - public: - // Called when information about the supervised user's custodian is changed, - // e.g. the display name. - virtual void OnCustodianInfoChanged() = 0; - - protected: - virtual ~CustodianInfoTrayObserver() {} -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SUPERVISED_CUSTODIAN_INFO_TRAY_OBSERVER_H_
diff --git a/ash/system/supervised/tray_supervised_user.cc b/ash/system/supervised/tray_supervised_user.cc deleted file mode 100644 index cd6b0a7..0000000 --- a/ash/system/supervised/tray_supervised_user.cc +++ /dev/null
@@ -1,132 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/supervised/tray_supervised_user.h" - -#include <utility> - -#include "ash/common/login_status.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/label_tray_view.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "base/callback.h" -#include "base/logging.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_delegate.h" - -using message_center::Notification; - -namespace ash { - -const char TraySupervisedUser::kNotificationId[] = - "chrome://user/locally-managed"; - -TraySupervisedUser::TraySupervisedUser(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_SUPERVISED_USER), - tray_view_(NULL), - status_(LoginStatus::NOT_LOGGED_IN), - is_user_supervised_(false) { - WmShell::Get()->system_tray_delegate()->AddCustodianInfoTrayObserver(this); -} - -TraySupervisedUser::~TraySupervisedUser() { - // We need the check as on shell destruction delegate is destroyed first. - SystemTrayDelegate* system_tray_delegate = - WmShell::Get()->system_tray_delegate(); - if (system_tray_delegate) - system_tray_delegate->RemoveCustodianInfoTrayObserver(this); -} - -void TraySupervisedUser::UpdateMessage() { - base::string16 message = - WmShell::Get()->system_tray_delegate()->GetSupervisedUserMessage(); - if (tray_view_) - tray_view_->SetMessage(message); - if (message_center::MessageCenter::Get()->FindVisibleNotificationById( - kNotificationId)) - CreateOrUpdateNotification(message); -} - -views::View* TraySupervisedUser::CreateDefaultView(LoginStatus status) { - CHECK(tray_view_ == NULL); - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (!delegate->IsUserSupervised()) - return NULL; - - tray_view_ = new LabelTrayView(this, GetSupervisedUserIconId()); - UpdateMessage(); - return tray_view_; -} - -void TraySupervisedUser::DestroyDefaultView() { - tray_view_ = NULL; -} - -void TraySupervisedUser::OnViewClicked(views::View* sender) { - // TODO(antrim): Find out what should we show in this case. -} - -void TraySupervisedUser::UpdateAfterLoginStatusChange(LoginStatus status) { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - - bool is_user_supervised = delegate->IsUserSupervised(); - if (status == status_ && is_user_supervised == is_user_supervised_) - return; - - if (is_user_supervised && !delegate->IsUserChild() && - status_ != LoginStatus::LOCKED && - !delegate->GetSupervisedUserManager().empty()) - CreateOrUpdateSupervisedWarningNotification(); - - status_ = status; - is_user_supervised_ = is_user_supervised; -} - -void TraySupervisedUser::CreateOrUpdateNotification( - const base::string16& new_message) { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - std::unique_ptr<Notification> notification( - message_center::Notification::CreateSystemNotification( - kNotificationId, base::string16() /* no title */, new_message, - bundle.GetImageNamed(GetSupervisedUserIconId()), - system_notifier::kNotifierSupervisedUser, - base::Closure() /* null callback */)); - message_center::MessageCenter::Get()->AddNotification( - std::move(notification)); -} - -void TraySupervisedUser::CreateOrUpdateSupervisedWarningNotification() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - CreateOrUpdateNotification(delegate->GetSupervisedUserMessage()); -} - -void TraySupervisedUser::OnCustodianInfoChanged() { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - std::string manager_name = delegate->GetSupervisedUserManager(); - if (!manager_name.empty()) { - if (!delegate->IsUserChild() && - !message_center::MessageCenter::Get()->FindVisibleNotificationById( - kNotificationId)) { - CreateOrUpdateSupervisedWarningNotification(); - } - UpdateMessage(); - } -} - -int TraySupervisedUser::GetSupervisedUserIconId() const { - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - - // Not intended to be used for non-supervised users. - CHECK(delegate->IsUserSupervised()); - - if (delegate->IsUserChild()) - return IDR_AURA_UBER_TRAY_CHILD_USER; - return IDR_AURA_UBER_TRAY_SUPERVISED_USER; -} - -} // namespace ash
diff --git a/ash/system/supervised/tray_supervised_user.h b/ash/system/supervised/tray_supervised_user.h deleted file mode 100644 index 2451263..0000000 --- a/ash/system/supervised/tray_supervised_user.h +++ /dev/null
@@ -1,65 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SUPERVISED_TRAY_SUPERVISED_USER_H_ -#define ASH_SYSTEM_SUPERVISED_TRAY_SUPERVISED_USER_H_ - -#include "ash/ash_export.h" -#include "ash/system/supervised/custodian_info_tray_observer.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/view_click_listener.h" -#include "base/macros.h" -#include "base/strings/string16.h" - -namespace ash { -class LabelTrayView; -class SystemTray; - -class ASH_EXPORT TraySupervisedUser : public SystemTrayItem, - public ViewClickListener, - public CustodianInfoTrayObserver { - public: - explicit TraySupervisedUser(SystemTray* system_tray); - ~TraySupervisedUser() override; - - // If message is not empty updates content of default view, otherwise hides - // tray items. - void UpdateMessage(); - - // Overridden from SystemTrayItem. - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyDefaultView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - - // Overridden from ViewClickListener. - void OnViewClicked(views::View* sender) override; - - // Overridden from CustodianInfoTrayObserver: - void OnCustodianInfoChanged() override; - - private: - friend class TraySupervisedUserTest; - - static const char kNotificationId[]; - - void CreateOrUpdateNotification(const base::string16& new_message); - - void CreateOrUpdateSupervisedWarningNotification(); - - int GetSupervisedUserIconId() const; - - LabelTrayView* tray_view_; - - // Previous login status to avoid showing notification upon unlock. - LoginStatus status_; - - // Previous user supervised state to avoid showing notification upon unlock. - bool is_user_supervised_; - - DISALLOW_COPY_AND_ASSIGN(TraySupervisedUser); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SUPERVISED_TRAY_SUPERVISED_USER_H_
diff --git a/ash/system/supervised/tray_supervised_user_unittest.cc b/ash/system/supervised/tray_supervised_user_unittest.cc deleted file mode 100644 index 2b666d3..0000000 --- a/ash/system/supervised/tray_supervised_user_unittest.cc +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/supervised/tray_supervised_user.h" - -#include "ash/common/login_status.h" -#include "ash/test/ash_test.h" -#include "ash/test/test_system_tray_delegate.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/notification.h" -#include "ui/message_center/notification_list.h" -#include "ui/message_center/notification_types.h" - -using message_center::NotificationList; - -namespace ash { - -class TraySupervisedUserTest : public AshTest { - public: - TraySupervisedUserTest() {} - ~TraySupervisedUserTest() override {} - - protected: - message_center::Notification* GetPopup(); - - private: - DISALLOW_COPY_AND_ASSIGN(TraySupervisedUserTest); -}; - -message_center::Notification* TraySupervisedUserTest::GetPopup() { - NotificationList::PopupNotifications popups = - message_center::MessageCenter::Get()->GetPopupNotifications(); - for (NotificationList::PopupNotifications::const_iterator iter = - popups.begin(); - iter != popups.end(); ++iter) { - if ((*iter)->id() == TraySupervisedUser::kNotificationId) - return *iter; - } - return NULL; -} - -class TraySupervisedUserInitialTest : public TraySupervisedUserTest { - public: - // Set the initial login status to supervised-user before AshTest::SetUp() - // constructs the system tray. - TraySupervisedUserInitialTest() - : scoped_initial_login_status_(LoginStatus::SUPERVISED) {} - ~TraySupervisedUserInitialTest() override {} - - private: - test::ScopedInitialLoginStatus scoped_initial_login_status_; - - DISALLOW_COPY_AND_ASSIGN(TraySupervisedUserInitialTest); -}; - -TEST_F(TraySupervisedUserTest, SupervisedUserHasNotification) { - test::TestSystemTrayDelegate* delegate = GetSystemTrayDelegate(); - delegate->SetLoginStatus(LoginStatus::SUPERVISED); - - message_center::Notification* notification = GetPopup(); - ASSERT_NE(static_cast<message_center::Notification*>(NULL), notification); - EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY), - notification->rich_notification_data().priority); -} - -TEST_F(TraySupervisedUserInitialTest, SupervisedUserNoCrash) { - // Initial login status is already SUPERVISED, which should create - // the notification and should not cause crashes. - message_center::Notification* notification = GetPopup(); - ASSERT_NE(static_cast<message_center::Notification*>(NULL), notification); - EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY), - notification->rich_notification_data().priority); -} - -} // namespace ash
diff --git a/ash/system/system_clock_observer.cc b/ash/system/system_clock_observer.cc deleted file mode 100644 index 6caaffa9..0000000 --- a/ash/system/system_clock_observer.cc +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/system_clock_observer.h" - -#include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "chromeos/dbus/dbus_thread_manager.h" - -namespace ash { - -SystemClockObserver::SystemClockObserver() { - chromeos::DBusThreadManager::Get()->GetSystemClockClient()->AddObserver(this); - chromeos::system::TimezoneSettings::GetInstance()->AddObserver(this); - can_set_time_ = - chromeos::DBusThreadManager::Get()->GetSystemClockClient()->CanSetTime(); -} - -SystemClockObserver::~SystemClockObserver() { - chromeos::DBusThreadManager::Get()->GetSystemClockClient()->RemoveObserver( - this); - chromeos::system::TimezoneSettings::GetInstance()->RemoveObserver(this); -} - -void SystemClockObserver::SystemClockUpdated() { - WmShell::Get()->system_tray_notifier()->NotifySystemClockTimeUpdated(); -} - -void SystemClockObserver::SystemClockCanSetTimeChanged(bool can_set_time) { - can_set_time_ = can_set_time; - WmShell::Get()->system_tray_notifier()->NotifySystemClockCanSetTimeChanged( - can_set_time_); -} - -void SystemClockObserver::TimezoneChanged(const icu::TimeZone& timezone) { - WmShell::Get()->system_tray_notifier()->NotifyRefreshClock(); -} - -} // namespace ash
diff --git a/ash/system/system_clock_observer.h b/ash/system/system_clock_observer.h deleted file mode 100644 index 5d8a866..0000000 --- a/ash/system/system_clock_observer.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ -#define ASH_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_ - -#include "base/macros.h" -#include "chromeos/dbus/system_clock_client.h" -#include "chromeos/settings/timezone_settings.h" - -namespace ash { - -class SystemClockObserver - : public chromeos::SystemClockClient::Observer, - public chromeos::system::TimezoneSettings::Observer { - public: - SystemClockObserver(); - ~SystemClockObserver() override; - - // chromeos::SystemClockClient::Observer - void SystemClockUpdated() override; - void SystemClockCanSetTimeChanged(bool can_set_time) override; - - // chromeos::system::TimezoneSettings::Observer - void TimezoneChanged(const icu::TimeZone& timezone) override; - - bool can_set_time() { return can_set_time_; } - - private: - bool can_set_time_; - - DISALLOW_COPY_AND_ASSIGN(SystemClockObserver); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_SYSTEM_CLOCK_OBSERVER_H_
diff --git a/ash/system/system_notifier.cc b/ash/system/system_notifier.cc deleted file mode 100644 index dbfd809..0000000 --- a/ash/system/system_notifier.cc +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/system_notifier.h" - -#include "base/logging.h" - -namespace ash { -namespace system_notifier { - -namespace { - -// See http://dev.chromium.org/chromium-os/chromiumos-design-docs/ -// system-notifications for the reasoning. - -// |kAlwaysShownSystemNotifierIds| is the list of system notification sources -// which can appear regardless of the situation, such like login screen or lock -// screen. -const char* kAlwaysShownSystemNotifierIds[] = { - kNotifierAccessibility, kNotifierDeprecatedAccelerator, kNotifierBattery, - kNotifierDisplay, kNotifierDisplayError, kNotifierNetworkError, - kNotifierPower, - // Note: Order doesn't matter here, so keep this in alphabetic order, don't - // just add your stuff at the end! - NULL}; - -// |kAshSystemNotifiers| is the list of normal system notification sources for -// ash events. These notifications can be hidden in some context. -const char* kAshSystemNotifiers[] = { - kNotifierBluetooth, kNotifierDisplayResolutionChange, kNotifierDisk, - kNotifierLocale, kNotifierMultiProfileFirstRun, kNotifierNetwork, - kNotifierNetworkPortalDetector, kNotifierScreenshot, kNotifierScreenCapture, - kNotifierScreenShare, kNotifierSessionLengthTimeout, - kNotifierSupervisedUser, kNotifierWebUsb, kNotifierSms, - // Note: Order doesn't matter here, so keep this in alphabetic order, don't - // just add your stuff at the end! - NULL}; - -bool MatchSystemNotifierId(const message_center::NotifierId& notifier_id, - const char* id_list[]) { - if (notifier_id.type != message_center::NotifierId::SYSTEM_COMPONENT) - return false; - - for (size_t i = 0; id_list[i] != NULL; ++i) { - if (notifier_id.id == id_list[i]) - return true; - } - return false; -} - -} // namespace - -const char kNotifierAccessibility[] = "ash.accessibility"; -const char kNotifierBattery[] = "ash.battery"; -const char kNotifierBluetooth[] = "ash.bluetooth"; -const char kNotifierDeprecatedAccelerator[] = "ash.accelerator-controller"; -const char kNotifierDisk[] = "ash.disk"; -const char kNotifierDisplay[] = "ash.display"; -const char kNotifierDisplayError[] = "ash.display.error"; -const char kNotifierDisplayResolutionChange[] = "ash.display.resolution-change"; -const char kNotifierDualRole[] = "ash.dual-role"; -const char kNotifierHats[] = "ash.hats"; -const char kNotifierLocale[] = "ash.locale"; -const char kNotifierMultiProfileFirstRun[] = "ash.multi-profile.first-run"; -const char kNotifierNetwork[] = "ash.network"; -const char kNotifierNetworkError[] = "ash.network.error"; -const char kNotifierNetworkPortalDetector[] = "ash.network.portal-detector"; -const char kNotifierPower[] = "ash.power"; -const char kNotifierQuickUnlock[] = "ash.quickunlock"; -const char kNotifierScreenshot[] = "ash.screenshot"; -const char kNotifierScreenCapture[] = "ash.screen-capture"; -const char kNotifierScreenShare[] = "ash.screen-share"; -const char kNotifierSessionLengthTimeout[] = "ash.session-length-timeout"; -const char kNotifierSms[] = "ash.sms"; -const char kNotifierSupervisedUser[] = "ash.locally-managed-user"; -const char kNotifierWebUsb[] = "ash.webusb"; - -bool ShouldAlwaysShowPopups(const message_center::NotifierId& notifier_id) { - return MatchSystemNotifierId(notifier_id, kAlwaysShownSystemNotifierIds); -} - -bool IsAshSystemNotifier(const message_center::NotifierId& notifier_id) { - return ShouldAlwaysShowPopups(notifier_id) || - MatchSystemNotifierId(notifier_id, kAshSystemNotifiers); -} - -} // namespace system_notifier -} // namespace ash
diff --git a/ash/system/system_notifier.h b/ash/system/system_notifier.h deleted file mode 100644 index f8ad65b..0000000 --- a/ash/system/system_notifier.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_SYSTEM_NOTIFIER_H_ -#define ASH_SYSTEM_SYSTEM_NOTIFIER_H_ - -#include <string> - -#include "ash/ash_export.h" -#include "ui/message_center/notifier_settings.h" - -namespace ash { -namespace system_notifier { - -// The list of ash system notifier IDs. Alphabetical order. -ASH_EXPORT extern const char kNotifierAccessibility[]; -ASH_EXPORT extern const char kNotifierBattery[]; -ASH_EXPORT extern const char kNotifierBluetooth[]; -ASH_EXPORT extern const char kNotifierDeprecatedAccelerator[]; -ASH_EXPORT extern const char kNotifierDisk[]; -ASH_EXPORT extern const char kNotifierDisplay[]; -ASH_EXPORT extern const char kNotifierDisplayResolutionChange[]; -ASH_EXPORT extern const char kNotifierDisplayError[]; -ASH_EXPORT extern const char kNotifierDualRole[]; -ASH_EXPORT extern const char kNotifierHats[]; -ASH_EXPORT extern const char kNotifierLocale[]; -ASH_EXPORT extern const char kNotifierMultiProfileFirstRun[]; -ASH_EXPORT extern const char kNotifierNetwork[]; -ASH_EXPORT extern const char kNotifierNetworkError[]; -ASH_EXPORT extern const char kNotifierNetworkPortalDetector[]; -ASH_EXPORT extern const char kNotifierPower[]; -ASH_EXPORT extern const char kNotifierQuickUnlock[]; -ASH_EXPORT extern const char kNotifierScreenshot[]; -ASH_EXPORT extern const char kNotifierScreenCapture[]; -ASH_EXPORT extern const char kNotifierScreenShare[]; -ASH_EXPORT extern const char kNotifierSessionLengthTimeout[]; -ASH_EXPORT extern const char kNotifierSms[]; -ASH_EXPORT extern const char kNotifierSupervisedUser[]; -ASH_EXPORT extern const char kNotifierWebUsb[]; - -// Returns true if notifications from |notifier_id| should always appear as -// popups. "Always appear" means the popups should appear even in login screen, -// lock screen, or fullscreen state. -ASH_EXPORT bool ShouldAlwaysShowPopups( - const message_center::NotifierId& notifier_id); - -// Returns true if |notifier_id| is the system notifier from Ash. -ASH_EXPORT bool IsAshSystemNotifier( - const message_center::NotifierId& notifier_id); - -} // namespace system_notifier -} // namespace ash - -#endif // ASH_SYSTEM_SYSTEM_NOTIFIER_H_
diff --git a/ash/system/tiles/tiles_default_view.cc b/ash/system/tiles/tiles_default_view.cc deleted file mode 100644 index d12e5ccf..0000000 --- a/ash/system/tiles/tiles_default_view.cc +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tiles/tiles_default_view.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/shutdown_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/wm/lock_state_controller.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/session_manager_client.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/custom_button.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" - -namespace { - -// The ISO-639 code for the Hebrew locale. The help icon asset is a '?' which is -// not mirrored in this locale. -const char kHebrewLocale[] = "he"; - -} // namespace - -namespace ash { - -TilesDefaultView::TilesDefaultView(SystemTrayItem* owner, LoginStatus login) - : owner_(owner), - login_(login), - settings_button_(nullptr), - help_button_(nullptr), - lock_button_(nullptr), - power_button_(nullptr) {} - -TilesDefaultView::~TilesDefaultView() {} - -void TilesDefaultView::Init() { - WmShell* shell = WmShell::Get(); - views::BoxLayout* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 4, 0, 0); - box_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); - box_layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - SetLayoutManager(box_layout); - - // Show the buttons in this row as disabled if the user is at the login - // screen, lock screen, or in a secondary account flow. The exception is - // |power_button_| which is always shown as enabled. - const bool disable_buttons = !TrayPopupUtils::CanOpenWebUISettings(login_); - - settings_button_ = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, - IDS_ASH_STATUS_TRAY_SETTINGS); - if (disable_buttons || !shell->system_tray_delegate()->ShouldShowSettings()) - settings_button_->SetEnabled(false); - AddChildView(settings_button_); - AddChildView(TrayPopupUtils::CreateVerticalSeparator()); - - help_button_ = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); - if (base::i18n::IsRTL() && - base::i18n::GetConfiguredLocale() == kHebrewLocale) { - // The asset for the help button is a question mark '?'. Normally this asset - // is flipped in RTL locales, however Hebrew uses the LTR '?'. So the - // flipping must be disabled. (crbug.com/475237) - help_button_->EnableCanvasFlippingForRTLUI(false); - } - if (disable_buttons) - help_button_->SetEnabled(false); - AddChildView(help_button_); - AddChildView(TrayPopupUtils::CreateVerticalSeparator()); - - lock_button_ = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - kSystemMenuLockIcon, IDS_ASH_STATUS_TRAY_LOCK); - if (disable_buttons || !shell->GetSessionStateDelegate()->CanLockScreen()) - lock_button_->SetEnabled(false); - - AddChildView(lock_button_); - AddChildView(TrayPopupUtils::CreateVerticalSeparator()); - - power_button_ = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - kSystemMenuPowerIcon, IDS_ASH_STATUS_TRAY_SHUTDOWN); - AddChildView(power_button_); - // This object is recreated every time the menu opens. Don't bother updating - // the tooltip if the shutdown policy changes while the menu is open. - bool reboot = WmShell::Get()->shutdown_controller()->reboot_on_shutdown(); - power_button_->SetTooltipText(l10n_util::GetStringUTF16( - reboot ? IDS_ASH_STATUS_TRAY_REBOOT : IDS_ASH_STATUS_TRAY_SHUTDOWN)); -} - -void TilesDefaultView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK(sender); - WmShell* shell = WmShell::Get(); - if (sender == settings_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_SETTINGS); - shell->system_tray_controller()->ShowSettings(); - } else if (sender == help_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_HELP); - shell->system_tray_controller()->ShowHelp(); - } else if (sender == lock_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_LOCK_SCREEN); - chromeos::DBusThreadManager::Get() - ->GetSessionManagerClient() - ->RequestLockScreen(); - } else if (sender == power_button_) { - shell->RecordUserMetricsAction(UMA_TRAY_SHUT_DOWN); - Shell::GetInstance()->lock_state_controller()->RequestShutdown(); - } - - owner_->system_tray()->CloseSystemBubble(); -} - -views::View* TilesDefaultView::GetHelpButtonView() const { - return help_button_; -} - -const views::CustomButton* TilesDefaultView::GetShutdownButtonViewForTest() - const { - return power_button_; -} - -} // namespace ash
diff --git a/ash/system/tiles/tiles_default_view.h b/ash/system/tiles/tiles_default_view.h deleted file mode 100644 index d719b623..0000000 --- a/ash/system/tiles/tiles_default_view.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TILES_TILES_DEFAULT_VIEW_H_ -#define ASH_SYSTEM_TILES_TILES_DEFAULT_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "base/macros.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" - -namespace views { -class CustomButton; -} - -namespace ash { -class SystemTrayItem; - -// The container view for the tiles in the bottom row of the system menu -// (settings, help, lock, and power). -class ASH_EXPORT TilesDefaultView : public views::View, - public views::ButtonListener { - public: - TilesDefaultView(SystemTrayItem* owner, LoginStatus login); - ~TilesDefaultView() override; - - // Sets the layout manager and child views of |this|. - // TODO(tdanderson|bruthig): Consider moving the layout manager - // setup code to a location which can be shared by other system menu rows. - void Init(); - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // Accessor needed to obtain the help button view for the first-run flow. - views::View* GetHelpButtonView() const; - - const views::CustomButton* GetShutdownButtonViewForTest() const; - - private: - friend class TrayTilesTest; - - SystemTrayItem* owner_; - LoginStatus login_; - - // Pointers to the child buttons of |this|. Note that some buttons may not - // exist (depending on the user's current login status, for instance), in - // which case the corresponding pointer will be null. - views::CustomButton* settings_button_; - views::CustomButton* help_button_; - views::CustomButton* lock_button_; - views::CustomButton* power_button_; - - DISALLOW_COPY_AND_ASSIGN(TilesDefaultView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TILES_TILES_DEFAULT_VIEW_H_
diff --git a/ash/system/tiles/tray_tiles.cc b/ash/system/tiles/tray_tiles.cc deleted file mode 100644 index ea1b5cc..0000000 --- a/ash/system/tiles/tray_tiles.cc +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tiles/tray_tiles.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/system/tiles/tiles_default_view.h" - -namespace ash { - -TrayTiles::TrayTiles(SystemTray* system_tray) - : SystemTrayItem(system_tray, UMA_NOT_RECORDED), default_view_(nullptr) {} - -TrayTiles::~TrayTiles() {} - -views::View* TrayTiles::GetHelpButtonView() const { - if (!default_view_) - return nullptr; - return default_view_->GetHelpButtonView(); -} - -TilesDefaultView* TrayTiles::GetDefaultViewForTesting() const { - return default_view_; -} - -views::View* TrayTiles::CreateDefaultViewForTesting(LoginStatus status) { - return CreateDefaultView(status); -} - -views::View* TrayTiles::CreateDefaultView(LoginStatus status) { - CHECK(default_view_ == nullptr); - default_view_ = new TilesDefaultView(this, status); - default_view_->Init(); - return default_view_; -} - -void TrayTiles::DestroyDefaultView() { - default_view_ = nullptr; -} - -} // namespace ash
diff --git a/ash/system/tiles/tray_tiles.h b/ash/system/tiles/tray_tiles.h deleted file mode 100644 index a1c1f629..0000000 --- a/ash/system/tiles/tray_tiles.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TILES_TRAY_TILES_H_ -#define ASH_SYSTEM_TILES_TRAY_TILES_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" - -namespace ash { -class SystemTray; -class TilesDefaultView; - -// The tray item for the 'tiles' at the bottom of the system menu. Each tile is -// an image button which does not reqire explanatory text, and thus does not -// require its own dedicated row in the system menu. -class ASH_EXPORT TrayTiles : public SystemTrayItem { - public: - explicit TrayTiles(SystemTray* system_tray); - ~TrayTiles() override; - - // Accessor needed to obtain the help button view for the first-run flow. - views::View* GetHelpButtonView() const; - - TilesDefaultView* GetDefaultViewForTesting() const; - views::View* CreateDefaultViewForTesting(LoginStatus status); - - private: - friend class TrayTilesTest; - - // SystemTrayItem: - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyDefaultView() override; - - TilesDefaultView* default_view_; - - DISALLOW_COPY_AND_ASSIGN(TrayTiles); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TILES_TRAY_TILES_H_
diff --git a/ash/system/tiles/tray_tiles_unittest.cc b/ash/system/tiles/tray_tiles_unittest.cc deleted file mode 100644 index b26b4ec..0000000 --- a/ash/system/tiles/tray_tiles_unittest.cc +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tiles/tray_tiles.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/system/tiles/tiles_default_view.h" -#include "ash/test/ash_test_base.h" -#include "ui/views/controls/button/custom_button.h" -#include "ui/views/view.h" - -namespace ash { - -class TrayTilesTest : public test::AshTestBase { - public: - TrayTilesTest() {} - ~TrayTilesTest() override {} - - void SetUp() override { - test::AshTestBase::SetUp(); - tray_tiles_.reset(new TrayTiles(GetPrimarySystemTray())); - } - - void TearDown() override { - tray_tiles_.reset(); - test::AshTestBase::TearDown(); - } - - views::CustomButton* GetSettingsButton() { - return tray_tiles()->default_view_->settings_button_; - } - - views::CustomButton* GetHelpButton() { - return tray_tiles()->default_view_->help_button_; - } - - views::CustomButton* GetLockButton() { - return tray_tiles()->default_view_->lock_button_; - } - - views::CustomButton* GetPowerButton() { - return tray_tiles()->default_view_->power_button_; - } - - TrayTiles* tray_tiles() { return tray_tiles_.get(); } - - private: - std::unique_ptr<TrayTiles> tray_tiles_; - - DISALLOW_COPY_AND_ASSIGN(TrayTilesTest); -}; - -TEST_F(TrayTilesTest, ButtonStatesWithAddingUser) { - SetUserAddingScreenRunning(true); - std::unique_ptr<views::View> default_view( - tray_tiles()->CreateDefaultViewForTesting(LoginStatus::USER)); - EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); -} - -TEST_F(TrayTilesTest, ButtonStatesWithLoginStatusNotLoggedIn) { - std::unique_ptr<views::View> default_view( - tray_tiles()->CreateDefaultViewForTesting(LoginStatus::NOT_LOGGED_IN)); - EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); -} - -TEST_F(TrayTilesTest, ButtonStatesWithLoginStatusLocked) { - std::unique_ptr<views::View> default_view( - tray_tiles()->CreateDefaultViewForTesting(LoginStatus::LOCKED)); - EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_DISABLED); - EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); -} - -TEST_F(TrayTilesTest, ButtonStatesWithLoginStatusUser) { - std::unique_ptr<views::View> default_view( - tray_tiles()->CreateDefaultViewForTesting(LoginStatus::USER)); - EXPECT_EQ(GetSettingsButton()->state(), views::Button::STATE_NORMAL); - EXPECT_EQ(GetHelpButton()->state(), views::Button::STATE_NORMAL); - EXPECT_EQ(GetLockButton()->state(), views::Button::STATE_NORMAL); - EXPECT_EQ(GetPowerButton()->state(), views::Button::STATE_NORMAL); -} - -} // namespace ash
diff --git a/ash/system/toast/toast_data.cc b/ash/system/toast/toast_data.cc deleted file mode 100644 index b80f1c7..0000000 --- a/ash/system/toast/toast_data.cc +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/toast/toast_data.h" - -#include <utility> - -namespace ash { - -ToastData::ToastData(std::string id, - const base::string16& text, - int32_t duration_ms, - const base::Optional<base::string16>& dismiss_text) - : id(std::move(id)), - text(text), - duration_ms(duration_ms), - dismiss_text(dismiss_text) {} - -ToastData::ToastData(const ToastData& other) = default; - -ToastData::~ToastData() = default; - -} // namespace ash
diff --git a/ash/system/toast/toast_data.h b/ash/system/toast/toast_data.h deleted file mode 100644 index f4ac1abf..0000000 --- a/ash/system/toast/toast_data.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TOAST_TOAST_DATA_H_ -#define ASH_SYSTEM_TOAST_TOAST_DATA_H_ - -#include <string> - -#include "ash/ash_export.h" -#include "base/optional.h" -#include "base/strings/string16.h" - -namespace ash { - -struct ASH_EXPORT ToastData { - // "|duration_ms| == -1" means the toast view should be displayed until the - // dismiss button is clicked. - static const int32_t kInfiniteDuration = -1; - - ToastData(std::string id, - const base::string16& text, - int32_t duration_ms, - const base::Optional<base::string16>& dismiss_text); - ToastData(const ToastData& other); - ~ToastData(); - - std::string id; - base::string16 text; - int32_t duration_ms; - base::Optional<base::string16> dismiss_text; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TOAST_TOAST_DATA_H_
diff --git a/ash/system/toast/toast_manager.cc b/ash/system/toast/toast_manager.cc deleted file mode 100644 index 88ac380..0000000 --- a/ash/system/toast/toast_manager.cc +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/toast/toast_manager.h" - -#include <algorithm> - -#include "base/bind.h" -#include "base/location.h" -#include "base/threading/thread_task_runner_handle.h" - -namespace ash { - -namespace { - -// Minimum duration for a toast to be visible (in millisecond). -const int32_t kMinimumDurationMs = 200; - -} // anonymous namespace - -ToastManager::ToastManager() : weak_ptr_factory_(this) {} - -ToastManager::~ToastManager() {} - -void ToastManager::Show(const ToastData& data) { - const std::string& id = data.id; - DCHECK(!id.empty()); - - if (current_toast_id_ == id) { - // TODO(yoshiki): Replaces the visible toast. - return; - } - - auto existing_toast = - std::find_if(queue_.begin(), queue_.end(), - [&id](const ToastData& data) { return data.id == id; }); - - if (existing_toast == queue_.end()) { - queue_.emplace_back(data); - } else { - *existing_toast = data; - } - - if (queue_.size() == 1 && overlay_ == nullptr) - ShowLatest(); -} - -void ToastManager::Cancel(const std::string& id) { - if (id == current_toast_id_) { - overlay_->Show(false); - return; - } - - auto cancelled_toast = - std::find_if(queue_.begin(), queue_.end(), - [&id](const ToastData& data) { return data.id == id; }); - if (cancelled_toast != queue_.end()) - queue_.erase(cancelled_toast); -} - -void ToastManager::OnClosed() { - overlay_.reset(); - current_toast_id_.clear(); - - // Show the next toast if available. - if (!queue_.empty()) - ShowLatest(); -} - -void ToastManager::ShowLatest() { - DCHECK(!overlay_); - - const ToastData data = std::move(queue_.front()); - queue_.pop_front(); - - current_toast_id_ = data.id; - serial_++; - - overlay_.reset(new ToastOverlay(this, data.text, data.dismiss_text)); - overlay_->Show(true); - - if (data.duration_ms != ToastData::kInfiniteDuration) { - int32_t duration_ms = std::max(data.duration_ms, kMinimumDurationMs); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&ToastManager::OnDurationPassed, - weak_ptr_factory_.GetWeakPtr(), serial_), - base::TimeDelta::FromMilliseconds(duration_ms)); - } -} - -void ToastManager::OnDurationPassed(int toast_number) { - if (overlay_ && serial_ == toast_number) - overlay_->Show(false); -} - -} // namespace ash
diff --git a/ash/system/toast/toast_manager.h b/ash/system/toast/toast_manager.h deleted file mode 100644 index 02cec1d..0000000 --- a/ash/system/toast/toast_manager.h +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TOAST_TOAST_MANAGER_H_ -#define ASH_SYSTEM_TOAST_TOAST_MANAGER_H_ - -#include <deque> -#include <memory> -#include <string> - -#include "ash/ash_export.h" -#include "ash/system/toast/toast_data.h" -#include "ash/system/toast/toast_overlay.h" -#include "base/memory/weak_ptr.h" - -namespace ash { - -// Class managing toast requests. -class ASH_EXPORT ToastManager : public ToastOverlay::Delegate { - public: - ToastManager(); - ~ToastManager() override; - - // Show a toast. If there are queued toasts, succeeding toasts are queued as - // well, and are shown one by one. - void Show(const ToastData& data); - - void Cancel(const std::string& id); - - // ToastOverlay::Delegate overrides: - void OnClosed() override; - - private: - friend class ToastManagerTest; - - void ShowLatest(); - void OnDurationPassed(int toast_number); - - ToastOverlay* GetCurrentOverlayForTesting() { return overlay_.get(); } - int serial_for_testing() const { return serial_; } - void ResetSerialForTesting() { serial_ = 0; } - - // ID of the toast which is currently shown. Empty if no toast is visible. - std::string current_toast_id_; - - int serial_ = 0; - std::deque<ToastData> queue_; - std::unique_ptr<ToastOverlay> overlay_; - - base::WeakPtrFactory<ToastManager> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ToastManager); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TOAST_TOAST_MANAGER_H_
diff --git a/ash/system/toast/toast_manager_unittest.cc b/ash/system/toast/toast_manager_unittest.cc index 1518d86..5fef6c2 100644 --- a/ash/system/toast/toast_manager_unittest.cc +++ b/ash/system/toast/toast_manager_unittest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/toast/toast_manager.h" +#include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/toast/toast_manager.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/wm_screen_util.h" #include "base/run_loop.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h"
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc deleted file mode 100644 index ab1885ae..0000000 --- a/ash/system/toast/toast_overlay.cc +++ /dev/null
@@ -1,310 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/toast/toast_overlay.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/font_list.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/wm/core/window_animations.h" - -namespace ash { - -namespace { - -// Offset of the overlay from the edge of the work area. -const int kOffset = 5; - -// Font style used for modifier key labels. -const ui::ResourceBundle::FontStyle kTextFontStyle = - ui::ResourceBundle::MediumFont; - -// Duration of slide animation when overlay is shown or hidden. -const int kSlideAnimationDurationMs = 100; - -// Colors for the dismiss button. -const SkColor kButtonBackgroundColor = SkColorSetARGB(0xFF, 0x32, 0x32, 0x32); -const SkColor kButtonTextColor = SkColorSetARGB(0xFF, 0x7B, 0xAA, 0xF7); - -// These values are in DIP. -const int kToastHorizontalSpacing = 16; -const int kToastVerticalSpacing = 16; -const int kToastMaximumWidth = 568; -const int kToastMinimumWidth = 288; - -// Returns the work area bounds for the root window where new windows are added -// (including new toasts). -gfx::Rect GetUserWorkAreaBounds() { - return WmShelf::ForWindow(WmShell::Get()->GetRootWindowForNewWindows()) - ->GetUserWorkAreaBounds(); -} - -} // anonymous namespace - -/////////////////////////////////////////////////////////////////////////////// -// ToastOverlayLabel -class ToastOverlayLabel : public views::Label { - public: - explicit ToastOverlayLabel(const base::string16& label); - ~ToastOverlayLabel() override; - - private: - DISALLOW_COPY_AND_ASSIGN(ToastOverlayLabel); -}; - -ToastOverlayLabel::ToastOverlayLabel(const base::string16& label) { - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); - - SetText(label); - SetHorizontalAlignment(gfx::ALIGN_LEFT); - SetFontList(rb->GetFontList(kTextFontStyle)); - SetAutoColorReadabilityEnabled(false); - SetMultiLine(true); - SetEnabledColor(SK_ColorWHITE); - SetDisabledColor(SK_ColorWHITE); - SetSubpixelRenderingEnabled(false); - - int verticalSpacing = - kToastVerticalSpacing - (GetPreferredSize().height() - GetBaseline()); - SetBorder(views::CreateEmptyBorder(verticalSpacing, kToastHorizontalSpacing, - verticalSpacing, kToastHorizontalSpacing)); -} - -ToastOverlayLabel::~ToastOverlayLabel() {} - -/////////////////////////////////////////////////////////////////////////////// -// ToastOverlayButton -class ToastOverlayButton : public views::LabelButton { - public: - explicit ToastOverlayButton(views::ButtonListener* listener, - const base::string16& label); - ~ToastOverlayButton() override {} - - private: - friend class ToastOverlay; // for ToastOverlay::ClickDismissButtonForTesting. - - DISALLOW_COPY_AND_ASSIGN(ToastOverlayButton); -}; - -ToastOverlayButton::ToastOverlayButton(views::ButtonListener* listener, - const base::string16& text) - : views::LabelButton(listener, text) { - SetInkDropMode(InkDropMode::ON); - set_has_ink_drop_action_on_click(true); - set_ink_drop_base_color(SK_ColorWHITE); - - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); - - SetEnabledTextColors(kButtonTextColor); - SetFontList(rb->GetFontList(kTextFontStyle)); - - // Treat the space below the baseline as a margin. - int verticalSpacing = kToastVerticalSpacing - - (GetPreferredSize().height() - label()->GetBaseline()); - SetBorder(views::CreateEmptyBorder(verticalSpacing, kToastHorizontalSpacing, - verticalSpacing, kToastHorizontalSpacing)); -} - -/////////////////////////////////////////////////////////////////////////////// -// ToastOverlayView -class ToastOverlayView : public views::View, public views::ButtonListener { - public: - // This object is not owned by the views hierarchy or by the widget. - ToastOverlayView(ToastOverlay* overlay, - const base::string16& text, - const base::Optional<base::string16>& dismiss_text); - ~ToastOverlayView() override; - - // views::View overrides: - void OnPaint(gfx::Canvas* canvas) override; - - ToastOverlayButton* button() { return button_; } - - private: - // views::View overrides: - gfx::Size GetMaximumSize() const override; - gfx::Size GetMinimumSize() const override; - - // views::ButtonListener overrides: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - ToastOverlay* overlay_ = nullptr; // weak - ToastOverlayButton* button_ = nullptr; // weak - - DISALLOW_COPY_AND_ASSIGN(ToastOverlayView); -}; - -ToastOverlayView::ToastOverlayView( - ToastOverlay* overlay, - const base::string16& text, - const base::Optional<base::string16>& dismiss_text) - : overlay_(overlay) { - auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - SetLayoutManager(layout); - - if (dismiss_text.has_value()) { - button_ = new ToastOverlayButton( - this, dismiss_text.value().empty() - ? l10n_util::GetStringUTF16(IDS_ASH_TOAST_DISMISS_BUTTON) - : dismiss_text.value()); - } - - ToastOverlayLabel* label = new ToastOverlayLabel(text); - AddChildView(label); - layout->SetFlexForView(label, 1); - - if (button_) { - label->SetMaximumWidth( - GetMaximumSize().width() - button_->GetPreferredSize().width() - - kToastHorizontalSpacing * 2 - kToastHorizontalSpacing * 2); - AddChildView(button_); - } -} - -ToastOverlayView::~ToastOverlayView() {} - -void ToastOverlayView::OnPaint(gfx::Canvas* canvas) { - cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setColor(kButtonBackgroundColor); - canvas->DrawRoundRect(GetLocalBounds(), 2, flags); - views::View::OnPaint(canvas); -} - -gfx::Size ToastOverlayView::GetMinimumSize() const { - return gfx::Size(kToastMinimumWidth, 0); -} - -gfx::Size ToastOverlayView::GetMaximumSize() const { - gfx::Rect work_area_bounds = GetUserWorkAreaBounds(); - return gfx::Size(kToastMaximumWidth, work_area_bounds.height() - kOffset * 2); -} - -void ToastOverlayView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - DCHECK_EQ(button_, sender); - overlay_->Show(false); -} - -/////////////////////////////////////////////////////////////////////////////// -// ToastOverlay -ToastOverlay::ToastOverlay(Delegate* delegate, - const base::string16& text, - base::Optional<base::string16> dismiss_text) - : delegate_(delegate), - text_(text), - dismiss_text_(dismiss_text), - overlay_widget_(new views::Widget), - overlay_view_(new ToastOverlayView(this, text, dismiss_text)), - widget_size_(overlay_view_->GetPreferredSize()) { - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_POPUP; - params.name = "ToastOverlay"; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.accept_events = true; - params.keep_on_top = true; - params.remove_standard_frame = true; - params.bounds = CalculateOverlayBounds(); - // Show toasts above the app list and below the lock screen. - WmShell::Get() - ->GetRootWindowForNewWindows() - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - overlay_widget_.get(), kShellWindowId_SystemModalContainer, ¶ms); - overlay_widget_->Init(params); - overlay_widget_->SetVisibilityChangedAnimationsEnabled(true); - overlay_widget_->SetContentsView(overlay_view_.get()); - overlay_widget_->SetBounds(CalculateOverlayBounds()); - - WmWindow* overlay_window = WmWindow::Get(overlay_widget_->GetNativeWindow()); - overlay_window->SetVisibilityAnimationType( - ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); - overlay_window->SetVisibilityAnimationDuration( - base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs)); -} - -ToastOverlay::~ToastOverlay() { - overlay_widget_->Close(); -} - -void ToastOverlay::Show(bool visible) { - if (overlay_widget_->GetLayer()->GetTargetVisibility() == visible) - return; - - ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator(); - DCHECK(animator); - if (animator->is_animating()) { - // Showing during hiding animation doesn't happen since, ToastOverlay should - // be one-time-use and not be reused. - DCHECK(!visible); - - return; - } - - base::TimeDelta original_duration = animator->GetTransitionDuration(); - ui::ScopedLayerAnimationSettings animation_settings(animator); - // ScopedLayerAnimationSettings ctor chanes the transition duration, so change - // back it to the original value (should be zero). - animation_settings.SetTransitionDuration(original_duration); - - animation_settings.AddObserver(this); - - if (visible) { - overlay_widget_->Show(); - - // Notify accessibility about the overlay. - overlay_view_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, false); - } else { - overlay_widget_->Hide(); - } -} - -gfx::Rect ToastOverlay::CalculateOverlayBounds() { - gfx::Rect bounds = GetUserWorkAreaBounds(); - int target_y = bounds.bottom() - widget_size_.height() - kOffset; - bounds.ClampToCenteredSize(widget_size_); - bounds.set_y(target_y); - return bounds; -} - -void ToastOverlay::OnImplicitAnimationsScheduled() {} - -void ToastOverlay::OnImplicitAnimationsCompleted() { - if (!overlay_widget_->GetLayer()->GetTargetVisibility()) - delegate_->OnClosed(); -} - -views::Widget* ToastOverlay::widget_for_testing() { - return overlay_widget_.get(); -} - -ToastOverlayButton* ToastOverlay::dismiss_button_for_testing() { - return overlay_view_->button(); -} - -void ToastOverlay::ClickDismissButtonForTesting(const ui::Event& event) { - DCHECK(overlay_view_->button()); - overlay_view_->button()->NotifyClick(event); -} - -} // namespace ash
diff --git a/ash/system/toast/toast_overlay.h b/ash/system/toast/toast_overlay.h deleted file mode 100644 index 034eb880..0000000 --- a/ash/system/toast/toast_overlay.h +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TOAST_TOAST_OVERLAY_H_ -#define ASH_SYSTEM_TOAST_TOAST_OVERLAY_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/optional.h" -#include "base/strings/string16.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/events/event.h" -#include "ui/events/event_constants.h" -#include "ui/gfx/geometry/size.h" - -namespace gfx { -class Rect; -} - -namespace views { -class Widget; -} - -namespace ash { - -class ToastManagerTest; -class ToastOverlayView; -class ToastOverlayButton; - -class ASH_EXPORT ToastOverlay : public ui::ImplicitAnimationObserver { - public: - class ASH_EXPORT Delegate { - public: - virtual ~Delegate() {} - virtual void OnClosed() = 0; - }; - - // Creates the Toast overlay UI. |text| is the message to be shown, and - // |dismiss_text| is the message for the button to dismiss the toast message. - // If |dismiss_text| is null, no dismiss button will be shown. If - // |dismiss_text| has a value but the string is empty, the default text is - // used. - ToastOverlay(Delegate* delegate, - const base::string16& text, - base::Optional<base::string16> dismiss_text); - ~ToastOverlay() override; - - // Shows or hides the overlay. - void Show(bool visible); - - private: - friend class ToastManagerTest; - - // Returns the current bounds of the overlay, which is based on visibility. - gfx::Rect CalculateOverlayBounds(); - - // ui::ImplicitAnimationObserver: - void OnImplicitAnimationsScheduled() override; - void OnImplicitAnimationsCompleted() override; - - views::Widget* widget_for_testing(); - ToastOverlayButton* dismiss_button_for_testing(); - void ClickDismissButtonForTesting(const ui::Event& event); - - Delegate* const delegate_; - const base::string16 text_; - const base::Optional<base::string16> dismiss_text_; - std::unique_ptr<views::Widget> overlay_widget_; - std::unique_ptr<ToastOverlayView> overlay_view_; - gfx::Size widget_size_; - - DISALLOW_COPY_AND_ASSIGN(ToastOverlay); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TOAST_TOAST_OVERLAY_H_
diff --git a/ash/system/tray/actionable_view.cc b/ash/system/tray/actionable_view.cc deleted file mode 100644 index 7914f5a..0000000 --- a/ash/system/tray/actionable_view.cc +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/actionable_view.h" - -#include "ash/common/ash_constants.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/events/keycodes/keyboard_codes.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect_f.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_highlight.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_mask.h" - -namespace ash { - -// static -const char ActionableView::kViewClassName[] = "tray/ActionableView"; - -ActionableView::ActionableView(SystemTrayItem* owner, - TrayPopupInkDropStyle ink_drop_style) - : views::CustomButton(this), - destroyed_(nullptr), - owner_(owner), - ink_drop_style_(ink_drop_style) { - SetFocusBehavior(FocusBehavior::ALWAYS); - set_ink_drop_base_color(kTrayPopupInkDropBaseColor); - set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); - set_has_ink_drop_action_on_click(false); - set_notify_enter_exit_on_child(true); -} - -ActionableView::~ActionableView() { - if (destroyed_) - *destroyed_ = true; -} - -void ActionableView::OnPaintFocus(gfx::Canvas* canvas) { - gfx::RectF rect(GetLocalBounds()); - canvas->DrawSolidFocusRect(rect, kFocusBorderColor, kFocusBorderThickness); -} - -void ActionableView::HandlePerformActionResult(bool action_performed, - const ui::Event& event) { - AnimateInkDrop(action_performed ? views::InkDropState::ACTION_TRIGGERED - : views::InkDropState::HIDDEN, - ui::LocatedEvent::FromIfValid(&event)); -} - -const char* ActionableView::GetClassName() const { - return kViewClassName; -} - -bool ActionableView::OnKeyPressed(const ui::KeyEvent& event) { - if (state() != STATE_DISABLED && event.key_code() == ui::VKEY_SPACE) { - NotifyClick(event); - return true; - } - return CustomButton::OnKeyPressed(event); -} - -void ActionableView::SetAccessibleName(const base::string16& name) { - accessible_name_ = name; -} - -void ActionableView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_BUTTON; - node_data->SetName(accessible_name_); -} - -void ActionableView::OnPaint(gfx::Canvas* canvas) { - CustomButton::OnPaint(canvas); - if (HasFocus()) - OnPaintFocus(canvas); -} - -void ActionableView::OnFocus() { - CustomButton::OnFocus(); - // We render differently when focused. - SchedulePaint(); -} - -void ActionableView::OnBlur() { - CustomButton::OnBlur(); - // We render differently when focused. - SchedulePaint(); -} - -std::unique_ptr<views::InkDrop> ActionableView::CreateInkDrop() { - return TrayPopupUtils::CreateInkDrop(ink_drop_style_, this); -} - -std::unique_ptr<views::InkDropRipple> ActionableView::CreateInkDropRipple() - const { - return TrayPopupUtils::CreateInkDropRipple( - ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent()); -} - -std::unique_ptr<views::InkDropHighlight> -ActionableView::CreateInkDropHighlight() const { - return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this); -} - -std::unique_ptr<views::InkDropMask> ActionableView::CreateInkDropMask() const { - return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this); -} - -void ActionableView::CloseSystemBubble() { - DCHECK(owner_); - owner_->system_tray()->CloseSystemBubble(); -} - -void ActionableView::ButtonPressed(Button* sender, const ui::Event& event) { - bool destroyed = false; - destroyed_ = &destroyed; - const bool action_performed = PerformAction(event); - if (destroyed) - return; - destroyed_ = nullptr; - - HandlePerformActionResult(action_performed, event); -} - -ButtonListenerActionableView::ButtonListenerActionableView( - SystemTrayItem* owner, - TrayPopupInkDropStyle ink_drop_style, - views::ButtonListener* listener) - : ActionableView(owner, ink_drop_style), listener_(listener) {} - -bool ButtonListenerActionableView::PerformAction(const ui::Event& event) { - listener_->ButtonPressed(this, event); - return true; -} - -} // namespace ash
diff --git a/ash/system/tray/actionable_view.h b/ash/system/tray/actionable_view.h deleted file mode 100644 index 95d43b4..0000000 --- a/ash/system/tray/actionable_view.h +++ /dev/null
@@ -1,115 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_ACTIONABLE_VIEW_H_ -#define ASH_SYSTEM_TRAY_ACTIONABLE_VIEW_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/tray_popup_ink_drop_style.h" -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/controls/button/custom_button.h" - -namespace ash { -class SystemTrayItem; - -// A focusable view that performs an action when user clicks on it, or presses -// enter or space when focused. Note that the action is triggered on mouse-up, -// instead of on mouse-down. So if user presses the mouse on the view, then -// moves the mouse out of the view and then releases, then the action will not -// be performed. -// Exported for SystemTray. -// -// TODO(bruthig): Consider removing ActionableView and make clients use -// CustomButtons instead. (See crbug.com/614453) -class ASH_EXPORT ActionableView : public views::ButtonListener, - public views::CustomButton { - public: - static const char kViewClassName[]; - - // The owner is used to close the system tray bubble. Can be null if - // the action will not close the bubble. - ActionableView(SystemTrayItem* owner, TrayPopupInkDropStyle ink_drop_style); - - ~ActionableView() override; - - void SetAccessibleName(const base::string16& name); - const base::string16& accessible_name() const { return accessible_name_; } - - // Closes the system tray bubble. The |owner_| must not be nullptr. - void CloseSystemBubble(); - - protected: - SystemTrayItem* owner() { return owner_; } - - // Draws focus rectangle on the canvas. - // Default implementation draws the focus rectangle with certain inset and - // color. Subclasses can override to change the default settings. - virtual void OnPaintFocus(gfx::Canvas* canvas); - - // Performs an action when user clicks on the view (on mouse-press event), or - // presses a key when this view is in focus. Returns true if the event has - // been handled and an action was performed. Returns false otherwise. - virtual bool PerformAction(const ui::Event& event) = 0; - - // Called after PerformAction() to act upon its result, including showing - // appropriate ink drop ripple. This will not get called if the view is - // destroyed during PerformAction(). Default implementation shows triggered - // ripple if action is performed or hides existing ripple if no action is - // performed. Subclasses can override to change the default behavior. - virtual void HandlePerformActionResult(bool action_performed, - const ui::Event& event); - - // Overridden from views::CustomButton. - const char* GetClassName() const override; - bool OnKeyPressed(const ui::KeyEvent& event) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void OnPaint(gfx::Canvas* canvas) override; - void OnFocus() override; - void OnBlur() override; - std::unique_ptr<views::InkDrop> CreateInkDrop() override; - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() - const override; - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; - - // Overridden from views::ButtonListener. - void ButtonPressed(Button* sender, const ui::Event& event) override; - - private: - // Used by ButtonPressed() to determine whether |this| has been destroyed as a - // result of performing the associated action. This is necessary because in - // the not-destroyed case ButtonPressed() uses member variables. - bool* destroyed_; - - SystemTrayItem* owner_; - - base::string16 accessible_name_; - - // Defines the flavor of ink drop ripple/highlight that should be constructed. - TrayPopupInkDropStyle ink_drop_style_; - - DISALLOW_COPY_AND_ASSIGN(ActionableView); -}; - -// An ActionableView that can be used with a ButtonListener instead of having to -// extend ActionableView and override PerformAction(). -class ASH_EXPORT ButtonListenerActionableView : public ActionableView { - public: - ButtonListenerActionableView(SystemTrayItem* owner, - TrayPopupInkDropStyle ink_drop_style, - views::ButtonListener* listener); - - // ActionableView: - bool PerformAction(const ui::Event& event) override; - - private: - views::ButtonListener* listener_; - - DISALLOW_COPY_AND_ASSIGN(ButtonListenerActionableView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_ACTIONABLE_VIEW_H_
diff --git a/ash/system/tray/default_system_tray_delegate.cc b/ash/system/tray/default_system_tray_delegate.cc deleted file mode 100644 index d4e1e25..0000000 --- a/ash/system/tray/default_system_tray_delegate.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/default_system_tray_delegate.h" - -#include <string> - -namespace ash { - -DefaultSystemTrayDelegate::DefaultSystemTrayDelegate() - : bluetooth_enabled_(true) {} - -DefaultSystemTrayDelegate::~DefaultSystemTrayDelegate() {} - -LoginStatus DefaultSystemTrayDelegate::GetUserLoginStatus() const { - return LoginStatus::USER; -} - -std::string DefaultSystemTrayDelegate::GetSupervisedUserManager() const { - if (!IsUserSupervised()) - return std::string(); - return "manager@chrome.com"; -} - -bool DefaultSystemTrayDelegate::IsUserSupervised() const { - return GetUserLoginStatus() == LoginStatus::SUPERVISED; -} - -bool DefaultSystemTrayDelegate::ShouldShowSettings() const { - return true; -} - -bool DefaultSystemTrayDelegate::ShouldShowNotificationTray() const { - return true; -} - -void DefaultSystemTrayDelegate::ToggleBluetooth() { - bluetooth_enabled_ = !bluetooth_enabled_; -} - -bool DefaultSystemTrayDelegate::IsBluetoothDiscovering() const { - return false; -} - -bool DefaultSystemTrayDelegate::GetBluetoothAvailable() { - return true; -} - -bool DefaultSystemTrayDelegate::GetBluetoothEnabled() { - return bluetooth_enabled_; -} - -bool DefaultSystemTrayDelegate::GetBluetoothDiscovering() { - return false; -} - -int DefaultSystemTrayDelegate::GetSystemTrayMenuWidth() { - // This is the default width for English languages. - return 300; -} - -} // namespace ash
diff --git a/ash/system/tray/default_system_tray_delegate.h b/ash/system/tray/default_system_tray_delegate.h deleted file mode 100644 index 6e9d6e9f..0000000 --- a/ash/system/tray/default_system_tray_delegate.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_DEFAULT_SYSTEM_TRAY_DELEGATE_H_ -#define ASH_SYSTEM_TRAY_DEFAULT_SYSTEM_TRAY_DELEGATE_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "base/macros.h" - -namespace ash { - -class ASH_EXPORT DefaultSystemTrayDelegate : public SystemTrayDelegate { - public: - DefaultSystemTrayDelegate(); - ~DefaultSystemTrayDelegate() override; - - // SystemTrayDelegate: - LoginStatus GetUserLoginStatus() const override; - std::string GetSupervisedUserManager() const override; - bool IsUserSupervised() const override; - bool ShouldShowSettings() const override; - bool ShouldShowNotificationTray() const override; - void ToggleBluetooth() override; - bool IsBluetoothDiscovering() const override; - bool GetBluetoothAvailable() override; - bool GetBluetoothEnabled() override; - bool GetBluetoothDiscovering() override; - int GetSystemTrayMenuWidth() override; - - private: - bool bluetooth_enabled_; - - DISALLOW_COPY_AND_ASSIGN(DefaultSystemTrayDelegate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_DEFAULT_SYSTEM_TRAY_DELEGATE_H_
diff --git a/ash/system/tray/fixed_sized_image_view.cc b/ash/system/tray/fixed_sized_image_view.cc deleted file mode 100644 index 27552f88..0000000 --- a/ash/system/tray/fixed_sized_image_view.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/fixed_sized_image_view.h" - -namespace ash { - -FixedSizedImageView::FixedSizedImageView(int width, int height) - : width_(width), height_(height) {} - -FixedSizedImageView::~FixedSizedImageView() {} - -gfx::Size FixedSizedImageView::GetPreferredSize() const { - gfx::Size size = views::ImageView::GetPreferredSize(); - return gfx::Size(width_ ? width_ : size.width(), - height_ ? height_ : size.height()); -} - -} // namespace ash
diff --git a/ash/system/tray/fixed_sized_image_view.h b/ash/system/tray/fixed_sized_image_view.h deleted file mode 100644 index 99a0ab2..0000000 --- a/ash/system/tray/fixed_sized_image_view.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_FIXED_SIZED_IMAGE_VIEW_H_ -#define ASH_SYSTEM_TRAY_FIXED_SIZED_IMAGE_VIEW_H_ - -#include "base/macros.h" -#include "ui/views/controls/image_view.h" - -namespace ash { - -// An image view with a specified width and height (kTrayPopupDetailsIconWidth). -// If the specified width or height is zero, then the image size is used for -// that dimension. -class FixedSizedImageView : public views::ImageView { - public: - FixedSizedImageView(int width, int height); - ~FixedSizedImageView() override; - - private: - gfx::Size GetPreferredSize() const override; - - int width_; - int height_; - - DISALLOW_COPY_AND_ASSIGN(FixedSizedImageView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_FIXED_SIZED_IMAGE_VIEW_H_
diff --git a/ash/system/tray/hover_highlight_view.cc b/ash/system/tray/hover_highlight_view.cc deleted file mode 100644 index 47322ce3..0000000 --- a/ash/system/tray/hover_highlight_view.cc +++ /dev/null
@@ -1,396 +0,0 @@ -// Copyright 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/hover_highlight_view.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ash/system/tray/view_click_listener.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/resources/grit/ui_resources.h" -#include "ui/views/border.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/resources/grit/views_resources.h" - -namespace { - -const gfx::FontList& GetFontList(bool highlight) { - return ui::ResourceBundle::GetSharedInstance().GetFontList( - highlight ? ui::ResourceBundle::BoldFont : ui::ResourceBundle::BaseFont); -} - -} // namespace - -namespace ash { - -HoverHighlightView::HoverHighlightView(ViewClickListener* listener) - : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), - listener_(listener), - highlight_color_(kHoverBackgroundColor) { - set_notify_enter_exit_on_child(true); - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - SetInkDropMode(InkDropHostView::InkDropMode::ON); -} - -HoverHighlightView::~HoverHighlightView() {} - -bool HoverHighlightView::GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const { - if (tooltip_.empty()) - return false; - *tooltip = tooltip_; - return true; -} - -void HoverHighlightView::AddRightIcon(const gfx::ImageSkia& image, - int icon_size) { - DCHECK(!right_view_); - - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - views::ImageView* right_icon = TrayPopupUtils::CreateMainImageView(); - right_icon->SetImage(image); - AddRightView(right_icon); - return; - } - - views::ImageView* right_icon = new FixedSizedImageView(icon_size, icon_size); - right_icon->SetImage(image); - AddRightView(right_icon); -} - -void HoverHighlightView::AddRightView(views::View* view) { - DCHECK(!right_view_); - - right_view_ = view; - right_view_->SetEnabled(enabled()); - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - DCHECK(tri_view_); - tri_view_->AddView(TriView::Container::END, right_view_); - tri_view_->SetContainerVisible(TriView::Container::END, true); - return; - } - DCHECK(box_layout_); - AddChildView(right_view_); -} - -// TODO(tdanderson): Ensure all checkable detailed view rows use this -// mechanism, and share the code that sets the accessible state for -// a checkbox. See crbug.com/652674. -void HoverHighlightView::SetRightViewVisible(bool visible) { - if (!right_view_) - return; - - right_view_->SetVisible(visible); - Layout(); -} - -void HoverHighlightView::AddIconAndLabel(const gfx::ImageSkia& image, - const base::string16& text, - bool highlight) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - DoAddIconAndLabelMd(image, text, - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - return; - } - - box_layout_ = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 3, - kTrayPopupPaddingBetweenItems); - SetLayoutManager(box_layout_); - DoAddIconAndLabel(image, kTrayPopupDetailsIconWidth, text, highlight); -} - -void HoverHighlightView::AddIconAndLabels(const gfx::ImageSkia& image, - const base::string16& text, - const base::string16& sub_text) { - DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); - DoAddIconAndLabelsMd(image, text, - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL, - sub_text); -} - -void HoverHighlightView::AddIconAndLabelCustomSize(const gfx::ImageSkia& image, - const base::string16& text, - bool highlight, - int icon_size, - int indent, - int space_between_items) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - DoAddIconAndLabelMd(image, text, - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - return; - } - - box_layout_ = new views::BoxLayout(views::BoxLayout::kHorizontal, indent, 0, - space_between_items); - SetLayoutManager(box_layout_); - DoAddIconAndLabel(image, icon_size, text, highlight); -} - -void HoverHighlightView::AddIconAndLabelForDefaultView( - const gfx::ImageSkia& image, - const base::string16& text, - bool highlight) { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - DoAddIconAndLabelMd(image, text, - TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - return; - } - - // For non-MD, call AddIconAndLabel() so that |box_layout_| is instantiated - // and installed as the layout manager. - AddIconAndLabel(image, text, highlight); -} - -void HoverHighlightView::DoAddIconAndLabel(const gfx::ImageSkia& image, - int icon_size, - const base::string16& text, - bool highlight) { - DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); - DCHECK(box_layout_); - - views::ImageView* image_view = new FixedSizedImageView(icon_size, 0); - image_view->SetImage(image); - image_view->SetEnabled(enabled()); - AddChildView(image_view); - - text_label_ = new views::Label(text); - text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - text_label_->SetFontList(GetFontList(highlight)); - if (text_default_color_) - text_label_->SetEnabledColor(text_default_color_); - text_label_->SetEnabled(enabled()); - AddChildView(text_label_); - box_layout_->SetFlexForView(text_label_, 1); - - SetAccessibleName(text); -} - -void HoverHighlightView::DoAddIconAndLabelMd( - const gfx::ImageSkia& image, - const base::string16& text, - TrayPopupItemStyle::FontStyle font_style) { - DoAddIconAndLabelsMd(image, text, font_style, base::string16()); -} - -void HoverHighlightView::DoAddIconAndLabelsMd( - const gfx::ImageSkia& image, - const base::string16& text, - TrayPopupItemStyle::FontStyle font_style, - const base::string16& sub_text) { - DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); - - SetLayoutManager(new views::FillLayout); - tri_view_ = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view_); - - left_icon_ = TrayPopupUtils::CreateMainImageView(); - left_icon_->SetImage(image); - left_icon_->SetEnabled(enabled()); - tri_view_->AddView(TriView::Container::START, left_icon_); - - text_label_ = TrayPopupUtils::CreateDefaultLabel(); - text_label_->SetText(text); - text_label_->SetEnabled(enabled()); - TrayPopupItemStyle style(font_style); - style.SetupLabel(text_label_); - - tri_view_->AddView(TriView::Container::CENTER, text_label_); - if (!sub_text.empty()) { - sub_text_label_ = TrayPopupUtils::CreateDefaultLabel(); - sub_text_label_->SetText(sub_text); - TrayPopupItemStyle sub_style(TrayPopupItemStyle::FontStyle::CAPTION); - sub_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); - sub_style.SetupLabel(sub_text_label_); - tri_view_->AddView(TriView::Container::CENTER, sub_text_label_); - } - - tri_view_->SetContainerVisible(TriView::Container::END, false); - - SetAccessibleName(text); -} - -views::Label* HoverHighlightView::AddLabel(const base::string16& text, - gfx::HorizontalAlignment alignment, - bool highlight) { - box_layout_ = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - SetLayoutManager(box_layout_); - text_label_ = new views::Label(text); - int left_margin = kTrayPopupPaddingHorizontal; - int right_margin = kTrayPopupPaddingHorizontal; - if (alignment != gfx::ALIGN_CENTER) { - if (base::i18n::IsRTL()) - right_margin += kTrayPopupDetailsLabelExtraLeftMargin; - else - left_margin += kTrayPopupDetailsLabelExtraLeftMargin; - } - text_label_->SetBorder( - views::CreateEmptyBorder(5, left_margin, 5, right_margin)); - text_label_->SetHorizontalAlignment(alignment); - text_label_->SetFontList(GetFontList(highlight)); - // Do not set alpha value in disable color. It will have issue with elide - // blending filter in disabled state for rendering label text color. - text_label_->SetDisabledColor(SkColorSetARGB(255, 127, 127, 127)); - if (text_default_color_) - text_label_->SetEnabledColor(text_default_color_); - text_label_->SetEnabled(enabled()); - AddChildView(text_label_); - box_layout_->SetFlexForView(text_label_, 1); - - SetAccessibleName(text); - return text_label_; -} - -void HoverHighlightView::AddLabelRowMd(const base::string16& text) { - DCHECK(MaterialDesignController::IsSystemTrayMenuMaterial()); - - SetLayoutManager(new views::FillLayout); - tri_view_ = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view_); - - text_label_ = TrayPopupUtils::CreateDefaultLabel(); - text_label_->SetText(text); - - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - style.SetupLabel(text_label_); - tri_view_->AddView(TriView::Container::CENTER, text_label_); - - SetAccessibleName(text); -} - -void HoverHighlightView::SetExpandable(bool expandable) { - if (expandable != expandable_) { - expandable_ = expandable; - InvalidateLayout(); - } -} - -void HoverHighlightView::SetHighlight(bool highlight) { - // Do not change the font styling for a highlighted row in material design. - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - - DCHECK(text_label_); - text_label_->SetFontList(GetFontList(highlight)); - text_label_->InvalidateLayout(); -} - -void HoverHighlightView::SetAccessiblityState( - AccessibilityState accessibility_state) { - accessibility_state_ = accessibility_state; - if (accessibility_state_ != AccessibilityState::DEFAULT) - NotifyAccessibilityEvent(ui::AX_EVENT_CHECKED_STATE_CHANGED, true); -} - -void HoverHighlightView::SetHoverHighlight(bool hover) { - // We do not show any hover effects for material design. - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return; - - if (!enabled() && hover) - return; - if (hover_ == hover) - return; - hover_ = hover; - if (!text_label_) - return; - if (hover_ && text_highlight_color_) - text_label_->SetEnabledColor(text_highlight_color_); - if (!hover_ && text_default_color_) - text_label_->SetEnabledColor(text_default_color_); - SchedulePaint(); -} - -bool HoverHighlightView::PerformAction(const ui::Event& event) { - if (!listener_) - return false; - listener_->OnViewClicked(this); - return true; -} - -void HoverHighlightView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - ActionableView::GetAccessibleNodeData(node_data); - - if (accessibility_state_ == AccessibilityState::CHECKED_CHECKBOX || - accessibility_state_ == AccessibilityState::UNCHECKED_CHECKBOX) { - node_data->role = ui::AX_ROLE_CHECK_BOX; - } - - if (accessibility_state_ == AccessibilityState::CHECKED_CHECKBOX) - node_data->AddStateFlag(ui::AX_STATE_CHECKED); -} - -gfx::Size HoverHighlightView::GetPreferredSize() const { - gfx::Size size = ActionableView::GetPreferredSize(); - - if (custom_height_) - size.set_height(custom_height_); - else if (!expandable_ || size.height() < kTrayPopupItemMinHeight) - size.set_height(kTrayPopupItemMinHeight); - - return size; -} - -int HoverHighlightView::GetHeightForWidth(int width) const { - return GetPreferredSize().height(); -} - -void HoverHighlightView::OnMouseEntered(const ui::MouseEvent& event) { - SetHoverHighlight(true); -} - -void HoverHighlightView::OnMouseExited(const ui::MouseEvent& event) { - SetHoverHighlight(false); -} - -void HoverHighlightView::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetHoverHighlight(true); - } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || - event->type() == ui::ET_GESTURE_TAP) { - SetHoverHighlight(false); - } - ActionableView::OnGestureEvent(event); -} - -void HoverHighlightView::OnBoundsChanged(const gfx::Rect& previous_bounds) { - SetHoverHighlight(IsMouseHovered()); -} - -void HoverHighlightView::OnEnabledChanged() { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) { - if (left_icon_) - left_icon_->SetEnabled(enabled()); - if (text_label_) - text_label_->SetEnabled(enabled()); - if (right_view_) - right_view_->SetEnabled(enabled()); - } else { - if (!enabled()) - SetHoverHighlight(false); - for (int i = 0; i < child_count(); ++i) - child_at(i)->SetEnabled(enabled()); - } -} - -void HoverHighlightView::OnPaintBackground(gfx::Canvas* canvas) { - canvas->DrawColor(hover_ ? highlight_color_ : default_color_); -} - -void HoverHighlightView::OnFocus() { - ScrollRectToVisible(gfx::Rect(gfx::Point(), size())); - ActionableView::OnFocus(); -} - -} // namespace ash
diff --git a/ash/system/tray/hover_highlight_view.h b/ash/system/tray/hover_highlight_view.h deleted file mode 100644 index 494e83e..0000000 --- a/ash/system/tray/hover_highlight_view.h +++ /dev/null
@@ -1,195 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_ -#define ASH_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_ - -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "base/macros.h" -#include "ui/gfx/font.h" -#include "ui/gfx/text_constants.h" - -namespace views { -class ImageView; -class Label; -class BoxLayout; -} - -namespace ash { -class TriView; -class ViewClickListener; - -// A view that changes background color on hover, and triggers a callback in the -// associated ViewClickListener on click. The view can also be forced to -// maintain a fixed height. -class HoverHighlightView : public ActionableView { - public: - enum class AccessibilityState { - // The default accessibility view. - DEFAULT, - // This view is a checked checkbox. - CHECKED_CHECKBOX, - // This view is an unchecked checkbox. - UNCHECKED_CHECKBOX - }; - - explicit HoverHighlightView(ViewClickListener* listener); - ~HoverHighlightView() override; - - // views::View - bool GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const override; - - // Convenience function for adding an icon and a label. This also sets the - // accessible name. Primarily used for scrollable rows in detailed views. - void AddIconAndLabel(const gfx::ImageSkia& image, - const base::string16& text, - bool highlight); - - // Convenience function for adding an icon, a main label, and a sub label. - // This also sets the accessible name besed on the main label. Used for - // scrollable rows in detailed views in material design. - void AddIconAndLabels(const gfx::ImageSkia& image, - const base::string16& text, - const base::string16& sub_text); - - // Convenience function for adding an icon and a label. This also sets the - // accessible name. This method allows the indent and spacing between elements - // to be set by the caller. |icon_size| is the size of the icon. |indent| is - // the distance between the edges of the view and the icons, and - // |space_between_items| is the minimum distance between any two child views. - // All distances are in DP. Primarily used for scrollable rows in detailed - // views. - void AddIconAndLabelCustomSize(const gfx::ImageSkia& image, - const base::string16& text, - bool highlight, - int icon_size, - int indent, - int space_between_items); - - // A convenience function for adding an icon and label for a system menu - // default view row. - void AddIconAndLabelForDefaultView(const gfx::ImageSkia& image, - const base::string16& text, - bool highlight); - - // Convenience function for adding a label with padding on the left for a - // blank icon. This also sets the accessible name. Returns label after - // parenting it. - views::Label* AddLabel(const base::string16& text, - gfx::HorizontalAlignment alignment, - bool highlight); - - // Adds a row containing only a text label, inset on the left by the - // horizontal space that would normally be occupied by an icon. - void AddLabelRowMd(const base::string16& text); - - // Add an optional right icon to an already established view (call one of - // the other Add* functions first). |icon_size| is the size of the icon in DP. - void AddRightIcon(const gfx::ImageSkia& image, int icon_size); - - // Add an optional right view to an already established view (call one of - // the other Add* functions first). - void AddRightView(views::View* view); - - // Hide or show the right view. - void SetRightViewVisible(bool visible); - - // Allows view to expand its height. - // Size of unexapandable view is fixed and equals to kTrayPopupItemHeight. - void SetExpandable(bool expandable); - - // Enables or disable highlighting on the label, where a highlighted label - // just uses a bold font. - void SetHighlight(bool hightlight); - - // Set a custom height for the view. A value of 0 means that no custom height - // is set. - void set_custom_height(int custom_height) { custom_height_ = custom_height; } - - // Changes the view's current accessibility state. This will fire an - // accessibility event if needed. - void SetAccessiblityState(AccessibilityState accessibility_state); - - void set_highlight_color(SkColor color) { highlight_color_ = color; } - void set_default_color(SkColor color) { default_color_ = color; } - void set_text_highlight_color(SkColor c) { text_highlight_color_ = c; } - void set_text_default_color(SkColor color) { text_default_color_ = color; } - - views::Label* text_label() { return text_label_; } - views::Label* sub_text_label() { return sub_text_label_; } - - bool hover() const { return hover_; } - - void set_tooltip(const base::string16& tooltip) { tooltip_ = tooltip; } - - protected: - // Overridden from views::View. - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - - // Sets the highlighted color on a text label if |hover| is set. - void SetHoverHighlight(bool hover); - - TriView* tri_view() { return tri_view_; } - - private: - // Actually adds the icon and label but does not set the layout manager. - // Not used in material design. - void DoAddIconAndLabel(const gfx::ImageSkia& image, - int icon_size, - const base::string16& text, - bool highlight); - - // Adds the image and label to the row with the label being styled using - // |font_style|. Only used in material design. - void DoAddIconAndLabelMd(const gfx::ImageSkia& image, - const base::string16& text, - TrayPopupItemStyle::FontStyle font_style); - - // Adds the image, main label and sub label to the row with the main label - // being styled using |font_style| and the sub label being styled using - // FontStyle::CAPTION and ColorStyle::INACTIVE. Only used in material design. - void DoAddIconAndLabelsMd(const gfx::ImageSkia& image, - const base::string16& text, - TrayPopupItemStyle::FontStyle font_style, - const base::string16& sub_text); - - // Overridden from ActionableView: - bool PerformAction(const ui::Event& event) override; - - // Overridden from views::View. - gfx::Size GetPreferredSize() const override; - int GetHeightForWidth(int width) const override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - void OnBoundsChanged(const gfx::Rect& previous_bounds) override; - void OnEnabledChanged() override; - void OnPaintBackground(gfx::Canvas* canvas) override; - void OnFocus() override; - - ViewClickListener* listener_ = nullptr; - views::Label* text_label_ = nullptr; - views::Label* sub_text_label_ = nullptr; - views::BoxLayout* box_layout_ = nullptr; // Not used in material design. - views::ImageView* left_icon_ = nullptr; - views::View* right_view_ = nullptr; - TriView* tri_view_ = nullptr; // Only used in material design. - SkColor highlight_color_ = 0; // Not used in material design. - SkColor default_color_ = 0; - SkColor text_highlight_color_ = 0; // Not used in material design. - SkColor text_default_color_ = 0; // Not used in material design. - bool hover_ = false; // Not used in material design. - bool expandable_ = false; - int custom_height_ = 0; // Not used in material design. - AccessibilityState accessibility_state_ = AccessibilityState::DEFAULT; - base::string16 tooltip_; - - DISALLOW_COPY_AND_ASSIGN(HoverHighlightView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_
diff --git a/ash/system/tray/ime_info.cc b/ash/system/tray/ime_info.cc deleted file mode 100644 index bed55d3..0000000 --- a/ash/system/tray/ime_info.cc +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/ime_info.h" - -namespace ash { - -IMEInfo::IMEInfo() : selected(false), third_party(false) {} - -IMEInfo::IMEInfo(const IMEInfo& other) = default; - -IMEInfo::~IMEInfo() {} - -IMEPropertyInfo::IMEPropertyInfo() : selected(false) {} - -IMEPropertyInfo::~IMEPropertyInfo() {} - -} // namespace ash
diff --git a/ash/system/tray/ime_info.h b/ash/system/tray/ime_info.h deleted file mode 100644 index 42685bd5..0000000 --- a/ash/system/tray/ime_info.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_IME_INFO_H_ -#define ASH_SYSTEM_TRAY_IME_INFO_H_ - -#include <string> -#include <vector> - -#include "ash/ash_export.h" -#include "base/strings/string16.h" - -namespace ash { - -struct ASH_EXPORT IMEInfo { - IMEInfo(); - IMEInfo(const IMEInfo& other); - ~IMEInfo(); - - // True if the IME the current IME. - bool selected; - - // True if the IME is a third-party extension. - bool third_party; - - // ID that identifies the IME (e.g., "t:latn-post", "pinyin", "hangul"). - std::string id; - - // Long name of the IME, which is used to specify the user-visible name. - base::string16 name; - - // Medium name of the IME, which is same with short name in most cases, unless - // find in a table for medium length names. - base::string16 medium_name; - - // Indicator of the IME (e.g., "US"). If indicator is empty, use the first two - // character in its preferred keyboard layout or language code (e.g., "ko", - // "ja", "en-US"). - base::string16 short_name; -}; - -using IMEInfoList = std::vector<IMEInfo>; - -struct ASH_EXPORT IMEPropertyInfo { - IMEPropertyInfo(); - ~IMEPropertyInfo(); - - // True if the property is a selection item. - bool selected; - - // The key which identifies the property, e.g. "InputMode.HalfWidthKatakana". - std::string key; - - // The description of the property, e.g. "Switch to full punctuation mode", - // "Hiragana". - base::string16 name; -}; - -using IMEPropertyInfoList = std::vector<IMEPropertyInfo>; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_IME_INFO_H_
diff --git a/ash/system/tray/label_tray_view.cc b/ash/system/tray/label_tray_view.cc deleted file mode 100644 index 518c633..0000000 --- a/ash/system/tray/label_tray_view.cc +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/label_tray_view.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/view_click_listener.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/font.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -namespace { - -// Maps a non-MD PNG resource id to its corresponding MD vector icon. -// TODO(tdanderson): Remove this once material design is enabled by -// default. See crbug.com/614453. -const gfx::VectorIcon& ResourceIdToVectorIcon(int resource_id) { - switch (resource_id) { - case IDR_AURA_UBER_TRAY_ENTERPRISE: - return kSystemMenuBusinessIcon; - case IDR_AURA_UBER_TRAY_BUBBLE_SESSION_LENGTH_LIMIT: - return kSystemMenuTimerIcon; - case IDR_AURA_UBER_TRAY_CHILD_USER: - return kSystemMenuChildUserIcon; - case IDR_AURA_UBER_TRAY_SUPERVISED_USER: - return kSystemMenuSupervisedUserIcon; - default: - NOTREACHED(); - break; - } - return gfx::kNoneIcon; -} - -} // namespace - -LabelTrayView::LabelTrayView(ViewClickListener* click_listener, - int icon_resource_id) - : click_listener_(click_listener), icon_resource_id_(icon_resource_id) { - SetLayoutManager(new views::FillLayout()); - SetVisible(false); -} - -LabelTrayView::~LabelTrayView() {} - -void LabelTrayView::SetMessage(const base::string16& message) { - if (message_ == message) - return; - - message_ = message; - RemoveAllChildViews(true); - - if (!message_.empty()) { - AddChildView(CreateChildView(message_)); - SetVisible(true); - } else { - SetVisible(false); - } -} - -views::View* LabelTrayView::CreateChildView( - const base::string16& message) const { - HoverHighlightView* child = new HoverHighlightView(click_listener_); - if (icon_resource_id_) { - const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial(); - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - gfx::ImageSkia icon = - use_md ? gfx::CreateVectorIcon( - ResourceIdToVectorIcon(icon_resource_id_), kMenuIconColor) - : *rb.GetImageSkiaNamed(icon_resource_id_); - child->AddIconAndLabelForDefaultView(icon, message, false /* highlight */); - child->text_label()->SetMultiLine(true); - if (!use_md) { - child->SetBorder(views::CreateEmptyBorder( - 0, kTrayPopupPaddingHorizontal, 0, kTrayPopupPaddingHorizontal)); - child->text_label()->SizeToFit(kTrayNotificationContentsWidth); - } - } else { - child->AddLabel(message, gfx::ALIGN_LEFT, false /* highlight */); - child->text_label()->SetMultiLine(true); - child->text_label()->SizeToFit(kTrayNotificationContentsWidth + - kNotificationIconWidth); - } - child->text_label()->SetAllowCharacterBreak(true); - child->SetExpandable(true); - child->SetVisible(true); - return child; -} - -} // namespace ash
diff --git a/ash/system/tray/label_tray_view.h b/ash/system/tray/label_tray_view.h deleted file mode 100644 index c526626..0000000 --- a/ash/system/tray/label_tray_view.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_LABEL_TRAY_VIEW_H_ -#define ASH_SYSTEM_TRAY_LABEL_TRAY_VIEW_H_ - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "ui/views/view.h" - -namespace ash { - -class ViewClickListener; - -// View for simple information in tray. Automatically hides when message is -// empty. Supports multiline messages. - -class LabelTrayView : public views::View { - public: - LabelTrayView(ViewClickListener* click_listener, int icon_resource_id); - ~LabelTrayView() override; - void SetMessage(const base::string16& message); - - private: - views::View* CreateChildView(const base::string16& message) const; - - ViewClickListener* click_listener_; - int icon_resource_id_; - base::string16 message_; - - DISALLOW_COPY_AND_ASSIGN(LabelTrayView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_LABEL_TRAY_VIEW_H_
diff --git a/ash/system/tray/size_range_layout.cc b/ash/system/tray/size_range_layout.cc deleted file mode 100644 index 7404ed2..0000000 --- a/ash/system/tray/size_range_layout.cc +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <limits> - -#include "ash/system/tray/size_range_layout.h" - -#include "base/logging.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -// static - -const int SizeRangeLayout::kAbsoluteMinSize = 0; -const int SizeRangeLayout::kAbsoluteMaxSize = std::numeric_limits<int>::max(); - -// Non static - -SizeRangeLayout::SizeRangeLayout() - : SizeRangeLayout(gfx::Size(kAbsoluteMinSize, kAbsoluteMinSize), - gfx::Size(kAbsoluteMaxSize, kAbsoluteMaxSize)) {} - -SizeRangeLayout::SizeRangeLayout(const gfx::Size& min_size, - const gfx::Size& max_size) - : layout_manager_(new views::FillLayout()), - min_size_(gfx::Size(kAbsoluteMinSize, kAbsoluteMinSize)), - max_size_(gfx::Size(kAbsoluteMaxSize, kAbsoluteMaxSize)) { - SetMinSize(min_size); - SetMaxSize(max_size); -} - -SizeRangeLayout::~SizeRangeLayout() {} - -void SizeRangeLayout::SetSize(const gfx::Size& size) { - SetMinSize(size); - SetMaxSize(size); -} - -void SizeRangeLayout::SetMinSize(const gfx::Size& size) { - min_size_ = size; - min_size_.SetToMax(gfx::Size()); - max_size_.SetToMax(min_size_); -} - -void SizeRangeLayout::SetMaxSize(const gfx::Size& size) { - max_size_ = size; - max_size_.SetToMax(gfx::Size()); - min_size_.SetToMin(max_size_); -} - -void SizeRangeLayout::SetLayoutManager( - std::unique_ptr<LayoutManager> layout_manager) { - DCHECK(layout_manager_); - layout_manager_ = std::move(layout_manager); - layout_manager_->Installed(host_); -} - -void SizeRangeLayout::Installed(views::View* host) { - DCHECK(!host_); - host_ = host; - layout_manager_->Installed(host); -} - -void SizeRangeLayout::Layout(views::View* host) { - layout_manager_->Layout(host); -} - -gfx::Size SizeRangeLayout::GetPreferredSize(const views::View* host) const { - gfx::Size preferred_size = layout_manager_->GetPreferredSize(host); - ClampSizeToRange(&preferred_size); - return preferred_size; -} - -int SizeRangeLayout::GetPreferredHeightForWidth(const views::View* host, - int width) const { - const int height = layout_manager_->GetPreferredHeightForWidth(host, width); - gfx::Size size(0, height); - ClampSizeToRange(&size); - return size.height(); -} - -void SizeRangeLayout::ViewAdded(views::View* host, views::View* view) { - layout_manager_->ViewAdded(host, view); -} - -void SizeRangeLayout::ViewRemoved(views::View* host, views::View* view) { - layout_manager_->ViewRemoved(host, view); -} - -void SizeRangeLayout::ClampSizeToRange(gfx::Size* size) const { - size->SetToMax(min_size_); - size->SetToMin(max_size_); -} - -} // namespace ash
diff --git a/ash/system/tray/size_range_layout.h b/ash/system/tray/size_range_layout.h deleted file mode 100644 index 82d355df..0000000 --- a/ash/system/tray/size_range_layout.h +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_ -#define ASH_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/layout/layout_manager.h" - -namespace views { -class View; -} // namespace views - -namespace ash { - -// A LayoutManager adapter that allows clients to specify a minimum and/or a -// maximum preferred size. The actual layout will be delegated to the -// LayoutManager owned by this. i.e. |this| can be used to override the -// preferred size returned by a View. -// -// By default the SizeRangeLayout is configured to own a FillLayout but this can -// be overridden with SetLayoutManager(). -// -// Example use case : -// -// Suppose you wanted a Label to take up a specific size of (50, 50) even -// though the label's preferred size was (25, 25). -// -// Example code: -// -// Label* label = new Label(kSomeDummyText); -// View* container = new View(); -// container->AddChildView(label); -// SizeRangeLayout* layout = new SizeRangeLayout(); -// layout->SetSize(gfx::Size(50, 50)); -// container->SetLayoutManager(layout); -// -class ASH_EXPORT SizeRangeLayout : public views::LayoutManager { - public: - // Create a layout with no minimum or maximum preferred size. - SizeRangeLayout(); - - // Create a layout with the given minimum and maximum preferred sizes. If - // |max_size| is smaller than |min_size| then |min_size| will be set to the - // smaller |max_size| value. - SizeRangeLayout(const gfx::Size& min_size, const gfx::Size& max_size); - - ~SizeRangeLayout() override; - - // The absolute minimum possible width/height. Use this with SetMinSize() to - // effectively unset the minimum preferred size. - static const int kAbsoluteMinSize; - - // Tthe absolute maximum possible width/height. Use this with SetMaxSize() to - // effectively unset the maximum preferred size. - static const int kAbsoluteMaxSize; - - // Sets both the minimum and maximum preferred size. - void SetSize(const gfx::Size& size); - void SetSize(int width, int height); - - // Set the minimum preferred size that GetPreferredSize() will round up to. If - // |size| is larger than the current |max_size_| then |max_size_| will set to - // |size| as well. - void SetMinSize(const gfx::Size& size); - void SetMinSize(int width, int height); - - gfx::Size min_size() const { return min_size_; } - - // Set the minimum preferred size that GetPreferredSize() will round down to. - // If |size| is smaller than the current |min_size_| then |min_size_| will set - // to |size| as well. - void SetMaxSize(const gfx::Size& size); - - // Sets the layout manager that actually performs the layout once the bounds - // have been defined. - void SetLayoutManager(std::unique_ptr<LayoutManager> layout_manager); - - // LayoutManager: - void Installed(views::View* host) override; - void Layout(views::View* host) override; - gfx::Size GetPreferredSize(const views::View* host) const override; - int GetPreferredHeightForWidth(const views::View* host, - int width) const override; - void ViewAdded(views::View* host, views::View* view) override; - void ViewRemoved(views::View* host, views::View* view) override; - - private: - friend class SizeRangeLayoutTest; - - // Clamps |size| to be within the minimum and maximum preferred sizes. - void ClampSizeToRange(gfx::Size* size) const; - - // The host View that this has been installed on. - views::View* host_ = nullptr; - - // The layout manager that actually performs the layout. - std::unique_ptr<views::LayoutManager> layout_manager_; - - // The minimum preferred size. - gfx::Size min_size_; - - // The maximum preferred size. - gfx::Size max_size_; - - DISALLOW_COPY_AND_ASSIGN(SizeRangeLayout); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SIZE_RANGE_LAYOUT_H_
diff --git a/ash/system/tray/size_range_layout_unittest.cc b/ash/system/tray/size_range_layout_unittest.cc deleted file mode 100644 index 12e2c21..0000000 --- a/ash/system/tray/size_range_layout_unittest.cc +++ /dev/null
@@ -1,189 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/size_range_layout.h" -#include "base/memory/ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/views/test/test_layout_manager.h" -#include "ui/views/view.h" - -namespace ash { - -class SizeRangeLayoutTest : public testing::Test { - public: - SizeRangeLayoutTest(); - - // Wrapper function to access the minimum preferred size of |layout|. - gfx::Size GetMinSize(const SizeRangeLayout* layout) const; - - // Wrapper function to access the maximum preferred size of |layout|. - gfx::Size GetMaxSize(const SizeRangeLayout* layout) const; - - protected: - views::View host_; - - const gfx::Size kAbsoluteMinSize; - const gfx::Size kAbsoluteMaxSize; - - private: - DISALLOW_COPY_AND_ASSIGN(SizeRangeLayoutTest); -}; - -SizeRangeLayoutTest::SizeRangeLayoutTest() - : kAbsoluteMinSize(SizeRangeLayout::kAbsoluteMinSize, - SizeRangeLayout::kAbsoluteMinSize), - kAbsoluteMaxSize(SizeRangeLayout::kAbsoluteMaxSize, - SizeRangeLayout::kAbsoluteMaxSize) {} - -gfx::Size SizeRangeLayoutTest::GetMinSize(const SizeRangeLayout* layout) const { - return layout->min_size_; -} - -gfx::Size SizeRangeLayoutTest::GetMaxSize(const SizeRangeLayout* layout) const { - return layout->max_size_; -} - -TEST_F(SizeRangeLayoutTest, SizeRangeForDefaultConstruction) { - SizeRangeLayout layout; - EXPECT_EQ(kAbsoluteMinSize, GetMinSize(&layout)); - EXPECT_EQ(kAbsoluteMaxSize, GetMaxSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, SizeRangeForExplicitConstruction) { - const gfx::Size kSmallSize = gfx::Size(13, 14); - const gfx::Size kLargeSize = gfx::Size(25, 26); - - SizeRangeLayout layout(kSmallSize, kLargeSize); - EXPECT_EQ(kSmallSize, GetMinSize(&layout)); - EXPECT_EQ(kLargeSize, GetMaxSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, InvalidMinSizeForExplicitConstruction) { - const gfx::Size kInvalidSmallSize(-1, 2); - const gfx::Size kExpectedMinSize(0, 2); - - SizeRangeLayout layout(kInvalidSmallSize, kAbsoluteMaxSize); - EXPECT_EQ(kExpectedMinSize, GetMinSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, InvalidMaxSizeForExplicitConstruction) { - const gfx::Size kInvalidSmallSize(-1, 2); - const gfx::Size kExpectedMinSize(0, 2); - - SizeRangeLayout layout(kInvalidSmallSize, kAbsoluteMaxSize); - EXPECT_EQ(kExpectedMinSize, GetMinSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, MaxSizeSmallerThanMinSizeConstruction) { - const gfx::Size kMinSize(10, 11); - const gfx::Size kMaxSize(5, 6); - - SizeRangeLayout layout(kMinSize, kMaxSize); - EXPECT_EQ(kMaxSize, GetMinSize(&layout)); - EXPECT_EQ(kMaxSize, GetMaxSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, SizeRangeForExplicitSetSize) { - const gfx::Size kSize = gfx::Size(13, 14); - - SizeRangeLayout layout; - EXPECT_NE(kSize, GetMinSize(&layout)); - EXPECT_NE(kSize, GetMaxSize(&layout)); - - layout.SetSize(kSize); - EXPECT_EQ(kSize, GetMinSize(&layout)); - EXPECT_EQ(kSize, GetMaxSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, InvalidSizeRangesForExplicitSetSize) { - const gfx::Size kInvalidSize(-7, 8); - const gfx::Size kExpectedSize(0, 8); - - SizeRangeLayout layout; - layout.SetSize(kInvalidSize); - EXPECT_EQ(kExpectedSize, GetMinSize(&layout)); - EXPECT_EQ(kExpectedSize, GetMaxSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, InternalLayoutManagerPreferredSizeIsUsed) { - const gfx::Size kSize(7, 8); - std::unique_ptr<views::test::TestLayoutManager> child_layout = - base::MakeUnique<views::test::TestLayoutManager>(); - child_layout->set_preferred_size(kSize); - - SizeRangeLayout layout; - EXPECT_NE(kSize, layout.GetPreferredSize(&host_)); - - layout.SetLayoutManager(std::move(child_layout)); - EXPECT_EQ(kSize, layout.GetPreferredSize(&host_)); -} - -TEST_F(SizeRangeLayoutTest, SmallPreferredSizeIsClamped) { - const gfx::Size kMinSize(10, 10); - const gfx::Size kMaxSize(20, 20); - const gfx::Size kLayoutPreferredSize(5, 5); - std::unique_ptr<views::test::TestLayoutManager> child_layout = - base::MakeUnique<views::test::TestLayoutManager>(); - child_layout->set_preferred_size(kLayoutPreferredSize); - - SizeRangeLayout layout; - layout.SetLayoutManager(std::move(child_layout)); - layout.SetMinSize(kMinSize); - layout.SetMaxSize(kMaxSize); - EXPECT_EQ(kMinSize, layout.GetPreferredSize(&host_)); -} - -TEST_F(SizeRangeLayoutTest, LargePreferredSizeIsClamped) { - const gfx::Size kMinSize(10, 10); - const gfx::Size kMaxSize(20, 20); - const gfx::Size kLayoutPreferredSize(25, 25); - std::unique_ptr<views::test::TestLayoutManager> child_layout = - base::MakeUnique<views::test::TestLayoutManager>(); - child_layout->set_preferred_size(kLayoutPreferredSize); - - SizeRangeLayout layout; - layout.SetLayoutManager(std::move(child_layout)); - layout.SetMinSize(kMinSize); - layout.SetMaxSize(kMaxSize); - EXPECT_EQ(kMaxSize, layout.GetPreferredSize(&host_)); -} - -TEST_F(SizeRangeLayoutTest, MaxSizeLargerThanMinSizeUpdatesMinSize) { - const gfx::Size kMinSize(10, 10); - const gfx::Size kMaxSize(5, 5); - - SizeRangeLayout layout; - layout.SetMinSize(kMinSize); - EXPECT_EQ(kMinSize, GetMinSize(&layout)); - layout.SetMaxSize(kMaxSize); - EXPECT_EQ(kMaxSize, GetMinSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, MinSizeSmallerThanMaxSizeUpdatesMaxSize) { - const gfx::Size kMinSize(10, 10); - const gfx::Size kMaxSize(5, 5); - - SizeRangeLayout layout; - layout.SetMaxSize(kMaxSize); - EXPECT_EQ(kMaxSize, GetMaxSize(&layout)); - layout.SetMinSize(kMinSize); - EXPECT_EQ(kMinSize, GetMaxSize(&layout)); -} - -TEST_F(SizeRangeLayoutTest, - InternalLayoutManagerPreferredHeightForWidthIsUsed) { - const int kWidth = 5; - const int kHeight = 9; - std::unique_ptr<views::test::TestLayoutManager> child_layout = - base::MakeUnique<views::test::TestLayoutManager>(); - child_layout->set_preferred_height_for_width(kHeight); - - SizeRangeLayout layout; - EXPECT_NE(kHeight, layout.GetPreferredHeightForWidth(&host_, kWidth)); - - layout.SetLayoutManager(std::move(child_layout)); - EXPECT_EQ(kHeight, layout.GetPreferredHeightForWidth(&host_, kWidth)); -} - -} // namespace ash
diff --git a/ash/system/tray/special_popup_row.cc b/ash/system/tray/special_popup_row.cc deleted file mode 100644 index 966b35b..0000000 --- a/ash/system/tray/special_popup_row.cc +++ /dev/null
@@ -1,155 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/special_popup_row.h" - -#include "ash/common/ash_constants.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/throbber_view.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_header_button.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/custom_button.h" -#include "ui/views/controls/button/image_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/painter.h" - -namespace ash { -namespace { - -const int kIconPaddingLeft = 5; -const int kSeparatorInset = 10; -const int kSpecialPopupRowHeight = 55; -const int kBorderHeight = 1; -const SkColor kBorderColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); - -views::View* CreateViewContainer() { - views::View* view = new views::View; - view->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); - view->SetBorder(views::CreateEmptyBorder(4, 0, 4, 5)); - return view; -} - -} // namespace - -SpecialPopupRow::SpecialPopupRow() - : content_(nullptr), views_after_content_container_(nullptr) { - DCHECK(!MaterialDesignController::IsSystemTrayMenuMaterial()); - set_background( - views::Background::CreateSolidBackground(kHeaderBackgroundColor)); - SetBorder( - views::CreateSolidSidedBorder(kBorderHeight, 0, 0, 0, kBorderColor)); -} - -SpecialPopupRow::~SpecialPopupRow() {} - -void SpecialPopupRow::SetTextLabel(int string_id, ViewClickListener* listener) { - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - HoverHighlightView* container = new HoverHighlightView(listener); - container->SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kHorizontal, 0, 3, kIconPaddingLeft)); - - container->set_highlight_color(SkColorSetARGB(0, 0, 0, 0)); - container->set_default_color(SkColorSetARGB(0, 0, 0, 0)); - container->set_text_highlight_color(kHeaderTextColorHover); - container->set_text_default_color(kHeaderTextColorNormal); - - container->AddIconAndLabel( - *rb.GetImageNamed(IDR_AURA_UBER_TRAY_LESS).ToImageSkia(), - rb.GetLocalizedString(string_id), true /* highlight */); - - container->SetBorder( - views::CreateEmptyBorder(0, kTrayPopupPaddingHorizontal, 0, 0)); - - container->SetAccessibleName( - rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_PREVIOUS_MENU)); - SetContent(container); -} - -void SpecialPopupRow::SetContent(views::View* view) { - CHECK(!content_); - views::BoxLayout* box_layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - SetLayoutManager(box_layout); - content_ = view; - AddChildViewAt(content_, 0); -} - -void SpecialPopupRow::AddViewToTitleRow(views::View* view) { - AddViewAfterContent(view); -} - -void SpecialPopupRow::AddViewToRowNonMd(views::View* view, bool add_separator) { - AddViewAfterContent(view, add_separator); -} - -gfx::Size SpecialPopupRow::GetPreferredSize() const { - gfx::Size size = views::View::GetPreferredSize(); - size.set_height(kSpecialPopupRowHeight); - return size; -} - -int SpecialPopupRow::GetHeightForWidth(int width) const { - return kSpecialPopupRowHeight; -} - -void SpecialPopupRow::Layout() { - views::View::Layout(); - - const gfx::Rect content_bounds = GetContentsBounds(); - if (content_bounds.IsEmpty()) - return; - - if (!views_after_content_container_) { - content_->SetBoundsRect(GetContentsBounds()); - return; - } - - gfx::Rect bounds(views_after_content_container_->GetPreferredSize()); - bounds.set_height(content_bounds.height()); - - gfx::Rect container_bounds = content_bounds; - container_bounds.ClampToCenteredSize(bounds.size()); - container_bounds.set_x(content_bounds.width() - container_bounds.width()); - views_after_content_container_->SetBoundsRect(container_bounds); - - bounds = content_->bounds(); - bounds.set_width(views_after_content_container_->x()); - content_->SetBoundsRect(bounds); -} - -void SpecialPopupRow::AddViewAfterContent(views::View* view) { - AddViewAfterContent(view, false); -} - -void SpecialPopupRow::AddViewAfterContent(views::View* view, - bool add_separator) { - if (!views_after_content_container_) { - views_after_content_container_ = CreateViewContainer(); - AddChildView(views_after_content_container_); - } - - if (add_separator) { - views::Separator* separator = new views::Separator(); - separator->SetColor(ash::kBorderDarkColor); - separator->SetBorder( - views::CreateEmptyBorder(kSeparatorInset, 0, kSeparatorInset, 0)); - views_after_content_container_->AddChildView(separator); - } - - views_after_content_container_->AddChildView(view); -} - -} // namespace ash
diff --git a/ash/system/tray/special_popup_row.h b/ash/system/tray/special_popup_row.h deleted file mode 100644 index 4df1bd6..0000000 --- a/ash/system/tray/special_popup_row.h +++ /dev/null
@@ -1,67 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SPECIAL_POPUP_ROW_H_ -#define ASH_SYSTEM_TRAY_SPECIAL_POPUP_ROW_H_ - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "base/macros.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/view.h" - -namespace ash { -class ViewClickListener; - -// Not used in material design. This class represents the bottom row of -// detailed views and the bottom row of the system menu (date, help, power, -// and lock). This row has a fixed height. -// TODO(tdanderson): Remove this class when material design is enabled by -// default. See crbug.com/614453. -class ASH_EXPORT SpecialPopupRow : public views::View { - public: - SpecialPopupRow(); - ~SpecialPopupRow() override; - - // Creates a text label corresponding to |string_id| and sets it as the - // content of this row. - void SetTextLabel(int string_id, ViewClickListener* listener); - - // Sets |content_| to be |view| and adds |content_| as a child view of this - // row. This should only be called once, upon initialization of the row. - void SetContent(views::View* view); - - // Adds |view| after this row's content. - void AddViewToTitleRow(views::View* view); - - // Adds |view| after this row's content, optionally with a separator. Only - // used for non-MD. - void AddViewToRowNonMd(views::View* view, bool add_separator); - - views::View* content() const { return content_; } - - private: - // views::View: - gfx::Size GetPreferredSize() const override; - int GetHeightForWidth(int width) const override; - void Layout() override; - - // Used to add views to |views_after_content_container_|, respectively. Views - // are added in a left-to-right order. - void AddViewAfterContent(views::View* view); - void AddViewAfterContent(views::View* view, bool add_separator); - - // The main content of this row, typically a label. - views::View* content_; - - // The container for the views positioned after |content_|. - views::View* views_after_content_container_; - - DISALLOW_COPY_AND_ASSIGN(SpecialPopupRow); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SPECIAL_POPUP_ROW_H_
diff --git a/ash/system/tray/system_menu_button.cc b/ash/system/tray/system_menu_button.cc deleted file mode 100644 index 3557fd43..0000000 --- a/ash/system/tray/system_menu_button.cc +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_menu_button.h" - -#include "ash/common/ash_constants.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_highlight.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_mask.h" -#include "ui/views/animation/square_ink_drop_ripple.h" -#include "ui/views/border.h" -#include "ui/views/painter.h" - -namespace ash { - -SystemMenuButton::SystemMenuButton(views::ButtonListener* listener, - TrayPopupInkDropStyle ink_drop_style, - gfx::ImageSkia normal_icon, - gfx::ImageSkia disabled_icon, - int accessible_name_id) - : views::ImageButton(listener), ink_drop_style_(ink_drop_style) { - DCHECK_EQ(normal_icon.width(), disabled_icon.width()); - DCHECK_EQ(normal_icon.height(), disabled_icon.height()); - - SetImage(views::Button::STATE_NORMAL, &normal_icon); - SetImage(views::Button::STATE_DISABLED, &disabled_icon); - - const int horizontal_padding = (kMenuButtonSize - normal_icon.width()) / 2; - const int vertical_padding = (kMenuButtonSize - normal_icon.height()) / 2; - SetBorder(views::CreateEmptyBorder(vertical_padding, horizontal_padding, - vertical_padding, horizontal_padding)); - - SetTooltipText(l10n_util::GetStringUTF16(accessible_name_id)); - - SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); - TrayPopupUtils::ConfigureTrayPopupButton(this); -} - -SystemMenuButton::SystemMenuButton(views::ButtonListener* listener, - TrayPopupInkDropStyle ink_drop_style, - const gfx::VectorIcon& icon, - int accessible_name_id) - : SystemMenuButton(listener, - ink_drop_style, - gfx::CreateVectorIcon(icon, kMenuIconColor), - gfx::CreateVectorIcon(icon, kMenuIconColorDisabled), - accessible_name_id) {} - -SystemMenuButton::~SystemMenuButton() {} - -void SystemMenuButton::SetInkDropColor(SkColor color) { - ink_drop_color_ = color; -} - -std::unique_ptr<views::InkDrop> SystemMenuButton::CreateInkDrop() { - return TrayPopupUtils::CreateInkDrop(ink_drop_style_, this); -} - -std::unique_ptr<views::InkDropRipple> SystemMenuButton::CreateInkDropRipple() - const { - return ink_drop_color_ == base::nullopt - ? TrayPopupUtils::CreateInkDropRipple( - ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent()) - : TrayPopupUtils::CreateInkDropRipple( - ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent(), - ink_drop_color_.value()); -} - -std::unique_ptr<views::InkDropHighlight> -SystemMenuButton::CreateInkDropHighlight() const { - return ink_drop_color_ == base::nullopt - ? TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this) - : TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this, - ink_drop_color_.value()); -} - -std::unique_ptr<views::InkDropMask> SystemMenuButton::CreateInkDropMask() - const { - return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this); -} - -} // namespace ash
diff --git a/ash/system/tray/system_menu_button.h b/ash/system/tray/system_menu_button.h deleted file mode 100644 index c7a381e5..0000000 --- a/ash/system/tray/system_menu_button.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_MENU_BUTTON_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_MENU_BUTTON_H_ - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/tray/tray_popup_ink_drop_style.h" -#include "base/macros.h" -#include "base/optional.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/image_button.h" - -namespace ash { - -// A 48x48 image button with a material design ripple effect, which can be -// used across Ash material design native UI menus. -// TODO(tdanderson): Deprecate TrayPopupHeaderButton in favor of -// SystemMenuButton once material design is enabled by default. See -// crbug.com/614453. -class SystemMenuButton : public views::ImageButton { - public: - // Constructs the button with |listener| and a centered icon corresponding to - // |normal_icon| when button is enabled and |disabled_icon| when it is - // disabled. |ink_drop_style| specifies which flavor of the ink drop should be - // used. |accessible_name_id| corresponds to the string in ui::ResourceBundle - // to use for the button's accessible and tooltip text. - SystemMenuButton(views::ButtonListener* listener, - TrayPopupInkDropStyle ink_drop_style, - gfx::ImageSkia normal_icon, - gfx::ImageSkia disabled_icon, - int accessible_name_id); - - // Similar to the above constructor. Just gets a single vector icon and - // creates the normal and disabled icons based on that using default menu icon - // colors. - SystemMenuButton(views::ButtonListener* listener, - TrayPopupInkDropStyle ink_drop_style, - const gfx::VectorIcon& icon, - int accessible_name_id); - ~SystemMenuButton() override; - - // Explicity sets the ink drop color. Otherwise the default value will be used - // by TrayPopupUtils::CreateInkDropRipple() and - // TrayPopupUtils::CreateInkDropHighlight(). - void SetInkDropColor(SkColor color); - - // views::ImageButton: - std::unique_ptr<views::InkDrop> CreateInkDrop() override; - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() - const override; - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; - - private: - // Returns the size that the ink drop should be constructed with. - gfx::Size GetInkDropSize() const; - - // Defines the flavor of ink drop ripple/highlight that should be constructed. - TrayPopupInkDropStyle ink_drop_style_; - - // The color to use when creating the ink drop. If null the default color is - // used as defined by TrayPopupUtils::CreateInkDropRipple() and - // TrayPopupUtils::CreateInkDropHighlight(). - base::Optional<SkColor> ink_drop_color_; - - DISALLOW_COPY_AND_ASSIGN(SystemMenuButton); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_MENU_BUTTON_H_
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc deleted file mode 100644 index 3bad616..0000000 --- a/ash/system/tray/system_tray.cc +++ /dev/null
@@ -1,776 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray.h" - -#include <algorithm> -#include <map> -#include <vector> - -#include "ash/common/key_event_watcher.h" -#include "ash/common/login_status.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_activation_observer.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/audio/tray_audio.h" -#include "ash/system/bluetooth/tray_bluetooth.h" -#include "ash/system/brightness/tray_brightness.h" -#include "ash/system/cast/tray_cast.h" -#include "ash/system/date/tray_date.h" -#include "ash/system/date/tray_system_info.h" -#include "ash/system/enterprise/tray_enterprise.h" -#include "ash/system/ime/tray_ime_chromeos.h" -#include "ash/system/media_security/multi_profile_media_tray_item.h" -#include "ash/system/network/tray_network.h" -#include "ash/system/network/tray_vpn.h" -#include "ash/system/power/power_status.h" -#include "ash/system/power/tray_power.h" -#include "ash/system/screen_security/screen_capture_tray_item.h" -#include "ash/system/screen_security/screen_share_tray_item.h" -#include "ash/system/session/tray_session_length_limit.h" -#include "ash/system/settings/tray_settings.h" -#include "ash/system/supervised/tray_supervised_user.h" -#include "ash/system/tiles/tray_tiles.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_bubble_wrapper.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray_accessibility.h" -#include "ash/system/tray_caps_lock.h" -#include "ash/system/tray_tracing.h" -#include "ash/system/update/tray_update.h" -#include "ash/system/user/tray_user.h" -#include "ash/system/web_notification/web_notification_tray.h" -#include "ash/wm/container_finder.h" -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/timer/timer.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/compositor/layer.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/events/event_constants.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/skia_util.h" -#include "ui/message_center/message_center.h" -#include "ui/message_center/message_center_style.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -using views::TrayBubbleView; - -namespace ash { - -namespace { - -// A tray item that just reserves space in the tray. -class PaddingTrayItem : public SystemTrayItem { - public: - PaddingTrayItem() : SystemTrayItem(nullptr, UMA_NOT_RECORDED) {} - ~PaddingTrayItem() override {} - - // SystemTrayItem: - views::View* CreateTrayView(LoginStatus status) override { - return new PaddingView(); - } - - private: - class PaddingView : public views::View { - public: - PaddingView() {} - ~PaddingView() override {} - - private: - gfx::Size GetPreferredSize() const override { - // The other tray items already have some padding baked in so we have to - // subtract that off. - const int side = kTrayEdgePadding - kTrayImageItemPadding; - return gfx::Size(side, side); - } - - DISALLOW_COPY_AND_ASSIGN(PaddingView); - }; - - DISALLOW_COPY_AND_ASSIGN(PaddingTrayItem); -}; - -} // namespace - -// Class to initialize and manage the SystemTrayBubble and TrayBubbleWrapper -// instances for a bubble. - -class SystemBubbleWrapper { - public: - // Takes ownership of |bubble|. - explicit SystemBubbleWrapper(SystemTrayBubble* bubble) - : bubble_(bubble), is_persistent_(false) {} - - // Initializes the bubble view and creates |bubble_wrapper_|. - void InitView(TrayBackgroundView* tray, - views::View* anchor, - const gfx::Insets& anchor_insets, - TrayBubbleView::InitParams* init_params, - bool is_persistent) { - DCHECK(anchor); - LoginStatus login_status = - WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); - bubble_->InitView(anchor, login_status, init_params); - bubble_->bubble_view()->set_anchor_view_insets(anchor_insets); - bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_->bubble_view())); - is_persistent_ = is_persistent; - - // If ChromeVox is enabled, focus the default item if no item is focused and - // there isn't a delayed close. - if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled() && - !is_persistent) { - bubble_->FocusDefaultIfNeeded(); - } - } - - // Convenience accessors: - SystemTrayBubble* bubble() const { return bubble_.get(); } - SystemTrayBubble::BubbleType bubble_type() const { - return bubble_->bubble_type(); - } - TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); } - bool is_persistent() const { return is_persistent_; } - - private: - std::unique_ptr<SystemTrayBubble> bubble_; - std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_; - bool is_persistent_; - - DISALLOW_COPY_AND_ASSIGN(SystemBubbleWrapper); -}; - -// An activation observer to close the bubble if the window other -// than system bubble nor popup notification is activated. -class SystemTray::ActivationObserver : public WmActivationObserver { - public: - explicit ActivationObserver(SystemTray* tray) : tray_(tray) { - DCHECK(tray_); - WmShell::Get()->AddActivationObserver(this); - } - - ~ActivationObserver() override { - WmShell::Get()->RemoveActivationObserver(this); - } - - // WmActivationObserver: - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override { - if (!tray_->HasSystemBubble() || !gained_active) - return; - - int container_id = - wm::GetContainerForWindow(gained_active)->GetShellWindowId(); - - // Don't close the bubble if a popup notification is activated. - if (container_id == kShellWindowId_StatusContainer) - return; - - if (tray_->GetSystemBubble()->bubble_view()->GetWidget() != - gained_active->GetInternalWidget()) { - tray_->CloseSystemBubble(); - } - } - void OnAttemptToReactivateWindow(WmWindow* request_active, - WmWindow* actual_active) override {} - - private: - SystemTray* tray_; - - DISALLOW_COPY_AND_ASSIGN(ActivationObserver); -}; - -// SystemTray - -SystemTray::SystemTray(WmShelf* wm_shelf) - : TrayBackgroundView(wm_shelf), - web_notification_tray_(nullptr), - detailed_item_(nullptr), - default_bubble_height_(0), - full_system_tray_menu_(false), - tray_accessibility_(nullptr), - tray_audio_(nullptr), - tray_cast_(nullptr), - tray_date_(nullptr), - tray_network_(nullptr), - tray_tiles_(nullptr), - tray_system_info_(nullptr), - tray_update_(nullptr), - screen_capture_tray_item_(nullptr), - screen_share_tray_item_(nullptr) { - if (MaterialDesignController::IsShelfMaterial()) { - SetInkDropMode(InkDropMode::ON); - SetContentsBackground(false); - - // Since user avatar is on the right hand side of System tray of a - // horizontal shelf and that is sufficient to indicate separation, no - // separator is required. - set_separator_visibility(false); - } else { - SetContentsBackground(true); - } -} - -SystemTray::~SystemTray() { - // Destroy any child views that might have back pointers before ~View(). - activation_observer_.reset(); - key_event_watcher_.reset(); - system_bubble_.reset(); - for (const auto& item : items_) - item->DestroyTrayView(); -} - -void SystemTray::InitializeTrayItems( - SystemTrayDelegate* delegate, - WebNotificationTray* web_notification_tray) { - DCHECK(web_notification_tray); - web_notification_tray_ = web_notification_tray; - TrayBackgroundView::Initialize(); - CreateItems(delegate); -} - -void SystemTray::Shutdown() { - DCHECK(web_notification_tray_); - web_notification_tray_ = nullptr; -} - -void SystemTray::CreateItems(SystemTrayDelegate* delegate) { - const bool use_md = MaterialDesignController::IsSystemTrayMenuMaterial(); - - // Create user items for each possible user. - int maximum_user_profiles = WmShell::Get() - ->GetSessionStateDelegate() - ->GetMaximumNumberOfLoggedInUsers(); - for (int i = 0; i < maximum_user_profiles; i++) - AddTrayItem(base::MakeUnique<TrayUser>(this, i)); - - // Crucially, this trailing padding has to be inside the user item(s). - // Otherwise it could be a main axis margin on the tray's box layout. - AddTrayItem(base::MakeUnique<PaddingTrayItem>()); - - tray_accessibility_ = new TrayAccessibility(this); - if (!use_md) - tray_date_ = new TrayDate(this); - tray_update_ = new TrayUpdate(this); - - AddTrayItem(base::MakeUnique<TraySessionLengthLimit>(this)); - AddTrayItem(base::MakeUnique<TrayEnterprise>(this)); - AddTrayItem(base::MakeUnique<TraySupervisedUser>(this)); - AddTrayItem(base::MakeUnique<TrayIME>(this)); - AddTrayItem(base::WrapUnique(tray_accessibility_)); - AddTrayItem(base::MakeUnique<TrayTracing>(this)); - AddTrayItem( - base::MakeUnique<TrayPower>(this, message_center::MessageCenter::Get())); - tray_network_ = new TrayNetwork(this); - AddTrayItem(base::WrapUnique(tray_network_)); - AddTrayItem(base::MakeUnique<TrayVPN>(this)); - AddTrayItem(base::MakeUnique<TrayBluetooth>(this)); - tray_cast_ = new TrayCast(this); - AddTrayItem(base::WrapUnique(tray_cast_)); - screen_capture_tray_item_ = new ScreenCaptureTrayItem(this); - AddTrayItem(base::WrapUnique(screen_capture_tray_item_)); - screen_share_tray_item_ = new ScreenShareTrayItem(this); - AddTrayItem(base::WrapUnique(screen_share_tray_item_)); - AddTrayItem(base::MakeUnique<MultiProfileMediaTrayItem>(this)); - tray_audio_ = new TrayAudio(this); - AddTrayItem(base::WrapUnique(tray_audio_)); - AddTrayItem(base::MakeUnique<TrayBrightness>(this)); - AddTrayItem(base::MakeUnique<TrayCapsLock>(this)); - // TODO(jamescook): Remove this when mus has support for display management - // and we have a DisplayManager equivalent. See http://crbug.com/548429 - std::unique_ptr<SystemTrayItem> tray_rotation_lock = - delegate->CreateRotationLockTrayItem(this); - if (tray_rotation_lock) - AddTrayItem(std::move(tray_rotation_lock)); - if (!use_md) - AddTrayItem(base::MakeUnique<TraySettings>(this)); - AddTrayItem(base::WrapUnique(tray_update_)); - if (use_md) { - tray_tiles_ = new TrayTiles(this); - AddTrayItem(base::WrapUnique(tray_tiles_)); - tray_system_info_ = new TraySystemInfo(this); - AddTrayItem(base::WrapUnique(tray_system_info_)); - // Leading padding. - AddTrayItem(base::MakeUnique<PaddingTrayItem>()); - } else { - AddTrayItem(base::WrapUnique(tray_date_)); - } -} - -void SystemTray::AddTrayItem(std::unique_ptr<SystemTrayItem> item) { - SystemTrayItem* item_ptr = item.get(); - items_.push_back(std::move(item)); - - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - views::View* tray_item = - item_ptr->CreateTrayView(delegate->GetUserLoginStatus()); - item_ptr->UpdateAfterShelfAlignmentChange(shelf_alignment()); - - if (tray_item) { - tray_container()->AddChildViewAt(tray_item, 0); - PreferredSizeChanged(); - tray_item_map_[item_ptr] = tray_item; - } -} - -std::vector<SystemTrayItem*> SystemTray::GetTrayItems() const { - std::vector<SystemTrayItem*> result; - for (const auto& item : items_) - result.push_back(item.get()); - return result; -} - -void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { - if (creation_type != BUBBLE_USE_EXISTING) - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_MENU_OPENED); - ShowItems(GetTrayItems(), false, true, creation_type, false); -} - -void SystemTray::ShowPersistentDefaultView() { - ShowItems(GetTrayItems(), false, false, BUBBLE_CREATE_NEW, true); -} - -void SystemTray::ShowDetailedView(SystemTrayItem* item, - int close_delay, - bool activate, - BubbleCreationType creation_type) { - std::vector<SystemTrayItem*> items; - // The detailed view with timeout means a UI to show the current system state, - // like the audio level or brightness. Such UI should behave as persistent and - // keep its own logic for the appearance. - bool persistent = - (!activate && close_delay > 0 && creation_type == BUBBLE_CREATE_NEW); - items.push_back(item); - ShowItems(items, true, activate, creation_type, persistent); - if (system_bubble_) - system_bubble_->bubble()->StartAutoCloseTimer(close_delay); -} - -void SystemTray::SetDetailedViewCloseDelay(int close_delay) { - if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DETAILED)) - system_bubble_->bubble()->StartAutoCloseTimer(close_delay); -} - -void SystemTray::HideDetailedView(SystemTrayItem* item, bool animate) { - if (item != detailed_item_) - return; - - if (!animate) { - // In unittest, GetSystemBubble might return nullptr. - if (GetSystemBubble()) { - GetSystemBubble() - ->bubble_view() - ->GetWidget() - ->SetVisibilityAnimationTransition( - views::Widget::VisibilityTransition::ANIMATE_NONE); - } - } - - DestroySystemBubble(); -} - -void SystemTray::UpdateAfterLoginStatusChange(LoginStatus login_status) { - DestroySystemBubble(); - - for (const auto& item : items_) - item->UpdateAfterLoginStatusChange(login_status); - - // Items default to SHELF_ALIGNMENT_BOTTOM. Update them if the initial - // position of the shelf differs. - if (!IsHorizontalAlignment(shelf_alignment())) - UpdateAfterShelfAlignmentChange(shelf_alignment()); - - SetVisible(true); - PreferredSizeChanged(); -} - -void SystemTray::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - for (const auto& item : items_) - item->UpdateAfterShelfAlignmentChange(alignment); -} - -bool SystemTray::ShouldShowShelf() const { - return system_bubble_.get() && system_bubble_->bubble()->ShouldShowShelf(); -} - -bool SystemTray::HasSystemBubble() const { - return system_bubble_.get() != NULL; -} - -SystemTrayBubble* SystemTray::GetSystemBubble() { - if (!system_bubble_) - return NULL; - return system_bubble_->bubble(); -} - -bool SystemTray::IsSystemBubbleVisible() const { - return HasSystemBubble() && system_bubble_->bubble()->IsVisible(); -} - -bool SystemTray::CloseSystemBubble() const { - if (!system_bubble_) - return false; - CHECK(!activating_); - system_bubble_->bubble()->Close(); - return true; -} - -views::View* SystemTray::GetHelpButtonView() const { - if (MaterialDesignController::IsSystemTrayMenuMaterial()) - return tray_tiles_->GetHelpButtonView(); - return tray_date_->GetHelpButtonView(); -} - -TrayAudio* SystemTray::GetTrayAudio() const { - return tray_audio_; -} - -// Private methods. - -bool SystemTray::HasSystemBubbleType(SystemTrayBubble::BubbleType type) { - return system_bubble_.get() && system_bubble_->bubble_type() == type; -} - -void SystemTray::DestroySystemBubble() { - CloseSystemBubbleAndDeactivateSystemTray(); - detailed_item_ = NULL; - UpdateWebNotifications(); -} - -base::string16 SystemTray::GetAccessibleNameForTray() { - base::string16 time = GetAccessibleTimeString(base::Time::Now()); - base::string16 battery = PowerStatus::Get()->GetAccessibleNameString(false); - return l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_DESCRIPTION, - time, battery); -} - -void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, - bool detailed, - bool can_activate, - BubbleCreationType creation_type, - bool persistent) { - // No system tray bubbles in kiosk mode. - SystemTrayDelegate* system_tray_delegate = - WmShell::Get()->system_tray_delegate(); - if (system_tray_delegate->GetUserLoginStatus() == LoginStatus::KIOSK_APP || - system_tray_delegate->GetUserLoginStatus() == - LoginStatus::ARC_KIOSK_APP) { - return; - } - - // Destroy any existing bubble and create a new one. - SystemTrayBubble::BubbleType bubble_type = - detailed ? SystemTrayBubble::BUBBLE_TYPE_DETAILED - : SystemTrayBubble::BUBBLE_TYPE_DEFAULT; - - if (system_bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { - system_bubble_->bubble()->UpdateView(items, bubble_type); - // If ChromeVox is enabled, focus the default item if no item is focused. - if (WmShell::Get()->accessibility_delegate()->IsSpokenFeedbackEnabled()) - system_bubble_->bubble()->FocusDefaultIfNeeded(); - } else { - // Cleanup the existing bubble before showing a new one. Otherwise, it's - // possible to confuse the new system bubble with the old one during - // destruction, leading to subtle errors/crashes such as crbug.com/545166. - DestroySystemBubble(); - - // Remember if the menu is a single property (like e.g. volume) or the - // full tray menu. Note that in case of the |BUBBLE_USE_EXISTING| case - // above, |full_system_tray_menu_| does not get changed since the fact that - // the menu is full (or not) doesn't change even if a "single property" - // (like network) replaces most of the menu. - full_system_tray_menu_ = items.size() > 1; - - // The menu width is fixed for all languages in material design. - int menu_width = kTrayMenuMinimumWidthMd; - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { - // The menu width is fixed, and it is a per language setting. - menu_width = std::max( - kTrayMenuMinimumWidth, - WmShell::Get()->system_tray_delegate()->GetSystemTrayMenuWidth()); - } - - TrayBubbleView::InitParams init_params(GetAnchorAlignment(), menu_width, - kTrayPopupMaxWidth); - // TODO(oshima): Change TrayBubbleView itself. - init_params.can_activate = false; - if (detailed) { - // This is the case where a volume control or brightness control bubble - // is created. - init_params.max_height = default_bubble_height_; - init_params.bg_color = kBackgroundColor; - } else { - init_params.bg_color = kHeaderBackgroundColor; - } - if (bubble_type == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) - init_params.close_on_deactivate = !persistent; - SystemTrayBubble* bubble = new SystemTrayBubble(this, items, bubble_type); - - system_bubble_.reset(new SystemBubbleWrapper(bubble)); - system_bubble_->InitView(this, GetBubbleAnchor(), GetBubbleAnchorInsets(), - &init_params, persistent); - - activation_observer_.reset(persistent ? nullptr - : new ActivationObserver(this)); - - // Record metrics for the system menu when the default view is invoked. - if (!detailed) - RecordSystemMenuMetrics(); - } - // Save height of default view for creating detailed views directly. - if (!detailed) - default_bubble_height_ = system_bubble_->bubble_view()->height(); - - key_event_watcher_.reset(); - if (can_activate) - CreateKeyEventWatcher(); - - if (detailed && items.size() > 0) - detailed_item_ = items[0]; - else - detailed_item_ = NULL; - - UpdateWebNotifications(); - shelf()->UpdateAutoHideState(); - - // When we show the system menu in our alternate shelf layout, we need to - // tint the background. - if (full_system_tray_menu_) - SetIsActive(true); -} - -void SystemTray::UpdateWebNotifications() { - TrayBubbleView* bubble_view = NULL; - if (system_bubble_) - bubble_view = system_bubble_->bubble_view(); - - int height = 0; - if (bubble_view) { - gfx::Rect work_area = - display::Screen::GetScreen() - ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView()) - .work_area(); - height = - std::max(0, work_area.bottom() - bubble_view->GetBoundsInScreen().y()); - } - if (web_notification_tray_) - web_notification_tray_->SetTrayBubbleHeight(height); -} - -base::string16 SystemTray::GetAccessibleTimeString( - const base::Time& now) const { - base::HourClockType hour_type = - WmShell::Get()->system_tray_controller()->hour_clock_type(); - return base::TimeFormatTimeOfDayWithHourClockType(now, hour_type, - base::kKeepAmPm); -} - -void SystemTray::SetShelfAlignment(ShelfAlignment alignment) { - if (alignment == shelf_alignment()) - return; - TrayBackgroundView::SetShelfAlignment(alignment); - UpdateAfterShelfAlignmentChange(alignment); - // Destroy any existing bubble so that it is rebuilt correctly. - CloseSystemBubbleAndDeactivateSystemTray(); - // Rebuild any notification bubble. - UpdateWebNotifications(); -} - -void SystemTray::AnchorUpdated() { - if (system_bubble_) { - system_bubble_->bubble_view()->UpdateBubble(); - UpdateBubbleViewArrow(system_bubble_->bubble_view()); - } -} - -void SystemTray::BubbleResized(const TrayBubbleView* bubble_view) { - UpdateWebNotifications(); -} - -void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) { - if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) { - DestroySystemBubble(); - shelf()->UpdateAutoHideState(); - } -} - -void SystemTray::ClickedOutsideBubble() { - if (!system_bubble_ || system_bubble_->is_persistent()) - return; - HideBubbleWithView(system_bubble_->bubble_view()); -} - -void SystemTray::BubbleViewDestroyed() { - if (system_bubble_) { - system_bubble_->bubble()->DestroyItemViews(); - system_bubble_->bubble()->BubbleViewDestroyed(); - } -} - -void SystemTray::OnMouseEnteredView() { - if (system_bubble_) - system_bubble_->bubble()->StopAutoCloseTimer(); -} - -void SystemTray::OnMouseExitedView() { - if (system_bubble_) - system_bubble_->bubble()->RestartAutoCloseTimer(); -} - -base::string16 SystemTray::GetAccessibleNameForBubble() { - return GetAccessibleNameForTray(); -} - -void SystemTray::OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const { - // Place the bubble in the same root window as |anchor_widget|. - WmWindow::Get(anchor_widget->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - bubble_widget, kShellWindowId_SettingBubbleContainer, params); -} - -void SystemTray::HideBubble(const TrayBubbleView* bubble_view) { - HideBubbleWithView(bubble_view); -} - -views::View* SystemTray::GetTrayItemViewForTest(SystemTrayItem* item) { - std::map<SystemTrayItem*, views::View*>::iterator it = - tray_item_map_.find(item); - return it == tray_item_map_.end() ? NULL : it->second; -} - -TrayCast* SystemTray::GetTrayCastForTesting() const { - return tray_cast_; -} - -TrayDate* SystemTray::GetTrayDateForTesting() const { - return tray_date_; -} - -TrayNetwork* SystemTray::GetTrayNetworkForTesting() const { - return tray_network_; -} - -TraySystemInfo* SystemTray::GetTraySystemInfoForTesting() const { - return tray_system_info_; -} - -TrayTiles* SystemTray::GetTrayTilesForTesting() const { - return tray_tiles_; -} - -void SystemTray::CloseBubble(const ui::KeyEvent& key_event) { - CloseSystemBubble(); -} - -void SystemTray::ActivateAndStartNavigation(const ui::KeyEvent& key_event) { - if (!system_bubble_) - return; - activating_ = true; - ActivateBubble(); - activating_ = false; - // TODO(oshima): This is to troubleshoot the issue crbug.com/651242. Remove - // once the root cause is fixed. - CHECK(system_bubble_) << " the bubble was deleted while activaing it"; - - views::Widget* widget = GetSystemBubble()->bubble_view()->GetWidget(); - widget->GetFocusManager()->OnKeyEvent(key_event); -} - -void SystemTray::CreateKeyEventWatcher() { - key_event_watcher_ = WmShell::Get()->CreateKeyEventWatcher(); - // mustash does not yet support KeyEventWatcher. http://crbug.com/649600. - if (!key_event_watcher_) - return; - key_event_watcher_->AddKeyEventCallback( - ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE), - base::Bind(&SystemTray::CloseBubble, base::Unretained(this))); - key_event_watcher_->AddKeyEventCallback( - ui::Accelerator(ui::VKEY_TAB, ui::EF_NONE), - base::Bind(&SystemTray::ActivateAndStartNavigation, - base::Unretained(this))); - key_event_watcher_->AddKeyEventCallback( - ui::Accelerator(ui::VKEY_TAB, ui::EF_SHIFT_DOWN), - base::Bind(&SystemTray::ActivateAndStartNavigation, - base::Unretained(this))); -} - -void SystemTray::ActivateBubble() { - TrayBubbleView* bubble_view = GetSystemBubble()->bubble_view(); - bubble_view->set_can_activate(true); - bubble_view->GetWidget()->Activate(); -} - -bool SystemTray::PerformAction(const ui::Event& event) { - // If we're already showing the default view, hide it; otherwise, show it - // (and hide any popup that's currently shown). - if (HasSystemBubbleType(SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { - system_bubble_->bubble()->Close(); - } else { - ShowDefaultView(BUBBLE_CREATE_NEW); - if (event.IsKeyEvent() || (event.flags() & ui::EF_TOUCH_ACCESSIBILITY)) - ActivateBubble(); - } - return true; -} - -void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() { - CHECK(!activating_); - activation_observer_.reset(); - key_event_watcher_.reset(); - system_bubble_.reset(); - // When closing a system bubble with the alternate shelf layout, we need to - // turn off the active tinting of the shelf. - if (full_system_tray_menu_) { - SetIsActive(false); - full_system_tray_menu_ = false; - } -} - -void SystemTray::RecordSystemMenuMetrics() { - DCHECK(system_bubble_); - - system_bubble_->bubble()->RecordVisibleRowMetrics(); - - TrayBubbleView* bubble_view = system_bubble_->bubble_view(); - int num_rows = 0; - for (int i = 0; i < bubble_view->child_count(); i++) { - // Certain menu rows are attached by default but can set themselves as - // invisible (IME is one such example). Count only user-visible rows. - if (bubble_view->child_at(i)->visible()) - num_rows++; - } - UMA_HISTOGRAM_COUNTS_100("Ash.SystemMenu.Rows", num_rows); - - int work_area_height = - display::Screen::GetScreen() - ->GetDisplayNearestWindow(bubble_view->GetWidget()->GetNativeView()) - .work_area() - .height(); - if (work_area_height > 0) { - UMA_HISTOGRAM_CUSTOM_COUNTS( - "Ash.SystemMenu.PercentageOfWorkAreaHeightCoveredByMenu", - 100 * bubble_view->height() / work_area_height, 1, 300, 100); - } -} - -} // namespace ash
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h deleted file mode 100644 index 3997ba0..0000000 --- a/ash/system/tray/system_tray.h +++ /dev/null
@@ -1,256 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_H_ - -#include <map> -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/system/tray/system_tray_bubble.h" -#include "ash/system/tray/tray_background_view.h" -#include "base/macros.h" -#include "ui/views/bubble/tray_bubble_view.h" -#include "ui/views/view.h" - -namespace ash { - -class KeyEventWatcher; -enum class LoginStatus; -class ScreenTrayItem; -class SystemBubbleWrapper; -class SystemTrayDelegate; -class SystemTrayItem; -class TrayAccessibility; -class TrayAudio; -class TrayCast; -class TrayDate; -class TrayNetwork; -class TraySystemInfo; -class TrayTiles; -class TrayUpdate; -class WebNotificationTray; - -// There are different methods for creating bubble views. -enum BubbleCreationType { - BUBBLE_CREATE_NEW, // Closes any existing bubble and creates a new one. - BUBBLE_USE_EXISTING, // Uses any existing bubble, or creates a new one. -}; - -class ASH_EXPORT SystemTray : public TrayBackgroundView, - public views::TrayBubbleView::Delegate { - public: - explicit SystemTray(WmShelf* wm_shelf); - ~SystemTray() override; - - TrayUpdate* tray_update() { return tray_update_; } - - // Calls TrayBackgroundView::Initialize(), creates the tray items, and - // adds them to SystemTrayNotifier. - void InitializeTrayItems(SystemTrayDelegate* delegate, - WebNotificationTray* web_notification_tray); - - // Resets internal pointers. This has to be called before deletion. - void Shutdown(); - - // Adds a new item in the tray. - void AddTrayItem(std::unique_ptr<SystemTrayItem> item); - - // Returns all tray items that has been added to system tray. - std::vector<SystemTrayItem*> GetTrayItems() const; - - // Shows the default view of all items. - void ShowDefaultView(BubbleCreationType creation_type); - - // Shows default view that ingnores outside clicks and activation loss. - void ShowPersistentDefaultView(); - - // Shows details of a particular item. If |close_delay_in_seconds| is - // non-zero, then the view is automatically closed after the specified time. - void ShowDetailedView(SystemTrayItem* item, - int close_delay_in_seconds, - bool activate, - BubbleCreationType creation_type); - - // Continue showing the existing detailed view, if any, for |close_delay| - // seconds. - void SetDetailedViewCloseDelay(int close_delay); - - // Hides the detailed view for |item|. If |animate| is false, disable - // the hiding animation for hiding |item|. - void HideDetailedView(SystemTrayItem* item, bool animate); - - // Updates the items when the login status of the system changes. - void UpdateAfterLoginStatusChange(LoginStatus login_status); - - // Updates the items when the shelf alignment changes. - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment); - - // Returns true if the shelf should be forced visible when auto-hidden. - bool ShouldShowShelf() const; - - // Returns true if there is a system bubble (already visible or in the process - // of being created). - bool HasSystemBubble() const; - - // Returns true if the system_bubble_ exists and is of type |type|. - bool HasSystemBubbleType(SystemTrayBubble::BubbleType type); - - // Returns a pointer to the system bubble or NULL if none. - SystemTrayBubble* GetSystemBubble(); - - // Returns true if system bubble is visible. - bool IsSystemBubbleVisible() const; - - // Closes system bubble and returns true if it did exist. - bool CloseSystemBubble() const; - - // Returns view for help button if default view is shown. Returns NULL - // otherwise. - views::View* GetHelpButtonView() const; - - // Returns TrayAudio object if present or null otherwise. - TrayAudio* GetTrayAudio() const; - - // Overridden from TrayBackgroundView. - void SetShelfAlignment(ShelfAlignment alignment) override; - void AnchorUpdated() override; - base::string16 GetAccessibleNameForTray() override; - void BubbleResized(const views::TrayBubbleView* bubble_view) override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void ClickedOutsideBubble() override; - - // views::TrayBubbleView::Delegate: - void BubbleViewDestroyed() override; - void OnMouseEnteredView() override; - void OnMouseExitedView() override; - base::string16 GetAccessibleNameForBubble() override; - void OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const override; - void HideBubble(const views::TrayBubbleView* bubble_view) override; - - ScreenTrayItem* GetScreenShareItem() { return screen_share_tray_item_; } - ScreenTrayItem* GetScreenCaptureItem() { return screen_capture_tray_item_; } - - TrayAccessibility* GetTrayAccessibilityForTest() { - return tray_accessibility_; - } - - // Get the tray item view (or NULL) for a given |tray_item| in a unit test. - views::View* GetTrayItemViewForTest(SystemTrayItem* tray_item); - - TrayCast* GetTrayCastForTesting() const; - TrayDate* GetTrayDateForTesting() const; - TrayNetwork* GetTrayNetworkForTesting() const; - TraySystemInfo* GetTraySystemInfoForTesting() const; - TrayTiles* GetTrayTilesForTesting() const; - - // Activates the system tray bubble. - void ActivateBubble(); - - private: - class ActivationObserver; - - // Closes the bubble. Used to bind as a KeyEventWatcher::KeyEventCallback. - void CloseBubble(const ui::KeyEvent& key_event); - - // Activates the bubble and starts key navigation with the |key_event|. - void ActivateAndStartNavigation(const ui::KeyEvent& key_event); - - // Creates the key event watcher. See |ShowItems()| for why key events are - // observed. - void CreateKeyEventWatcher(); - - // Creates the default set of items for the sytem tray. - void CreateItems(SystemTrayDelegate* delegate); - - // Resets |system_bubble_| and clears any related state. - void DestroySystemBubble(); - - // Returns a string with the current time for accessibility on the status - // tray bar. - base::string16 GetAccessibleTimeString(const base::Time& now) const; - - // Constructs or re-constructs |system_bubble_| and populates it with |items|. - // Specify |change_tray_status| to true if want to change the tray background - // status. The bubble will be opened in inactive state. If |can_activate| is - // true, the bubble will be activated by one of following means. - // * When alt/alt-tab acclerator is used to start navigation. - // * When the bubble is opened by accelerator. - // * When the tray item is set to be focused. - void ShowItems(const std::vector<SystemTrayItem*>& items, - bool details, - bool can_activate, - BubbleCreationType creation_type, - bool persistent); - - // Checks the current status of the system tray and updates the web - // notification tray according to the current status. - void UpdateWebNotifications(); - - // Deactivate the system tray in the shelf if it was active before. - void CloseSystemBubbleAndDeactivateSystemTray(); - - // Records UMA metrics for the number of user-visible rows in the system menu - // and the percentage of the work area height covered by the system menu. - void RecordSystemMenuMetrics(); - - // Overridden from ActionableView. - bool PerformAction(const ui::Event& event) override; - - // The web notification tray view that appears adjacent to this view. - WebNotificationTray* web_notification_tray_; - - // Items. - std::vector<std::unique_ptr<SystemTrayItem>> items_; - - // Pointers to members of |items_|. - SystemTrayItem* detailed_item_; - - // Mappings of system tray item and it's view in the tray. - std::map<SystemTrayItem*, views::View*> tray_item_map_; - - // Bubble for default and detailed views. - std::unique_ptr<SystemBubbleWrapper> system_bubble_; - - // Keep track of the default view height so that when we create detailed - // views directly (e.g. from a notification) we know what height to use. - int default_bubble_height_; - - // This is true when the displayed system tray menu is a full tray menu, - // otherwise a single line item menu like the volume slider is shown. - // Note that the value is only valid when |system_bubble_| is true. - bool full_system_tray_menu_; - - // These objects are not owned by this class. - TrayAccessibility* tray_accessibility_; - TrayAudio* tray_audio_; // May be null. - TrayCast* tray_cast_; - TrayDate* tray_date_; // null for material design. - TrayNetwork* tray_network_; - TrayTiles* tray_tiles_; // only used in material design. - TraySystemInfo* tray_system_info_; // only used in material design. - TrayUpdate* tray_update_; - - // A reference to the Screen share and capture item. - ScreenTrayItem* screen_capture_tray_item_; // not owned - ScreenTrayItem* screen_share_tray_item_; // not owned - - // TODO(oshima): Remove this when crbug.com/651242 is fixed. - bool activating_ = false; - - std::unique_ptr<KeyEventWatcher> key_event_watcher_; - - std::unique_ptr<ActivationObserver> activation_observer_; - - DISALLOW_COPY_AND_ASSIGN(SystemTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_H_
diff --git a/ash/system/tray/system_tray_bubble.cc b/ash/system/tray/system_tray_bubble.cc deleted file mode 100644 index f4e96569..0000000 --- a/ash/system/tray/system_tray_bubble.cc +++ /dev/null
@@ -1,368 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray_bubble.h" - -#include <utility> -#include <vector> - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_bubble_wrapper.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_container.h" -#include "base/metrics/histogram_macros.h" -#include "base/threading/thread_task_runner_handle.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/canvas.h" -#include "ui/views/border.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -using views::TrayBubbleView; - -namespace ash { - -namespace { - -// Normally a detailed view is the same size as the default view. However, -// when showing a detailed view directly (e.g. clicking on a notification), -// we may not know the height of the default view, or the default view may -// be too short, so we use this as a default and minimum height for any -// detailed view. -int GetDetailedBubbleMaxHeight() { - return kTrayPopupItemMinHeight * 5; -} - -// Duration of swipe animation used when transitioning from a default to -// detailed view or vice versa. -const int kSwipeDelayMS = 150; - -// Extra bottom padding when showing the BUBBLE_TYPE_DEFAULT view. -const int kDefaultViewBottomPadding = 4; - -// Implicit animation observer that deletes itself and the layer at the end of -// the animation. -class AnimationObserverDeleteLayer : public ui::ImplicitAnimationObserver { - public: - explicit AnimationObserverDeleteLayer(ui::Layer* layer) : layer_(layer) {} - - ~AnimationObserverDeleteLayer() override {} - - void OnImplicitAnimationsCompleted() override { - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); - } - - private: - std::unique_ptr<ui::Layer> layer_; - - DISALLOW_COPY_AND_ASSIGN(AnimationObserverDeleteLayer); -}; - -} // namespace - -// SystemTrayBubble - -SystemTrayBubble::SystemTrayBubble( - ash::SystemTray* tray, - const std::vector<ash::SystemTrayItem*>& items, - BubbleType bubble_type) - : tray_(tray), - bubble_view_(nullptr), - items_(items), - bubble_type_(bubble_type), - autoclose_delay_(0) {} - -SystemTrayBubble::~SystemTrayBubble() { - DestroyItemViews(); - // Reset the host pointer in bubble_view_ in case its destruction is deferred. - if (bubble_view_) - bubble_view_->reset_delegate(); -} - -void SystemTrayBubble::UpdateView( - const std::vector<ash::SystemTrayItem*>& items, - BubbleType bubble_type) { - std::unique_ptr<ui::Layer> scoped_layer; - if (bubble_type != bubble_type_) { - base::TimeDelta swipe_duration = - base::TimeDelta::FromMilliseconds(kSwipeDelayMS); - scoped_layer = bubble_view_->RecreateLayer(); - // Keep the reference to layer as we need it after releasing it. - ui::Layer* layer = scoped_layer.get(); - DCHECK(layer); - layer->SuppressPaint(); - - // When transitioning from detailed view to default view, animate the - // existing view (slide out towards the right). - if (bubble_type == BUBBLE_TYPE_DEFAULT) { - ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); - settings.AddObserver( - new AnimationObserverDeleteLayer(scoped_layer.release())); - settings.SetTransitionDuration(swipe_duration); - settings.SetTweenType(gfx::Tween::EASE_OUT); - gfx::Transform transform; - transform.Translate(layer->bounds().width(), 0.0); - layer->SetTransform(transform); - } - - { - // Add a shadow layer to make the old layer darker as the animation - // progresses. - ui::Layer* shadow = new ui::Layer(ui::LAYER_SOLID_COLOR); - shadow->SetColor(SK_ColorBLACK); - shadow->SetOpacity(0.01f); - shadow->SetBounds(layer->bounds()); - layer->Add(shadow); - layer->StackAtTop(shadow); - { - // Animate the darkening effect a little longer than the swipe-in. This - // is to make sure the darkening animation does not end up finishing - // early, because the dark layer goes away at the end of the animation, - // and there is a brief moment when the old view is still visible, but - // it does not have the shadow layer on top. - ui::ScopedLayerAnimationSettings settings(shadow->GetAnimator()); - settings.AddObserver(new AnimationObserverDeleteLayer(shadow)); - settings.SetTransitionDuration(swipe_duration + - base::TimeDelta::FromMilliseconds(150)); - settings.SetTweenType(gfx::Tween::LINEAR); - shadow->SetOpacity(0.15f); - } - } - } - - DestroyItemViews(); - bubble_view_->RemoveAllChildViews(true); - - items_ = items; - bubble_type_ = bubble_type; - CreateItemViews(WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()); - - // Close bubble view if we failed to create the item view. - if (!bubble_view_->has_children()) { - Close(); - return; - } - - UpdateBottomPadding(); - bubble_view_->GetWidget()->GetContentsView()->Layout(); - // Make sure that the bubble is large enough for the default view. - if (bubble_type_ == BUBBLE_TYPE_DEFAULT) { - bubble_view_->SetMaxHeight(0); // Clear max height limit. - } - - if (scoped_layer) { - // When transitioning from default view to detailed view, animate the new - // view (slide in from the right). - if (bubble_type == BUBBLE_TYPE_DETAILED) { - ui::Layer* new_layer = bubble_view_->layer(); - - // Make sure the new layer is stacked above the old layer during the - // animation. - new_layer->parent()->StackAbove(new_layer, scoped_layer.get()); - - gfx::Rect bounds = new_layer->bounds(); - gfx::Transform transform; - transform.Translate(bounds.width(), 0.0); - new_layer->SetTransform(transform); - { - ui::ScopedLayerAnimationSettings settings(new_layer->GetAnimator()); - settings.AddObserver( - new AnimationObserverDeleteLayer(scoped_layer.release())); - settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kSwipeDelayMS)); - settings.SetTweenType(gfx::Tween::EASE_OUT); - new_layer->SetTransform(gfx::Transform()); - } - } - } -} - -void SystemTrayBubble::InitView(views::View* anchor, - LoginStatus login_status, - TrayBubbleView::InitParams* init_params) { - DCHECK(anchor); - DCHECK(!bubble_view_); - - if (bubble_type_ == BUBBLE_TYPE_DETAILED && - init_params->max_height < GetDetailedBubbleMaxHeight()) { - init_params->max_height = GetDetailedBubbleMaxHeight(); - } - - bubble_view_ = TrayBubbleView::Create(anchor, tray_, init_params); - UpdateBottomPadding(); - bubble_view_->set_adjust_if_offscreen(false); - CreateItemViews(login_status); - - if (bubble_view_->CanActivate()) { - bubble_view_->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT, true); - } -} - -void SystemTrayBubble::FocusDefaultIfNeeded() { - views::FocusManager* manager = bubble_view_->GetFocusManager(); - if (!manager || manager->GetFocusedView()) - return; - - views::View* view = - manager->GetNextFocusableView(nullptr, nullptr, false, false); - // TODO(oshima): RequestFocus calls View::OnFocus even if the widget - // is not active (crbug.com/621791). Remove this check once the bug - // is fixed. - if (bubble_view_->GetWidget()->IsActive()) { - view->RequestFocus(); - } else { - manager->SetStoredFocusView(view); - } -} - -void SystemTrayBubble::DestroyItemViews() { - for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin(); - it != items_.end(); ++it) { - switch (bubble_type_) { - case BUBBLE_TYPE_DEFAULT: - (*it)->DestroyDefaultView(); - break; - case BUBBLE_TYPE_DETAILED: - (*it)->DestroyDetailedView(); - break; - } - } -} - -void SystemTrayBubble::BubbleViewDestroyed() { - bubble_view_ = nullptr; -} - -void SystemTrayBubble::StartAutoCloseTimer(int seconds) { - autoclose_.Stop(); - autoclose_delay_ = seconds; - if (autoclose_delay_) { - autoclose_.Start(FROM_HERE, base::TimeDelta::FromSeconds(autoclose_delay_), - this, &SystemTrayBubble::Close); - } -} - -void SystemTrayBubble::StopAutoCloseTimer() { - autoclose_.Stop(); -} - -void SystemTrayBubble::RestartAutoCloseTimer() { - if (autoclose_delay_) - StartAutoCloseTimer(autoclose_delay_); -} - -void SystemTrayBubble::Close() { - tray_->HideBubbleWithView(bubble_view()); -} - -void SystemTrayBubble::SetVisible(bool is_visible) { - if (!bubble_view_) - return; - views::Widget* bubble_widget = bubble_view_->GetWidget(); - if (is_visible) - bubble_widget->Show(); - else - bubble_widget->Hide(); -} - -bool SystemTrayBubble::IsVisible() { - return bubble_view() && bubble_view()->GetWidget()->IsVisible(); -} - -bool SystemTrayBubble::ShouldShowShelf() const { - for (std::vector<ash::SystemTrayItem*>::const_iterator it = items_.begin(); - it != items_.end(); ++it) { - if ((*it)->ShouldShowShelf()) - return true; - } - return false; -} - -void SystemTrayBubble::RecordVisibleRowMetrics() { - if (bubble_type_ != BUBBLE_TYPE_DEFAULT) - return; - - for (const std::pair<SystemTrayItem::UmaType, views::View*>& pair : - tray_item_view_map_) { - if (pair.second->visible() && - pair.first != SystemTrayItem::UMA_NOT_RECORDED) { - UMA_HISTOGRAM_ENUMERATION("Ash.SystemMenu.DefaultView.VisibleRows", - pair.first, SystemTrayItem::UMA_COUNT); - } - } -} - -void SystemTrayBubble::UpdateBottomPadding() { - if (bubble_type_ == BUBBLE_TYPE_DEFAULT && - MaterialDesignController::IsSystemTrayMenuMaterial()) { - bubble_view_->SetBottomPadding(kDefaultViewBottomPadding); - } else { - bubble_view_->SetBottomPadding(0); - } -} - -void SystemTrayBubble::CreateItemViews(LoginStatus login_status) { - tray_item_view_map_.clear(); - - // If a system modal dialog is present, create the same tray as - // in locked state. - if (WmShell::Get()->IsSystemModalWindowOpen() && - login_status != LoginStatus::NOT_LOGGED_IN) { - login_status = LoginStatus::LOCKED; - } - - std::vector<TrayPopupItemContainer*> item_containers; - views::View* focus_view = nullptr; - const bool is_default_bubble = bubble_type_ == BUBBLE_TYPE_DEFAULT; - for (size_t i = 0; i < items_.size(); ++i) { - views::View* item_view = nullptr; - switch (bubble_type_) { - case BUBBLE_TYPE_DEFAULT: - item_view = items_[i]->CreateDefaultView(login_status); - if (items_[i]->restore_focus()) - focus_view = item_view; - break; - case BUBBLE_TYPE_DETAILED: - item_view = items_[i]->CreateDetailedView(login_status); - break; - } - if (item_view) { - TrayPopupItemContainer* tray_popup_item_container = - new TrayPopupItemContainer( - item_view, - is_default_bubble && - !MaterialDesignController::IsSystemTrayMenuMaterial()); - bubble_view_->AddChildView(tray_popup_item_container); - item_containers.push_back(tray_popup_item_container); - tray_item_view_map_[items_[i]->uma_type()] = tray_popup_item_container; - } - } - - if (!MaterialDesignController::IsSystemTrayMenuMaterial()) { - // For default view, draw bottom border for each item, except the last - // 2 items, which are the bottom header row and the one just above it. - if (is_default_bubble) { - const int last_item_with_border = - static_cast<int>(item_containers.size()) - 2; - for (int i = 0; i < last_item_with_border; ++i) { - item_containers.at(i)->SetBorder( - views::CreateSolidSidedBorder(0, 0, 1, 0, kBorderLightColor)); - } - } - } - - if (focus_view) { - tray_->ActivateBubble(); - focus_view->RequestFocus(); - } -} - -} // namespace ash
diff --git a/ash/system/tray/system_tray_bubble.h b/ash/system/tray/system_tray_bubble.h deleted file mode 100644 index f7f9687a..0000000 --- a/ash/system/tray/system_tray_bubble.h +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_ - -#include <map> -#include <memory> -#include <vector> - -#include "ash/common/login_status.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "ui/views/bubble/tray_bubble_view.h" - -namespace ash { -class SystemTray; -class SystemTrayItem; - -class SystemTrayBubble { - public: - enum BubbleType { BUBBLE_TYPE_DEFAULT, BUBBLE_TYPE_DETAILED }; - - SystemTrayBubble(ash::SystemTray* tray, - const std::vector<ash::SystemTrayItem*>& items, - BubbleType bubble_type); - virtual ~SystemTrayBubble(); - - // Change the items displayed in the bubble. - void UpdateView(const std::vector<ash::SystemTrayItem*>& items, - BubbleType bubble_type); - - // Creates |bubble_view_| and a child views for each member of |items_|. - // Also creates |bubble_wrapper_|. |init_params| may be modified. - void InitView(views::View* anchor, - LoginStatus login_status, - views::TrayBubbleView::InitParams* init_params); - - // Focus the default item if no item is focused. Othewise, do nothing. - void FocusDefaultIfNeeded(); - - BubbleType bubble_type() const { return bubble_type_; } - views::TrayBubbleView* bubble_view() const { return bubble_view_; } - - void DestroyItemViews(); - void BubbleViewDestroyed(); - void StartAutoCloseTimer(int seconds); - void StopAutoCloseTimer(); - void RestartAutoCloseTimer(); - void Close(); - void SetVisible(bool is_visible); - bool IsVisible(); - - // Returns true if any of the SystemTrayItems return true from - // ShouldShowShelf(). - bool ShouldShowShelf() const; - - // Records metrics for visible system menu rows. Only implemented for the - // BUBBLE_TYPE_DEFAULT BubbleType. - void RecordVisibleRowMetrics(); - - private: - // Updates the bottom padding of the |bubble_view_| based on the - // |bubble_type_|. - void UpdateBottomPadding(); - void CreateItemViews(LoginStatus login_status); - - ash::SystemTray* tray_; - views::TrayBubbleView* bubble_view_; - std::vector<ash::SystemTrayItem*> items_; - BubbleType bubble_type_; - - // Tracks the views created in the last call to CreateItemViews(). - std::map<SystemTrayItem::UmaType, views::View*> tray_item_view_map_; - - int autoclose_delay_; - base::OneShotTimer autoclose_; - - DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
diff --git a/ash/system/tray/system_tray_controller.cc b/ash/system/tray/system_tray_controller.cc deleted file mode 100644 index 2432aeff..0000000 --- a/ash/system/tray/system_tray_controller.cc +++ /dev/null
@@ -1,181 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray_controller.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/update/tray_update.h" - -namespace ash { - -SystemTrayController::SystemTrayController() - : hour_clock_type_(base::GetHourClockType()) {} - -SystemTrayController::~SystemTrayController() {} - -void SystemTrayController::ShowSettings() { - if (system_tray_client_) - system_tray_client_->ShowSettings(); -} - -void SystemTrayController::ShowDateSettings() { - if (system_tray_client_) - system_tray_client_->ShowDateSettings(); -} - -void SystemTrayController::ShowSetTimeDialog() { - if (system_tray_client_) - system_tray_client_->ShowSetTimeDialog(); -} - -void SystemTrayController::ShowDisplaySettings() { - if (system_tray_client_) - system_tray_client_->ShowDisplaySettings(); -} - -void SystemTrayController::ShowPowerSettings() { - if (system_tray_client_) - system_tray_client_->ShowPowerSettings(); -} - -void SystemTrayController::ShowChromeSlow() { - if (system_tray_client_) - system_tray_client_->ShowChromeSlow(); -} - -void SystemTrayController::ShowIMESettings() { - if (system_tray_client_) - system_tray_client_->ShowIMESettings(); -} - -void SystemTrayController::ShowHelp() { - if (system_tray_client_) - system_tray_client_->ShowHelp(); -} - -void SystemTrayController::ShowAccessibilityHelp() { - if (system_tray_client_) - system_tray_client_->ShowAccessibilityHelp(); -} - -void SystemTrayController::ShowAccessibilitySettings() { - if (system_tray_client_) - system_tray_client_->ShowAccessibilitySettings(); -} - -void SystemTrayController::ShowPaletteHelp() { - if (system_tray_client_) - system_tray_client_->ShowPaletteHelp(); -} - -void SystemTrayController::ShowPaletteSettings() { - if (system_tray_client_) - system_tray_client_->ShowPaletteSettings(); -} - -void SystemTrayController::ShowPublicAccountInfo() { - if (system_tray_client_) - system_tray_client_->ShowPublicAccountInfo(); -} - -void SystemTrayController::ShowNetworkConfigure(const std::string& network_id) { - if (system_tray_client_) - system_tray_client_->ShowNetworkConfigure(network_id); -} - -void SystemTrayController::ShowNetworkCreate(const std::string& type) { - if (system_tray_client_) - system_tray_client_->ShowNetworkCreate(type); -} - -void SystemTrayController::ShowThirdPartyVpnCreate( - const std::string& extension_id) { - if (system_tray_client_) - system_tray_client_->ShowThirdPartyVpnCreate(extension_id); -} - -void SystemTrayController::ShowNetworkSettings(const std::string& network_id) { - if (system_tray_client_) - system_tray_client_->ShowNetworkSettings(network_id); -} - -void SystemTrayController::ShowProxySettings() { - if (system_tray_client_) - system_tray_client_->ShowProxySettings(); -} - -void SystemTrayController::SignOut() { - if (system_tray_client_) - system_tray_client_->SignOut(); -} - -void SystemTrayController::RequestRestartForUpdate() { - if (system_tray_client_) - system_tray_client_->RequestRestartForUpdate(); -} - -void SystemTrayController::BindRequest(mojom::SystemTrayRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void SystemTrayController::SetClient(mojom::SystemTrayClientPtr client) { - system_tray_client_ = std::move(client); -} - -void SystemTrayController::SetPrimaryTrayEnabled(bool enabled) { - ash::SystemTray* tray = - WmShell::Get()->GetPrimaryRootWindowController()->GetSystemTray(); - if (!tray) - return; - - // We disable the UI to prevent user from interacting with UI elements, - // particularly with the system tray menu. However, in case if the system tray - // bubble is opened at this point, it remains opened and interactive even - // after SystemTray::SetEnabled(false) call, which can be dangerous - // (http://crbug.com/497080). Close the menu to fix it. Calling - // SystemTray::SetEnabled(false) guarantees, that the menu will not be opened - // until the UI is enabled again. - if (!enabled && tray->HasSystemBubble()) - tray->CloseSystemBubble(); - - tray->SetEnabled(enabled); -} - -void SystemTrayController::SetPrimaryTrayVisible(bool visible) { - ash::SystemTray* tray = - WmShell::Get()->GetPrimaryRootWindowController()->GetSystemTray(); - if (!tray) - return; - - tray->SetVisible(visible); - tray->GetWidget()->SetOpacity(visible ? 1.f : 0.f); - if (visible) { - tray->GetWidget()->Show(); - } else { - tray->GetWidget()->Hide(); - } -} - -void SystemTrayController::SetUse24HourClock(bool use_24_hour) { - hour_clock_type_ = use_24_hour ? base::k24HourClock : base::k12HourClock; - WmShell::Get()->system_tray_notifier()->NotifyDateFormatChanged(); -} - -void SystemTrayController::ShowUpdateIcon(mojom::UpdateSeverity severity, - bool factory_reset_required) { - // Show the icon on all displays. - for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { - ash::SystemTray* tray = root->GetRootWindowController()->GetSystemTray(); - // External monitors might not have a tray yet. - if (!tray) - continue; - tray->tray_update()->ShowUpdateIcon(severity, factory_reset_required); - } -} - -} // namespace ash
diff --git a/ash/system/tray/system_tray_controller.h b/ash/system/tray/system_tray_controller.h deleted file mode 100644 index 2ad8cb5..0000000 --- a/ash/system/tray/system_tray_controller.h +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_CONTROLLER_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_CONTROLLER_H_ - -#include "ash/ash_export.h" -#include "ash/public/interfaces/system_tray.mojom.h" -#include "base/compiler_specific.h" -#include "base/i18n/time_formatting.h" -#include "base/macros.h" -#include "mojo/public/cpp/bindings/binding_set.h" - -namespace ash { - -// Both implements mojom::SystemTray and wraps the mojom::SystemTrayClient -// interface. Implements both because it caches state pushed down from the -// browser process via SystemTray so it can be synchronously queried inside ash. -// -// Conceptually similar to historical ash-to-chrome interfaces like -// SystemTrayDelegate. Lives on the main thread. -// -// TODO: Consider renaming this to SystemTrayClient or renaming the current -// SystemTray to SystemTrayView and making this class SystemTray. -class ASH_EXPORT SystemTrayController - : NON_EXPORTED_BASE(public mojom::SystemTray) { - public: - SystemTrayController(); - ~SystemTrayController() override; - - base::HourClockType hour_clock_type() const { return hour_clock_type_; } - - // Wrappers around the mojom::SystemTrayClient interface. - void ShowSettings(); - void ShowDateSettings(); - void ShowSetTimeDialog(); - void ShowDisplaySettings(); - void ShowPowerSettings(); - void ShowChromeSlow(); - void ShowIMESettings(); - void ShowHelp(); - void ShowAccessibilityHelp(); - void ShowAccessibilitySettings(); - void ShowPaletteHelp(); - void ShowPaletteSettings(); - void ShowPublicAccountInfo(); - void ShowNetworkConfigure(const std::string& network_id); - void ShowNetworkCreate(const std::string& type); - void ShowThirdPartyVpnCreate(const std::string& extension_id); - void ShowNetworkSettings(const std::string& network_id); - void ShowProxySettings(); - void SignOut(); - void RequestRestartForUpdate(); - - // Binds the mojom::SystemTray interface to this object. - void BindRequest(mojom::SystemTrayRequest request); - - // mojom::SystemTray overrides. Public for testing. - void SetClient(mojom::SystemTrayClientPtr client) override; - void SetPrimaryTrayEnabled(bool enabled) override; - void SetPrimaryTrayVisible(bool visible) override; - void SetUse24HourClock(bool use_24_hour) override; - void ShowUpdateIcon(mojom::UpdateSeverity severity, - bool factory_reset_required) override; - - private: - // Client interface in chrome browser. Only bound on Chrome OS. - mojom::SystemTrayClientPtr system_tray_client_; - - // Bindings for the SystemTray interface. - mojo::BindingSet<mojom::SystemTray> bindings_; - - // The type of clock hour display: 12 or 24 hour. - base::HourClockType hour_clock_type_; - - DISALLOW_COPY_AND_ASSIGN(SystemTrayController); -}; - -} // namspace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_CONTROLLER_H_
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc deleted file mode 100644 index 1506c93..0000000 --- a/ash/system/tray/system_tray_delegate.cc +++ /dev/null
@@ -1,153 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray_delegate.h" - -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/system_tray_item.h" - -namespace ash { - -BluetoothDeviceInfo::BluetoothDeviceInfo() - : connected(false), connecting(false), paired(false) {} - -BluetoothDeviceInfo::BluetoothDeviceInfo(const BluetoothDeviceInfo& other) = - default; - -BluetoothDeviceInfo::~BluetoothDeviceInfo() {} - -SystemTrayDelegate::SystemTrayDelegate() {} - -SystemTrayDelegate::~SystemTrayDelegate() {} - -void SystemTrayDelegate::Initialize() {} - -LoginStatus SystemTrayDelegate::GetUserLoginStatus() const { - return LoginStatus::NOT_LOGGED_IN; -} - -std::string SystemTrayDelegate::GetEnterpriseDomain() const { - return std::string(); -} - -std::string SystemTrayDelegate::GetEnterpriseRealm() const { - return std::string(); -} - -base::string16 SystemTrayDelegate::GetEnterpriseMessage() const { - return base::string16(); -} - -std::string SystemTrayDelegate::GetSupervisedUserManager() const { - return std::string(); -} - -base::string16 SystemTrayDelegate::GetSupervisedUserManagerName() const { - return base::string16(); -} - -base::string16 SystemTrayDelegate::GetSupervisedUserMessage() const { - return base::string16(); -} - -bool SystemTrayDelegate::IsUserSupervised() const { - return false; -} - -bool SystemTrayDelegate::IsUserChild() const { - return false; -} - -bool SystemTrayDelegate::ShouldShowSettings() const { - return false; -} - -bool SystemTrayDelegate::ShouldShowNotificationTray() const { - return false; -} - -void SystemTrayDelegate::ShowEnterpriseInfo() {} - -void SystemTrayDelegate::ShowUserLogin() {} - -void SystemTrayDelegate::GetAvailableBluetoothDevices( - BluetoothDeviceList* list) {} - -void SystemTrayDelegate::BluetoothStartDiscovering() {} - -void SystemTrayDelegate::BluetoothStopDiscovering() {} - -void SystemTrayDelegate::ConnectToBluetoothDevice(const std::string& address) {} - -void SystemTrayDelegate::GetCurrentIME(IMEInfo* info) {} - -void SystemTrayDelegate::GetAvailableIMEList(IMEInfoList* list) {} - -void SystemTrayDelegate::GetCurrentIMEProperties(IMEPropertyInfoList* list) {} - -base::string16 SystemTrayDelegate::GetIMEManagedMessage() { - return base::string16(); -} - -void SystemTrayDelegate::SwitchIME(const std::string& ime_id) {} - -void SystemTrayDelegate::ActivateIMEProperty(const std::string& key) {} - -void SystemTrayDelegate::ManageBluetoothDevices() {} - -void SystemTrayDelegate::ToggleBluetooth() {} - -bool SystemTrayDelegate::IsBluetoothDiscovering() const { - return false; -} - -bool SystemTrayDelegate::GetBluetoothAvailable() { - return false; -} - -bool SystemTrayDelegate::GetBluetoothEnabled() { - return false; -} - -bool SystemTrayDelegate::GetBluetoothDiscovering() { - return false; -} - -NetworkingConfigDelegate* SystemTrayDelegate::GetNetworkingConfigDelegate() - const { - return nullptr; -} - -bool SystemTrayDelegate::GetSessionStartTime( - base::TimeTicks* session_start_time) { - return false; -} - -bool SystemTrayDelegate::GetSessionLengthLimit( - base::TimeDelta* session_length_limit) { - return false; -} - -int SystemTrayDelegate::GetSystemTrayMenuWidth() { - return 0; -} - -void SystemTrayDelegate::ActiveUserWasChanged() {} - -bool SystemTrayDelegate::IsSearchKeyMappedToCapsLock() { - return false; -} - -void SystemTrayDelegate::AddCustodianInfoTrayObserver( - CustodianInfoTrayObserver* observer) {} - -void SystemTrayDelegate::RemoveCustodianInfoTrayObserver( - CustodianInfoTrayObserver* observer) {} - -std::unique_ptr<SystemTrayItem> SystemTrayDelegate::CreateRotationLockTrayItem( - SystemTray* tray) { - return nullptr; -} - -} // namespace ash
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h deleted file mode 100644 index 509fc04..0000000 --- a/ash/system/tray/system_tray_delegate.h +++ /dev/null
@@ -1,206 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_DELEGATE_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_DELEGATE_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "base/callback_forward.h" -#include "base/files/file_path.h" -#include "base/i18n/time_formatting.h" -#include "base/strings/string16.h" - -namespace base { -class TimeDelta; -class TimeTicks; -} - -namespace device { -enum class BluetoothDeviceType; -} - -namespace ash { -struct IMEInfo; -struct IMEPropertyInfo; - -class CustodianInfoTrayObserver; -class SystemTray; -class SystemTrayItem; - -using IMEInfoList = std::vector<IMEInfo>; -using IMEPropertyInfoList = std::vector<IMEPropertyInfo>; - -struct ASH_EXPORT BluetoothDeviceInfo { - BluetoothDeviceInfo(); - BluetoothDeviceInfo(const BluetoothDeviceInfo& other); - ~BluetoothDeviceInfo(); - - std::string address; - base::string16 display_name; - bool connected; - bool connecting; - bool paired; - device::BluetoothDeviceType device_type; -}; - -using BluetoothDeviceList = std::vector<BluetoothDeviceInfo>; - -class NetworkingConfigDelegate; - -// SystemTrayDelegate is intended for delegating tasks in the System Tray to the -// application (e.g. Chrome). These tasks should be limited to application -// (browser) specific tasks. For non application specific tasks, where possible, -// components/, chromeos/, device/, etc., code should be used directly. If more -// than one related method is being added, consider adding an additional -// specific delegate (e.g. CastConfigDelegate). -// -// These methods should all have trivial default implementations for platforms -// that do not implement the method (e.g. return false or nullptr). This -// eliminates the need to propagate default implementations across the various -// implementations of this class. Consumers of this delegate should handle the -// default return value (e.g. nullptr). -class ASH_EXPORT SystemTrayDelegate { - public: - SystemTrayDelegate(); - virtual ~SystemTrayDelegate(); - - // Called after SystemTray has been instantiated. - virtual void Initialize(); - - // Gets information about the active user. - virtual LoginStatus GetUserLoginStatus() const; - - // Returns the domain that manages the device, if it is enterprise-enrolled. - virtual std::string GetEnterpriseDomain() const; - - // Returns the realm that manages the device, if it is enterprise enrolled - // with Active Directory and joined the realm (Active Directory domain). - virtual std::string GetEnterpriseRealm() const; - - // Returns notification for enterprise enrolled devices. - virtual base::string16 GetEnterpriseMessage() const; - - // Returns the display email of the user that manages the current supervised - // user. - virtual std::string GetSupervisedUserManager() const; - - // Returns the name of the user that manages the current supervised user. - virtual base::string16 GetSupervisedUserManagerName() const; - - // Returns the notification for supervised users. - virtual base::string16 GetSupervisedUserMessage() const; - - // Returns true if the current user is supervised: has legacy supervised - // account or kid account. - virtual bool IsUserSupervised() const; - - // Returns true if the current user is child. - // TODO(merkulova): remove on FakeUserManager componentization. - // crbug.com/443119 - virtual bool IsUserChild() const; - - // Returns true if settings menu item should appear. - virtual bool ShouldShowSettings() const; - - // Returns true if notification tray should appear. - virtual bool ShouldShowNotificationTray() const; - - // Shows information about enterprise enrolled devices. - virtual void ShowEnterpriseInfo(); - - // Shows login UI to add other users to this session. - virtual void ShowUserLogin(); - - // Returns a list of available bluetooth devices. - virtual void GetAvailableBluetoothDevices(BluetoothDeviceList* devices); - - // Requests bluetooth start discovering devices. - virtual void BluetoothStartDiscovering(); - - // Requests bluetooth stop discovering devices. - virtual void BluetoothStopDiscovering(); - - // Connect to a specific bluetooth device. - virtual void ConnectToBluetoothDevice(const std::string& address); - - // Returns true if bluetooth adapter is discovering bluetooth devices. - virtual bool IsBluetoothDiscovering() const; - - // Returns the currently selected IME. - virtual void GetCurrentIME(IMEInfo* info); - - // Returns a list of availble IMEs. - virtual void GetAvailableIMEList(IMEInfoList* list); - - // Returns a list of properties for the currently selected IME. - virtual void GetCurrentIMEProperties(IMEPropertyInfoList* list); - - // Returns a non-empty string if IMEs are managed by policy. - virtual base::string16 GetIMEManagedMessage(); - - // Switches to the selected input method. - virtual void SwitchIME(const std::string& ime_id); - - // Activates an IME property. - virtual void ActivateIMEProperty(const std::string& key); - - // Shows UI to manage bluetooth devices. - virtual void ManageBluetoothDevices(); - - // Toggles bluetooth. - virtual void ToggleBluetooth(); - - // Returns whether bluetooth capability is available. - virtual bool GetBluetoothAvailable(); - - // Returns whether bluetooth is enabled. - virtual bool GetBluetoothEnabled(); - - // Returns whether the delegate has initiated a bluetooth discovery session. - virtual bool GetBluetoothDiscovering(); - - // Returns NetworkingConfigDelegate. May return nullptr. - virtual NetworkingConfigDelegate* GetNetworkingConfigDelegate() const; - - // Retrieves the session start time. Returns |false| if the time is not set. - virtual bool GetSessionStartTime(base::TimeTicks* session_start_time); - - // Retrieves the session length limit. Returns |false| if no limit is set. - virtual bool GetSessionLengthLimit(base::TimeDelta* session_length_limit); - - // Get the system tray menu size in pixels (dependent on the language). - // This is not used in material design and should be removed during pre-MD - // code cleanup. See https://crbug.com/614453. - virtual int GetSystemTrayMenuWidth(); - - // The active user has been changed. This will be called when the UI is ready - // to be switched to the new user. - // Note: This will happen after SessionStateObserver::ActiveUserChanged fires. - virtual void ActiveUserWasChanged(); - - // Returns true when the Search key is configured to be treated as Caps Lock. - virtual bool IsSearchKeyMappedToCapsLock(); - - // Adding observers that are notified when supervised info is being changed. - virtual void AddCustodianInfoTrayObserver( - CustodianInfoTrayObserver* observer); - - virtual void RemoveCustodianInfoTrayObserver( - CustodianInfoTrayObserver* observer); - - // Creates a system tray item for display rotation lock. - // TODO(jamescook): Remove this when mus has support for display management - // and we have a DisplayManager equivalent. See http://crbug.com/548429 - virtual std::unique_ptr<SystemTrayItem> CreateRotationLockTrayItem( - SystemTray* tray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_DELEGATE_H_
diff --git a/ash/system/tray/system_tray_item.cc b/ash/system/tray/system_tray_item.cc deleted file mode 100644 index ac6dde2..0000000 --- a/ash/system/tray/system_tray_item.cc +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray_item.h" - -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "base/timer/timer.h" -#include "ui/views/view.h" - -namespace ash { - -SystemTrayItem::SystemTrayItem(SystemTray* system_tray, UmaType uma_type) - : system_tray_(system_tray), uma_type_(uma_type), restore_focus_(false) {} - -SystemTrayItem::~SystemTrayItem() {} - -views::View* SystemTrayItem::CreateTrayView(LoginStatus status) { - return nullptr; -} - -views::View* SystemTrayItem::CreateDefaultView(LoginStatus status) { - return nullptr; -} - -views::View* SystemTrayItem::CreateDetailedView(LoginStatus status) { - return nullptr; -} - -void SystemTrayItem::DestroyTrayView() {} - -void SystemTrayItem::DestroyDefaultView() {} - -void SystemTrayItem::DestroyDetailedView() {} - -void SystemTrayItem::TransitionDetailedView() { - transition_delay_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs), - base::Bind(&SystemTray::ShowDetailedView, base::Unretained(system_tray()), - this, 0, true, BUBBLE_USE_EXISTING)); -} - -void SystemTrayItem::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void SystemTrayItem::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { -} - -void SystemTrayItem::PopupDetailedView(int for_seconds, bool activate) { - system_tray()->ShowDetailedView(this, for_seconds, activate, - BUBBLE_CREATE_NEW); -} - -void SystemTrayItem::SetDetailedViewCloseDelay(int for_seconds) { - system_tray()->SetDetailedViewCloseDelay(for_seconds); -} - -void SystemTrayItem::HideDetailedView(bool animate) { - system_tray()->HideDetailedView(this, animate); -} - -bool SystemTrayItem::ShouldShowShelf() const { - return true; -} - -} // namespace ash
diff --git a/ash/system/tray/system_tray_item.h b/ash/system/tray/system_tray_item.h deleted file mode 100644 index 087fb40..0000000 --- a/ash/system/tray/system_tray_item.h +++ /dev/null
@@ -1,159 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_ITEM_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_ITEM_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/public/cpp/shelf_types.h" -#include "base/macros.h" -#include "base/timer/timer.h" - -namespace views { -class View; -} - -namespace ash { -class SystemTray; -class SystemTrayBubble; -class TrayItemView; - -// Controller for an item in the system tray. Each item can create these views: -// Tray view - The icon in the status area in the shelf. -// Default view - The row in the top-level menu. -// Detailed view - The submenu shown when the top-level menu row is clicked. -class ASH_EXPORT SystemTrayItem { - public: - // The different types of SystemTrayItems. - // - // NOTE: These values are used for UMA metrics so do NOT re-order this enum - // and only insert items before the COUNT item. - enum UmaType { - // SystemTrayItem's with this type are not recorded in the histogram. - UMA_NOT_RECORDED = 0, - // Used for testing purposes only. - UMA_TEST = 1, - UMA_ACCESSIBILITY = 2, - UMA_AUDIO = 3, - UMA_BLUETOOTH = 4, - UMA_CAPS_LOCK = 5, - UMA_CAST = 6, - UMA_DATE = 7, - UMA_DISPLAY = 8, - UMA_DISPLAY_BRIGHTNESS = 9, - UMA_ENTERPRISE = 10, - UMA_IME = 11, - UMA_MULTI_PROFILE_MEDIA = 12, - UMA_NETWORK = 13, - UMA_SETTINGS = 14, - UMA_UPDATE = 15, - UMA_POWER = 16, - UMA_ROTATION_LOCK = 17, - UMA_SCREEN_CAPTURE = 18, - UMA_SCREEN_SHARE = 19, - UMA_SESSION_LENGTH_LIMIT = 20, - UMA_SMS = 21, - UMA_SUPERVISED_USER = 22, - UMA_TRACING = 23, - UMA_USER = 24, - UMA_VPN = 25, - UMA_COUNT = 26, - }; - - SystemTrayItem(SystemTray* system_tray, UmaType type); - virtual ~SystemTrayItem(); - - // Create* functions may return NULL if nothing should be displayed for the - // type of view. The default implementations return NULL. - - // Returns a view to be displayed in the system tray. If this returns NULL, - // then this item is not displayed in the tray. - // NOTE: The returned view should almost always be a TrayItemView, which - // automatically resizes the widget when the size of the view changes, and - // adds animation when the visibility of the view changes. If a view wants to - // avoid this behavior, then it should not be a TrayItemView. - virtual views::View* CreateTrayView(LoginStatus status); - - // Returns a view for the item to be displayed in the list. This view can be - // displayed with a number of other tray items, so this should not be too - // big. - virtual views::View* CreateDefaultView(LoginStatus status); - - // Returns a detailed view for the item. This view is displayed standalone. - virtual views::View* CreateDetailedView(LoginStatus status); - - // These functions are called when the corresponding view item is about to be - // removed. An item should do appropriate cleanup in these functions. - // The default implementation does nothing. - virtual void DestroyTrayView(); - virtual void DestroyDefaultView(); - virtual void DestroyDetailedView(); - - // Updates the tray view (if applicable) when the user's login status changes. - // It is not necessary the update the default or detailed view, since the - // default/detailed popup is closed when login status changes. The default - // implementation does nothing. - virtual void UpdateAfterLoginStatusChange(LoginStatus status); - - // Updates the tray view (if applicable) when shelf's alignment changes. - // The default implementation does nothing. - virtual void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment); - - // Shows the detailed view for this item. If the main popup for the tray is - // currently visible, then making this call would use the existing window to - // display the detailed item. The detailed item will inherit the bounds of the - // existing window. - // - // In Material Design the actual transition is intentionally delayed to allow - // the user to perceive the ink drop animation on the clicked target. - void TransitionDetailedView(); - - // Pops up the detailed view for this item. An item can request to show its - // detailed view using this function (e.g. from an observer callback when - // something, e.g. volume, network availability etc. changes). If - // |for_seconds| is non-zero, then the popup is closed after the specified - // time. - void PopupDetailedView(int for_seconds, bool activate); - - // Continue showing the currently-shown detailed view, if any, for - // |for_seconds| seconds. The caller is responsible for checking that the - // currently-shown view is for this item. - void SetDetailedViewCloseDelay(int for_seconds); - - // Hides the detailed view for this item. Disable hiding animation if - // |animate| is false. - void HideDetailedView(bool animate); - - // Returns true if this item needs to force the shelf to be visible when - // the shelf is in the auto-hide state. Default is true. - virtual bool ShouldShowShelf() const; - - // Returns the system tray that this item belongs to. - SystemTray* system_tray() const { return system_tray_; } - - bool restore_focus() const { return restore_focus_; } - void set_restore_focus(bool restore_focus) { restore_focus_ = restore_focus; } - - private: - // Accesses uma_type(). - friend class SystemTrayBubble; - - UmaType uma_type() const { return uma_type_; } - - SystemTray* system_tray_; - UmaType uma_type_; - bool restore_focus_; - - // Used to delay the transition to the detailed view. - base::OneShotTimer transition_delay_timer_; - - DISALLOW_COPY_AND_ASSIGN(SystemTrayItem); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_ITEM_H_
diff --git a/ash/system/tray/system_tray_notifier.cc b/ash/system/tray/system_tray_notifier.cc deleted file mode 100644 index baa5755..0000000 --- a/ash/system/tray/system_tray_notifier.cc +++ /dev/null
@@ -1,299 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray_notifier.h" - -#include "ash/system/accessibility_observer.h" -#include "ash/system/bluetooth/bluetooth_observer.h" -#include "ash/system/date/clock_observer.h" -#include "ash/system/enterprise/enterprise_domain_observer.h" -#include "ash/system/ime/ime_observer.h" -#include "ash/system/network/network_observer.h" -#include "ash/system/network/network_portal_detector_observer.h" -#include "ash/system/screen_security/screen_capture_observer.h" -#include "ash/system/screen_security/screen_share_observer.h" -#include "ash/system/session/last_window_closed_observer.h" -#include "ash/system/session/logout_button_observer.h" -#include "ash/system/session/session_length_limit_observer.h" -#include "ash/system/tray_tracing.h" -#include "ash/system/user/user_observer.h" -#include "ash/system/virtual_keyboard/virtual_keyboard_observer.h" - -namespace ash { - -SystemTrayNotifier::SystemTrayNotifier() {} - -SystemTrayNotifier::~SystemTrayNotifier() {} - -void SystemTrayNotifier::AddAccessibilityObserver( - AccessibilityObserver* observer) { - accessibility_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveAccessibilityObserver( - AccessibilityObserver* observer) { - accessibility_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyAccessibilityModeChanged( - AccessibilityNotificationVisibility notify) { - for (auto& observer : accessibility_observers_) - observer.OnAccessibilityModeChanged(notify); -} - -void SystemTrayNotifier::AddBluetoothObserver(BluetoothObserver* observer) { - bluetooth_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveBluetoothObserver(BluetoothObserver* observer) { - bluetooth_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyRefreshBluetooth() { - for (auto& observer : bluetooth_observers_) - observer.OnBluetoothRefresh(); -} - -void SystemTrayNotifier::NotifyBluetoothDiscoveringChanged() { - for (auto& observer : bluetooth_observers_) - observer.OnBluetoothDiscoveringChanged(); -} - -void SystemTrayNotifier::AddClockObserver(ClockObserver* observer) { - clock_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveClockObserver(ClockObserver* observer) { - clock_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyRefreshClock() { - for (auto& observer : clock_observers_) - observer.Refresh(); -} - -void SystemTrayNotifier::NotifyDateFormatChanged() { - for (auto& observer : clock_observers_) - observer.OnDateFormatChanged(); -} - -void SystemTrayNotifier::NotifySystemClockTimeUpdated() { - for (auto& observer : clock_observers_) - observer.OnSystemClockTimeUpdated(); -} - -void SystemTrayNotifier::NotifySystemClockCanSetTimeChanged(bool can_set_time) { - for (auto& observer : clock_observers_) - observer.OnSystemClockCanSetTimeChanged(can_set_time); -} - -void SystemTrayNotifier::AddEnterpriseDomainObserver( - EnterpriseDomainObserver* observer) { - enterprise_domain_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveEnterpriseDomainObserver( - EnterpriseDomainObserver* observer) { - enterprise_domain_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyEnterpriseDomainChanged() { - for (auto& observer : enterprise_domain_observers_) - observer.OnEnterpriseDomainChanged(); -} - -void SystemTrayNotifier::AddIMEObserver(IMEObserver* observer) { - ime_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveIMEObserver(IMEObserver* observer) { - ime_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyRefreshIME() { - for (auto& observer : ime_observers_) - observer.OnIMERefresh(); -} - -void SystemTrayNotifier::NotifyRefreshIMEMenu(bool is_active) { - for (auto& observer : ime_observers_) - observer.OnIMEMenuActivationChanged(is_active); -} - -void SystemTrayNotifier::AddLastWindowClosedObserver( - LastWindowClosedObserver* observer) { - last_window_closed_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveLastWindowClosedObserver( - LastWindowClosedObserver* observer) { - last_window_closed_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyLastWindowClosed() { - for (auto& observer : last_window_closed_observers_) - observer.OnLastWindowClosed(); -} - -void SystemTrayNotifier::AddLogoutButtonObserver( - LogoutButtonObserver* observer) { - logout_button_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveLogoutButtonObserver( - LogoutButtonObserver* observer) { - logout_button_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyShowLoginButtonChanged(bool show_login_button) { - for (auto& observer : logout_button_observers_) - observer.OnShowLogoutButtonInTrayChanged(show_login_button); -} - -void SystemTrayNotifier::NotifyLogoutDialogDurationChanged( - base::TimeDelta duration) { - for (auto& observer : logout_button_observers_) - observer.OnLogoutDialogDurationChanged(duration); -} - -void SystemTrayNotifier::AddNetworkObserver(NetworkObserver* observer) { - network_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveNetworkObserver(NetworkObserver* observer) { - network_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyRequestToggleWifi() { - for (auto& observer : network_observers_) - observer.RequestToggleWifi(); -} - -void SystemTrayNotifier::AddNetworkPortalDetectorObserver( - NetworkPortalDetectorObserver* observer) { - network_portal_detector_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveNetworkPortalDetectorObserver( - NetworkPortalDetectorObserver* observer) { - network_portal_detector_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyOnCaptivePortalDetected( - const std::string& guid) { - for (auto& observer : network_portal_detector_observers_) - observer.OnCaptivePortalDetected(guid); -} - -void SystemTrayNotifier::AddScreenCaptureObserver( - ScreenCaptureObserver* observer) { - screen_capture_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveScreenCaptureObserver( - ScreenCaptureObserver* observer) { - screen_capture_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyScreenCaptureStart( - const base::Closure& stop_callback, - const base::string16& sharing_app_name) { - for (auto& observer : screen_capture_observers_) - observer.OnScreenCaptureStart(stop_callback, sharing_app_name); -} - -void SystemTrayNotifier::NotifyScreenCaptureStop() { - for (auto& observer : screen_capture_observers_) - observer.OnScreenCaptureStop(); -} - -void SystemTrayNotifier::AddScreenShareObserver(ScreenShareObserver* observer) { - screen_share_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveScreenShareObserver( - ScreenShareObserver* observer) { - screen_share_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyScreenShareStart( - const base::Closure& stop_callback, - const base::string16& helper_name) { - for (auto& observer : screen_share_observers_) - observer.OnScreenShareStart(stop_callback, helper_name); -} - -void SystemTrayNotifier::NotifyScreenShareStop() { - for (auto& observer : screen_share_observers_) - observer.OnScreenShareStop(); -} - -void SystemTrayNotifier::AddSessionLengthLimitObserver( - SessionLengthLimitObserver* observer) { - session_length_limit_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveSessionLengthLimitObserver( - SessionLengthLimitObserver* observer) { - session_length_limit_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifySessionStartTimeChanged() { - for (auto& observer : session_length_limit_observers_) - observer.OnSessionStartTimeChanged(); -} - -void SystemTrayNotifier::NotifySessionLengthLimitChanged() { - for (auto& observer : session_length_limit_observers_) - observer.OnSessionLengthLimitChanged(); -} - -void SystemTrayNotifier::AddTracingObserver(TracingObserver* observer) { - tracing_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveTracingObserver(TracingObserver* observer) { - tracing_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyTracingModeChanged(bool value) { - for (auto& observer : tracing_observers_) - observer.OnTracingModeChanged(value); -} - -void SystemTrayNotifier::AddUserObserver(UserObserver* observer) { - user_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveUserObserver(UserObserver* observer) { - user_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyUserUpdate() { - for (auto& observer : user_observers_) - observer.OnUserUpdate(); -} - -void SystemTrayNotifier::NotifyUserAddedToSession() { - for (auto& observer : user_observers_) - observer.OnUserAddedToSession(); -} - -void SystemTrayNotifier::AddVirtualKeyboardObserver( - VirtualKeyboardObserver* observer) { - virtual_keyboard_observers_.AddObserver(observer); -} - -void SystemTrayNotifier::RemoveVirtualKeyboardObserver( - VirtualKeyboardObserver* observer) { - virtual_keyboard_observers_.RemoveObserver(observer); -} - -void SystemTrayNotifier::NotifyVirtualKeyboardSuppressionChanged( - bool suppressed) { - for (auto& observer : virtual_keyboard_observers_) - observer.OnKeyboardSuppressionChanged(suppressed); -} - -} // namespace ash
diff --git a/ash/system/tray/system_tray_notifier.h b/ash/system/tray/system_tray_notifier.h deleted file mode 100644 index 945a299c..0000000 --- a/ash/system/tray/system_tray_notifier.h +++ /dev/null
@@ -1,160 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_SYSTEM_TRAY_NOTIFIER_H_ -#define ASH_SYSTEM_TRAY_SYSTEM_TRAY_NOTIFIER_H_ - -#include <string> - -#include "ash/ash_export.h" -#include "ash/common/accessibility_types.h" -#include "base/callback_forward.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/strings/string16.h" -#include "base/time/time.h" - -namespace ash { - -class AccessibilityObserver; -class BluetoothObserver; -class ClockObserver; -class EnterpriseDomainObserver; -class IMEObserver; -class LastWindowClosedObserver; -class LogoutButtonObserver; -class NetworkObserver; -class NetworkPortalDetectorObserver; -class ScreenCaptureObserver; -class ScreenShareObserver; -class SessionLengthLimitObserver; -class TracingObserver; -class UserObserver; -class VirtualKeyboardObserver; - -namespace mojom { -enum class UpdateSeverity; -} - -// Observer and notification manager for the ash system tray. -class ASH_EXPORT SystemTrayNotifier { - public: - SystemTrayNotifier(); - ~SystemTrayNotifier(); - - // Accessibility. - void AddAccessibilityObserver(AccessibilityObserver* observer); - void RemoveAccessibilityObserver(AccessibilityObserver* observer); - void NotifyAccessibilityModeChanged( - AccessibilityNotificationVisibility notify); - - // Bluetooth. - void AddBluetoothObserver(BluetoothObserver* observer); - void RemoveBluetoothObserver(BluetoothObserver* observer); - void NotifyRefreshBluetooth(); - void NotifyBluetoothDiscoveringChanged(); - - // Date and time. - void AddClockObserver(ClockObserver* observer); - void RemoveClockObserver(ClockObserver* observer); - void NotifyRefreshClock(); - void NotifyDateFormatChanged(); - void NotifySystemClockTimeUpdated(); - void NotifySystemClockCanSetTimeChanged(bool can_set_time); - - // Enterprise domain. - void AddEnterpriseDomainObserver(EnterpriseDomainObserver* observer); - void RemoveEnterpriseDomainObserver(EnterpriseDomainObserver* observer); - void NotifyEnterpriseDomainChanged(); - - // Input methods. - void AddIMEObserver(IMEObserver* observer); - void RemoveIMEObserver(IMEObserver* observer); - void NotifyRefreshIME(); - void NotifyRefreshIMEMenu(bool is_active); - - // Last window closed. - void AddLastWindowClosedObserver(LastWindowClosedObserver* observer); - void RemoveLastWindowClosedObserver(LastWindowClosedObserver* observer); - void NotifyLastWindowClosed(); - - // Logout button. - void AddLogoutButtonObserver(LogoutButtonObserver* observer); - void RemoveLogoutButtonObserver(LogoutButtonObserver* observer); - void NotifyShowLoginButtonChanged(bool show_login_button); - void NotifyLogoutDialogDurationChanged(base::TimeDelta duration); - - // Network. - void AddNetworkObserver(NetworkObserver* observer); - void RemoveNetworkObserver(NetworkObserver* observer); - void NotifyRequestToggleWifi(); - - // Network portal detector. - void AddNetworkPortalDetectorObserver( - NetworkPortalDetectorObserver* observer); - void RemoveNetworkPortalDetectorObserver( - NetworkPortalDetectorObserver* observer); - void NotifyOnCaptivePortalDetected(const std::string& guid); - - // Screen capture. - void AddScreenCaptureObserver(ScreenCaptureObserver* observer); - void RemoveScreenCaptureObserver(ScreenCaptureObserver* observer); - void NotifyScreenCaptureStart(const base::Closure& stop_callback, - const base::string16& sharing_app_name); - void NotifyScreenCaptureStop(); - - // Screen share. - void AddScreenShareObserver(ScreenShareObserver* observer); - void RemoveScreenShareObserver(ScreenShareObserver* observer); - void NotifyScreenShareStart(const base::Closure& stop_callback, - const base::string16& helper_name); - void NotifyScreenShareStop(); - - // Session length limit. - void AddSessionLengthLimitObserver(SessionLengthLimitObserver* observer); - void RemoveSessionLengthLimitObserver(SessionLengthLimitObserver* observer); - void NotifySessionStartTimeChanged(); - void NotifySessionLengthLimitChanged(); - - // Tracing. - void AddTracingObserver(TracingObserver* observer); - void RemoveTracingObserver(TracingObserver* observer); - void NotifyTracingModeChanged(bool value); - - // User. - void AddUserObserver(UserObserver* observer); - void RemoveUserObserver(UserObserver* observer); - void NotifyUserUpdate(); - void NotifyUserAddedToSession(); - - // Virtual keyboard. - void AddVirtualKeyboardObserver(VirtualKeyboardObserver* observer); - void RemoveVirtualKeyboardObserver(VirtualKeyboardObserver* observer); - void NotifyVirtualKeyboardSuppressionChanged(bool suppressed); - - private: - base::ObserverList<AccessibilityObserver> accessibility_observers_; - base::ObserverList<BluetoothObserver> bluetooth_observers_; - base::ObserverList<ClockObserver> clock_observers_; - base::ObserverList<EnterpriseDomainObserver> enterprise_domain_observers_; - base::ObserverList<IMEObserver> ime_observers_; - base::ObserverList<LastWindowClosedObserver> last_window_closed_observers_; - base::ObserverList<LogoutButtonObserver> logout_button_observers_; - base::ObserverList<NetworkObserver> network_observers_; - base::ObserverList<NetworkPortalDetectorObserver> - network_portal_detector_observers_; - base::ObserverList<ScreenCaptureObserver> screen_capture_observers_; - base::ObserverList<ScreenShareObserver> screen_share_observers_; - base::ObserverList<SessionLengthLimitObserver> - session_length_limit_observers_; - base::ObserverList<TracingObserver> tracing_observers_; - base::ObserverList<UserObserver> user_observers_; - base::ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; - - DISALLOW_COPY_AND_ASSIGN(SystemTrayNotifier); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_SYSTEM_TRAY_NOTIFIER_H_
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc deleted file mode 100644 index 62c8d95..0000000 --- a/ash/system/tray/system_tray_unittest.cc +++ /dev/null
@@ -1,562 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/system_tray.h" - -#include <string> -#include <vector> - -#include "ash/accelerators/accelerator_controller.h" -#include "ash/common/accessibility_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray_bubble.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_container.h" -#include "ash/system/web_notification/web_notification_tray.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/status_area_widget_test_helper.h" -#include "ash/test/test_system_tray_item.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/test/histogram_tester.h" -#include "ui/base/ui_base_types.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/events/test/event_generator.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/controls/separator.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { -namespace test { - -namespace { - -const char kVisibleRowsHistogramName[] = - "Ash.SystemMenu.DefaultView.VisibleRows"; - -class ModalWidgetDelegate : public views::WidgetDelegateView { - public: - ModalWidgetDelegate() {} - ~ModalWidgetDelegate() override {} - - ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_SYSTEM; } - - private: - DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate); -}; - -} // namespace - -typedef AshTestBase SystemTrayTest; - -// Verifies only the visible default views are recorded in the -// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. -TEST_F(SystemTrayTest, OnlyVisibleItemsRecorded) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(test_item)); - - base::HistogramTester histogram_tester; - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 1); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 2); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); - - test_item->set_views_are_visible(false); - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 2); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); -} - -// Verifies a visible UMA_NOT_RECORDED default view is not recorded in the -// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. -TEST_F(SystemTrayTest, NotRecordedtemsAreNotRecorded) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = - new TestSystemTrayItem(SystemTrayItem::UMA_NOT_RECORDED); - tray->AddTrayItem(base::WrapUnique(test_item)); - - base::HistogramTester histogram_tester; - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_NOT_RECORDED, 0); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); -} - -// Verifies null default views are not recorded in the -// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. -TEST_F(SystemTrayTest, NullDefaultViewIsNotRecorded) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - test_item->set_has_views(false); - tray->AddTrayItem(base::WrapUnique(test_item)); - - base::HistogramTester histogram_tester; - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 0); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); -} - -// Verifies visible detailed views are not recorded in the -// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. -TEST_F(SystemTrayTest, VisibleDetailedViewsIsNotRecorded) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(test_item)); - - base::HistogramTester histogram_tester; - - tray->ShowDetailedView(test_item, 0, false, BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - - histogram_tester.ExpectTotalCount(kVisibleRowsHistogramName, 0); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); -} - -// Verifies visible default views are not recorded for menu re-shows in the -// "Ash.SystemMenu.DefaultView.VisibleItems" histogram. -TEST_F(SystemTrayTest, VisibleDefaultViewIsNotRecordedOnReshow) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(test_item)); - - base::HistogramTester histogram_tester; - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 1); - - tray->ShowDetailedView(test_item, 0, false, BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 1); - - tray->ShowDefaultView(BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - histogram_tester.ExpectBucketCount(kVisibleRowsHistogramName, - SystemTrayItem::UMA_TEST, 1); - - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); -} - -TEST_F(SystemTrayTest, SystemTrayDefaultView) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - - // Ensure that closing the bubble destroys it. - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); - ASSERT_FALSE(tray->CloseSystemBubble()); -} - -// Make sure the opening system tray bubble will not deactivate the -// other window. crbug.com/120680. -TEST_F(SystemTrayTest, Activation) { - // TODO: investigate why this fails in mash. http://crbug.com/695559. - if (WmShell::Get()->IsRunningInMash()) - return; - - SystemTray* tray = GetPrimarySystemTray(); - std::unique_ptr<views::Widget> widget(CreateTestWidget( - nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100))); - EXPECT_TRUE(widget->IsActive()); - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - ASSERT_TRUE(tray->GetWidget()); - EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive()); - EXPECT_TRUE(widget->IsActive()); - - tray->ActivateBubble(); - EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive()); - EXPECT_FALSE(widget->IsActive()); - - // Accelerator will activate the bubble. - tray->CloseSystemBubble(); - - EXPECT_TRUE(widget->IsActive()); - WmShell::Get()->accelerator_controller()->PerformActionIfEnabled( - SHOW_SYSTEM_TRAY_BUBBLE); - EXPECT_TRUE(tray->GetSystemBubble()->bubble_view()->GetWidget()->IsActive()); - EXPECT_FALSE(widget->IsActive()); -} - -// Opening and closing the bubble should change the coloring of the tray. -TEST_F(SystemTrayTest, SystemTrayColoring) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - // At the beginning the tray coloring is not active. - ASSERT_FALSE(tray->is_active()); - - // Showing the system bubble should show the background as active. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - ASSERT_TRUE(tray->is_active()); - - // Closing the system menu should change the coloring back to normal. - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); - ASSERT_FALSE(tray->is_active()); -} - -// Closing the system bubble through an alignment change should change the -// system tray coloring back to normal. -TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - WmShelf* shelf = GetPrimaryShelf(); - shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); - // At the beginning the tray coloring is not active. - ASSERT_FALSE(tray->is_active()); - - // Showing the system bubble should show the background as active. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - ASSERT_TRUE(tray->is_active()); - - // Changing the alignment should close the system bubble and change the - // background color. - shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); - ASSERT_FALSE(tray->is_active()); - RunAllPendingInMessageLoop(); - // The bubble should already be closed by now. - ASSERT_FALSE(tray->CloseSystemBubble()); -} - -TEST_F(SystemTrayTest, SystemTrayTestItems) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - TestSystemTrayItem* detailed_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(test_item)); - tray->AddTrayItem(base::WrapUnique(detailed_item)); - - // Check items have been added. - std::vector<SystemTrayItem*> items = tray->GetTrayItems(); - ASSERT_TRUE(std::find(items.begin(), items.end(), test_item) != items.end()); - ASSERT_TRUE(std::find(items.begin(), items.end(), detailed_item) != - items.end()); - - // Ensure the tray views are created. - ASSERT_TRUE(test_item->tray_view() != NULL); - ASSERT_TRUE(detailed_item->tray_view() != NULL); - - // Ensure a default views are created. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - ASSERT_TRUE(test_item->default_view() != NULL); - ASSERT_TRUE(detailed_item->default_view() != NULL); - - // Show the detailed view, ensure it's created and the default view destroyed. - tray->ShowDetailedView(detailed_item, 0, false, BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - ASSERT_TRUE(test_item->default_view() == NULL); - ASSERT_TRUE(detailed_item->detailed_view() != NULL); - - // Show the default view, ensure it's created and the detailed view destroyed. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - ASSERT_TRUE(test_item->default_view() != NULL); - ASSERT_TRUE(detailed_item->detailed_view() == NULL); -} - -TEST_F(SystemTrayTest, SystemTrayNoViewItems) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - // Verify that no crashes occur on items lacking some views. - TestSystemTrayItem* no_view_item = new TestSystemTrayItem(); - no_view_item->set_has_views(false); - tray->AddTrayItem(base::WrapUnique(no_view_item)); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - tray->ShowDetailedView(no_view_item, 0, false, BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); -} - -TEST_F(SystemTrayTest, TrayWidgetAutoResizes) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - // Add an initial tray item so that the tray gets laid out correctly. - TestSystemTrayItem* initial_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(initial_item)); - - gfx::Size initial_size = tray->GetWidget()->GetWindowBoundsInScreen().size(); - - TestSystemTrayItem* new_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(new_item)); - - gfx::Size new_size = tray->GetWidget()->GetWindowBoundsInScreen().size(); - - // Adding the new item should change the size of the tray. - EXPECT_NE(initial_size.ToString(), new_size.ToString()); - - // Hiding the tray view of the new item should also change the size of the - // tray. - new_item->tray_view()->SetVisible(false); - EXPECT_EQ(initial_size.ToString(), - tray->GetWidget()->GetWindowBoundsInScreen().size().ToString()); - - new_item->tray_view()->SetVisible(true); - EXPECT_EQ(new_size.ToString(), - tray->GetWidget()->GetWindowBoundsInScreen().size().ToString()); -} - -// Test is flaky. http://crbug.com/637978 -TEST_F(SystemTrayTest, DISABLED_BubbleCreationTypesTest) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(test_item)); - - // Ensure the tray views are created. - ASSERT_TRUE(test_item->tray_view() != NULL); - - // Show the default view, ensure the notification view is destroyed. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - - views::Widget* widget = test_item->default_view()->GetWidget(); - gfx::Rect bubble_bounds = widget->GetWindowBoundsInScreen(); - - tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - - EXPECT_FALSE(test_item->default_view()); - - EXPECT_EQ(bubble_bounds.ToString(), test_item->detailed_view() - ->GetWidget() - ->GetWindowBoundsInScreen() - .ToString()); - EXPECT_EQ(widget, test_item->detailed_view()->GetWidget()); - - tray->ShowDefaultView(BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - - EXPECT_EQ(bubble_bounds.ToString(), test_item->default_view() - ->GetWidget() - ->GetWindowBoundsInScreen() - .ToString()); - EXPECT_EQ(widget, test_item->default_view()->GetWidget()); -} - -// Tests that the tray view is laid out properly and is fully contained within -// the shelf widget. -TEST_F(SystemTrayTest, TrayBoundsInWidget) { - WmShelf* shelf = GetPrimaryShelf(); - StatusAreaWidget* widget = StatusAreaWidgetTestHelper::GetStatusAreaWidget(); - SystemTray* tray = GetPrimarySystemTray(); - - // Test in bottom alignment. - shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); - gfx::Rect window_bounds = widget->GetWindowBoundsInScreen(); - gfx::Rect tray_bounds = tray->GetBoundsInScreen(); - EXPECT_TRUE(window_bounds.Contains(tray_bounds)); - - // Test in locked alignment. - shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM_LOCKED); - window_bounds = widget->GetWindowBoundsInScreen(); - tray_bounds = tray->GetBoundsInScreen(); - EXPECT_TRUE(window_bounds.Contains(tray_bounds)); - - // Test in the left alignment. - shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); - window_bounds = widget->GetWindowBoundsInScreen(); - tray_bounds = tray->GetBoundsInScreen(); - // TODO(estade): Re-enable this check. See crbug.com/660928. - // EXPECT_TRUE(window_bounds.Contains(tray_bounds)); - - // Test in the right alignment. - shelf->SetAlignment(SHELF_ALIGNMENT_LEFT); - window_bounds = widget->GetWindowBoundsInScreen(); - tray_bounds = tray->GetBoundsInScreen(); - // TODO(estade): Re-enable this check. See crbug.com/660928. - // EXPECT_TRUE(window_bounds.Contains(tray_bounds)); -} - -TEST_F(SystemTrayTest, PersistentBubble) { - // TODO: investigate why this fails in mash. http://crbug.com/695559. - if (WmShell::Get()->IsRunningInMash()) - return; - - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestSystemTrayItem* test_item = new TestSystemTrayItem(); - tray->AddTrayItem(base::WrapUnique(test_item)); - - std::unique_ptr<views::Widget> widget(CreateTestWidget( - nullptr, kShellWindowId_DefaultContainer, gfx::Rect(0, 0, 100, 100))); - - // Tests for usual default view while activating a window. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - tray->ActivateBubble(); - ASSERT_TRUE(tray->HasSystemBubble()); - widget->Activate(); - base::RunLoop().RunUntilIdle(); - ASSERT_FALSE(tray->HasSystemBubble()); - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - ASSERT_TRUE(tray->HasSystemBubble()); - { - ui::test::EventGenerator& generator = GetEventGenerator(); - generator.set_current_location(gfx::Point(5, 5)); - generator.ClickLeftButton(); - ASSERT_FALSE(tray->HasSystemBubble()); - } - - // Same tests for persistent default view. - tray->ShowPersistentDefaultView(); - ASSERT_TRUE(tray->HasSystemBubble()); - widget->Activate(); - base::RunLoop().RunUntilIdle(); - ASSERT_TRUE(tray->HasSystemBubble()); - - { - ui::test::EventGenerator& generator = GetEventGenerator(); - generator.set_current_location(gfx::Point(5, 5)); - generator.ClickLeftButton(); - ASSERT_TRUE(tray->HasSystemBubble()); - } - - // Same tests for persistent default view with activation. - tray->ShowPersistentDefaultView(); - EXPECT_TRUE(tray->HasSystemBubble()); - widget->Activate(); - base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(tray->HasSystemBubble()); - - ui::test::EventGenerator& generator = GetEventGenerator(); - generator.set_current_location(gfx::Point(5, 5)); - generator.ClickLeftButton(); - EXPECT_TRUE(tray->HasSystemBubble()); -} - -TEST_F(SystemTrayTest, WithSystemModal) { - // Check if the accessibility item is created even with system modal dialog. - WmShell::Get()->accessibility_delegate()->SetVirtualKeyboardEnabled(true); - std::unique_ptr<views::Widget> widget(CreateTestWidget( - new ModalWidgetDelegate, kShellWindowId_SystemModalContainer, - gfx::Rect(0, 0, 100, 100))); - - SystemTray* tray = GetPrimarySystemTray(); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - - ASSERT_TRUE(tray->HasSystemBubble()); - const views::View* accessibility = - tray->GetSystemBubble()->bubble_view()->GetViewByID( - test::kAccessibilityTrayItemViewId); - ASSERT_TRUE(accessibility); - EXPECT_TRUE(accessibility->visible()); - EXPECT_FALSE(tray->GetSystemBubble()->bubble_view()->GetViewByID( - test::kSettingsTrayItemViewId)); - - // Close the modal dialog. - widget.reset(); - - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - // System modal is gone. The bubble should now contains settings - // as well. - accessibility = tray->GetSystemBubble()->bubble_view()->GetViewByID( - test::kAccessibilityTrayItemViewId); - ASSERT_TRUE(accessibility); - EXPECT_TRUE(accessibility->visible()); -} - -// Tests that if SetVisible(true) is called while animating to hidden that the -// tray becomes visible, and stops animating to hidden. -TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->visible()); - - std::unique_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration; - animation_duration.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::SLOW_DURATION)); - tray->SetVisible(false); - EXPECT_TRUE(tray->visible()); - EXPECT_EQ(0.0f, tray->layer()->GetTargetOpacity()); - - tray->SetVisible(true); - animation_duration.reset(); - tray->layer()->GetAnimator()->StopAnimating(); - EXPECT_TRUE(tray->visible()); - EXPECT_EQ(1.0f, tray->layer()->GetTargetOpacity()); -} - -TEST_F(SystemTrayTest, SystemTrayHeightWithBubble) { - SystemTray* tray = GetPrimarySystemTray(); - WebNotificationTray* notification_tray = - StatusAreaWidgetTestHelper::GetStatusAreaWidget() - ->web_notification_tray(); - - // Ensure the initial tray bubble height is zero. - EXPECT_EQ(0, notification_tray->tray_bubble_height_for_test()); - - // Show the default view, ensure the tray bubble height is changed. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - EXPECT_LT(0, notification_tray->tray_bubble_height_for_test()); - - // Hide the default view, ensure the tray bubble height is back to zero. - ASSERT_TRUE(tray->CloseSystemBubble()); - RunAllPendingInMessageLoop(); - - EXPECT_EQ(0, notification_tray->tray_bubble_height_for_test()); -} - -TEST_F(SystemTrayTest, SeparatorThickness) { - EXPECT_EQ(kSeparatorWidth, views::Separator::kThickness); -} - -} // namespace test -} // namespace ash
diff --git a/ash/system/tray/throbber_view.cc b/ash/system/tray/throbber_view.cc deleted file mode 100644 index b6c02d8..0000000 --- a/ash/system/tray/throbber_view.cc +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/throbber_view.h" - -#include "ash/resources/grit/ash_resources.h" -#include "ash/system/tray/tray_constants.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" - -namespace ash { -namespace { - -// Duration for showing/hiding animation in milliseconds. -const int kThrobberAnimationDurationMs = 200; - -} // namespace - -SystemTrayThrobber::SystemTrayThrobber() : views::SmoothedThrobber() {} - -SystemTrayThrobber::~SystemTrayThrobber() {} - -void SystemTrayThrobber::SetTooltipText(const base::string16& tooltip_text) { - tooltip_text_ = tooltip_text; -} - -bool SystemTrayThrobber::GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const { - if (tooltip_text_.empty()) - return false; - - *tooltip = tooltip_text_; - return true; -} - -ThrobberView::ThrobberView() { - throbber_ = new SystemTrayThrobber(); - throbber_->set_stop_delay_ms(kThrobberAnimationDurationMs); - AddChildView(throbber_); - - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetOpacity(0.0); -} - -ThrobberView::~ThrobberView() {} - -gfx::Size ThrobberView::GetPreferredSize() const { - return gfx::Size(kTrayPopupItemMinHeight, kTrayPopupItemMinHeight); -} - -void ThrobberView::Layout() { - View* child = child_at(0); - gfx::Size ps = child->GetPreferredSize(); - child->SetBounds((width() - ps.width()) / 2, (height() - ps.height()) / 2, - ps.width(), ps.height()); - SizeToPreferredSize(); -} - -bool ThrobberView::GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const { - if (tooltip_text_.empty()) - return false; - - *tooltip = tooltip_text_; - return true; -} - -void ThrobberView::Start() { - ScheduleAnimation(true); - throbber_->Start(); -} - -void ThrobberView::Stop() { - ScheduleAnimation(false); - throbber_->Stop(); -} - -void ThrobberView::SetTooltipText(const base::string16& tooltip_text) { - tooltip_text_ = tooltip_text; - throbber_->SetTooltipText(tooltip_text); -} - -void ThrobberView::ScheduleAnimation(bool start_throbber) { - // Stop any previous animation. - layer()->GetAnimator()->StopAnimating(); - - ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); - animation.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kThrobberAnimationDurationMs)); - - layer()->SetOpacity(start_throbber ? 1.0 : 0.0); -} - -} // namespace ash
diff --git a/ash/system/tray/throbber_view.h b/ash/system/tray/throbber_view.h deleted file mode 100644 index 9faf3bf..0000000 --- a/ash/system/tray/throbber_view.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_THROBBER_VIEW_H_ -#define ASH_SYSTEM_TRAY_THROBBER_VIEW_H_ - -#include "base/macros.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/controls/throbber.h" -#include "ui/views/view.h" - -namespace ash { - -// A SmoothedThrobber with tooltip. -class SystemTrayThrobber : public views::SmoothedThrobber { - public: - SystemTrayThrobber(); - ~SystemTrayThrobber() override; - - void SetTooltipText(const base::string16& tooltip_text); - - // Overriden from views::View. - bool GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const override; - - private: - // The current tooltip text. - base::string16 tooltip_text_; - - DISALLOW_COPY_AND_ASSIGN(SystemTrayThrobber); -}; - -// A View containing a SystemTrayThrobber with animation for starting/stopping. -class ThrobberView : public views::View { - public: - ThrobberView(); - ~ThrobberView() override; - - void Start(); - void Stop(); - void SetTooltipText(const base::string16& tooltip_text); - - // Overriden from views::View. - gfx::Size GetPreferredSize() const override; - void Layout() override; - bool GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const override; - - private: - // Schedules animation for starting/stopping throbber. - void ScheduleAnimation(bool start_throbber); - - SystemTrayThrobber* throbber_; - - // The current tooltip text. - base::string16 tooltip_text_; - - DISALLOW_COPY_AND_ASSIGN(ThrobberView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_THROBBER_VIEW_H_
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc deleted file mode 100644 index 326c4a2..0000000 --- a/ash/system/tray/tray_background_view.cc +++ /dev/null
@@ -1,622 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_background_view.h" - -#include <algorithm> - -#include "ash/common/ash_constants.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_event_filter.h" -#include "base/memory/ptr_util.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/nine_image_painter_factory.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animation_element.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/events/event_constants.h" -#include "ui/gfx/animation/tween.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/gfx/nine_image_painter.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/gfx/skia_util.h" -#include "ui/gfx/transform.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_highlight.h" -#include "ui/views/animation/ink_drop_mask.h" -#include "ui/views/background.h" -#include "ui/views/layout/box_layout.h" -#include "ui/wm/core/window_animations.h" - -namespace { - -const int kAnimationDurationForPopupMs = 200; - -// Duration of opacity animation for visibility changes. -const int kAnimationDurationForVisibilityMs = 250; - -// When becoming visible delay the animation so that StatusAreaWidgetDelegate -// can animate sibling views out of the position to be occuped by the -// TrayBackgroundView. -const int kShowAnimationDelayMs = 100; - -// Additional padding used to adjust the user-visible size of status tray -// and overview button dark background. -const int kBackgroundAdjustPadding = 3; - -// Switches left and right insets if RTL mode is active. -void MirrorInsetsIfNecessary(gfx::Insets* insets) { - if (base::i18n::IsRTL()) { - insets->Set(insets->top(), insets->right(), insets->bottom(), - insets->left()); - } -} - -// Returns background insets relative to the contents bounds of the view and -// mirrored if RTL mode is active. -gfx::Insets GetMirroredBackgroundInsets(ash::ShelfAlignment shelf_alignment) { - gfx::Insets insets; - if (IsHorizontalAlignment(shelf_alignment)) { - insets.Set(0, ash::kHitRegionPadding, 0, - ash::kHitRegionPadding + ash::kSeparatorWidth); - } else { - insets.Set(ash::kHitRegionPadding, 0, - ash::kHitRegionPadding + ash::kSeparatorWidth, 0); - } - MirrorInsetsIfNecessary(&insets); - return insets; -} - -} // namespace - -using views::TrayBubbleView; - -namespace ash { - -// static -const char TrayBackgroundView::kViewClassName[] = "tray/TrayBackgroundView"; - -// Used to track when the anchor widget changes position on screen so that the -// bubble position can be updated. -class TrayBackgroundView::TrayWidgetObserver : public views::WidgetObserver { - public: - explicit TrayWidgetObserver(TrayBackgroundView* host) : host_(host) {} - - void OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) override { - host_->AnchorUpdated(); - } - - void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override { - host_->AnchorUpdated(); - } - - private: - TrayBackgroundView* host_; - - DISALLOW_COPY_AND_ASSIGN(TrayWidgetObserver); -}; - -class TrayBackground : public views::Background { - public: - TrayBackground(TrayBackgroundView* tray_background_view, bool draws_active) - : tray_background_view_(tray_background_view), - draws_active_(draws_active), - color_(SK_ColorTRANSPARENT) {} - - ~TrayBackground() override {} - - void set_color(SkColor color) { color_ = color; } - - private: - WmShelf* GetShelf() const { return tray_background_view_->shelf(); } - - void PaintMaterial(gfx::Canvas* canvas, views::View* view) const { - cc::PaintFlags background_flags; - background_flags.setAntiAlias(true); - background_flags.setColor(color_); - gfx::Insets insets = - GetMirroredBackgroundInsets(GetShelf()->GetAlignment()); - gfx::Rect bounds = view->GetLocalBounds(); - bounds.Inset(insets); - canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, background_flags); - - if (draws_active_ && tray_background_view_->is_active()) { - cc::PaintFlags highlight_flags; - highlight_flags.setAntiAlias(true); - highlight_flags.setColor(kShelfButtonActivatedHighlightColor); - canvas->DrawRoundRect(bounds, kTrayRoundedBorderRadius, highlight_flags); - } - } - - void PaintNonMaterial(gfx::Canvas* canvas, views::View* view) const { - const static int kImageTypeDefault = 0; - // TODO(estade): leftover type which should be removed along with the rest - // of pre-MD code. - // const static int kImageTypeOnBlack = 1; - const static int kImageTypePressed = 2; - const static int kNumStates = 3; - - const static int kImageHorizontal = 0; - const static int kImageVertical = 1; - const static int kNumOrientations = 2; - - const int kGridSizeForPainter = 9; - - const int kImages[kNumOrientations][kNumStates][kGridSizeForPainter] = { - { - // Horizontal - IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ), - IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_ONBLACK), - IMAGE_GRID_HORIZONTAL(IDR_AURA_TRAY_BG_HORIZ_PRESSED), - }, - { - // Vertical - IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL), - IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_ONBLACK), - IMAGE_GRID_VERTICAL(IDR_AURA_TRAY_BG_VERTICAL_PRESSED), - }}; - - WmShelf* shelf = GetShelf(); - const int orientation = IsHorizontalAlignment(shelf->GetAlignment()) - ? kImageHorizontal - : kImageVertical; - - int state = kImageTypeDefault; - if (draws_active_ && tray_background_view_->is_active()) - state = kImageTypePressed; - else - state = kImageTypeDefault; - - ui::CreateNineImagePainter(kImages[orientation][state]) - ->Paint(canvas, view->GetLocalBounds()); - } - - // Overridden from views::Background. - void Paint(gfx::Canvas* canvas, views::View* view) const override { - if (MaterialDesignController::IsShelfMaterial()) - PaintMaterial(canvas, view); - else - PaintNonMaterial(canvas, view); - } - - // Reference to the TrayBackgroundView for which this is a background. - TrayBackgroundView* tray_background_view_; - - // Determines whether we should draw an active background for the view when it - // is active. This is used in non-MD mode. In material design mode, an active - // ink drop ripple would indicate if the view is active or not. - // TODO(mohsen): This is used only in non-MD version. Remove when non-MD code - // is removed (see https://crbug.com/614453). - bool draws_active_; - - SkColor color_; - - DISALLOW_COPY_AND_ASSIGN(TrayBackground); -}; - -TrayBackgroundView::TrayContainer::TrayContainer(ShelfAlignment alignment) - : alignment_(alignment) { - UpdateLayout(); -} - -void TrayBackgroundView::TrayContainer::SetAlignment(ShelfAlignment alignment) { - if (alignment_ == alignment) - return; - alignment_ = alignment; - UpdateLayout(); -} - -void TrayBackgroundView::TrayContainer::SetMargin(int main_axis_margin, - int cross_axis_margin) { - main_axis_margin_ = main_axis_margin; - cross_axis_margin_ = cross_axis_margin; - UpdateLayout(); -} - -void TrayBackgroundView::TrayContainer::ChildPreferredSizeChanged( - views::View* child) { - PreferredSizeChanged(); -} - -void TrayBackgroundView::TrayContainer::ChildVisibilityChanged(View* child) { - PreferredSizeChanged(); -} - -void TrayBackgroundView::TrayContainer::ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) { - if (details.parent == this) - PreferredSizeChanged(); -} - -void TrayBackgroundView::TrayContainer::UpdateLayout() { - bool is_horizontal = IsHorizontalAlignment(alignment_); - - // Adjust the size of status tray dark background by adding additional - // empty border. - views::BoxLayout::Orientation orientation = - is_horizontal ? views::BoxLayout::kHorizontal - : views::BoxLayout::kVertical; - - if (ash::MaterialDesignController::IsShelfMaterial()) { - const int hit_region_with_separator = kHitRegionPadding + kSeparatorWidth; - gfx::Insets insets( - is_horizontal - ? gfx::Insets(0, kHitRegionPadding, 0, hit_region_with_separator) - : gfx::Insets(kHitRegionPadding, 0, hit_region_with_separator, 0)); - MirrorInsetsIfNecessary(&insets); - SetBorder(views::CreateEmptyBorder(insets)); - } else { - SetBorder(views::CreateEmptyBorder(gfx::Insets(kBackgroundAdjustPadding))); - } - - int horizontal_margin = main_axis_margin_; - int vertical_margin = cross_axis_margin_; - if (!is_horizontal) - std::swap(horizontal_margin, vertical_margin); - views::BoxLayout* layout = - new views::BoxLayout(orientation, horizontal_margin, vertical_margin, 0); - - if (!ash::MaterialDesignController::IsShelfMaterial()) - layout->SetDefaultFlex(1); - layout->set_minimum_cross_axis_size(kTrayItemSize); - views::View::SetLayoutManager(layout); - - PreferredSizeChanged(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TrayBackgroundView - -TrayBackgroundView::TrayBackgroundView(WmShelf* wm_shelf) - // Note the ink drop style is ignored. - : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), - wm_shelf_(wm_shelf), - tray_container_(NULL), - shelf_alignment_(SHELF_ALIGNMENT_BOTTOM), - background_(NULL), - is_active_(false), - separator_visible_(true), - widget_observer_(new TrayWidgetObserver(this)) { - DCHECK(wm_shelf_); - set_notify_enter_exit_on_child(true); - set_ink_drop_base_color(kShelfInkDropBaseColor); - set_ink_drop_visible_opacity(kShelfInkDropVisibleOpacity); - - tray_container_ = new TrayContainer(shelf_alignment_); - SetContents(tray_container_); - tray_event_filter_.reset(new TrayEventFilter); - - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - // Start the tray items not visible, because visibility changes are animated. - views::View::SetVisible(false); -} - -TrayBackgroundView::~TrayBackgroundView() { - if (GetWidget()) - GetWidget()->RemoveObserver(widget_observer_.get()); - StopObservingImplicitAnimations(); -} - -void TrayBackgroundView::Initialize() { - GetWidget()->AddObserver(widget_observer_.get()); -} - -// static -void TrayBackgroundView::InitializeBubbleAnimations( - views::Widget* bubble_widget) { - WmWindow* window = WmWindow::Get(bubble_widget->GetNativeWindow()); - window->SetVisibilityAnimationType( - ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); - window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE); - window->SetVisibilityAnimationDuration( - base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs)); -} - -void TrayBackgroundView::SetVisible(bool visible) { - if (visible == layer()->GetTargetVisibility()) - return; - - if (visible) { - // The alignment of the shelf can change while the TrayBackgroundView is - // hidden. Reset the offscreen transform so that the animation to becoming - // visible reflects the current layout. - HideTransformation(); - // SetVisible(false) is defered until the animation for hiding is done. - // Otherwise the view is immediately hidden and the animation does not - // render. - views::View::SetVisible(true); - // If SetVisible(true) is called while animating to not visible, then - // views::View::SetVisible(true) is a no-op. When the previous animation - // ends layer->SetVisible(false) is called. To prevent this - // layer->SetVisible(true) immediately interrupts the animation of this - // property, and keeps the layer visible. - layer()->SetVisible(true); - } - - ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator()); - animation.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kAnimationDurationForVisibilityMs)); - animation.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - - if (visible) { - animation.SetTweenType(gfx::Tween::EASE_OUT); - // Show is delayed so as to allow time for other children of - // StatusAreaWidget to begin animating to their new positions. - layer()->GetAnimator()->SchedulePauseForProperties( - base::TimeDelta::FromMilliseconds(kShowAnimationDelayMs), - ui::LayerAnimationElement::OPACITY | - ui::LayerAnimationElement::TRANSFORM); - layer()->SetOpacity(1.0f); - gfx::Transform transform; - transform.Translate(0.0f, 0.0f); - layer()->SetTransform(transform); - } else { - // Listen only to the hide animation. As we cannot turn off visibility - // until the animation is over. - animation.AddObserver(this); - animation.SetTweenType(gfx::Tween::EASE_IN); - layer()->SetOpacity(0.0f); - layer()->SetVisible(false); - HideTransformation(); - } -} - -const char* TrayBackgroundView::GetClassName() const { - return kViewClassName; -} - -void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) { - PreferredSizeChanged(); -} - -void TrayBackgroundView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - ActionableView::GetAccessibleNodeData(node_data); - node_data->SetName(GetAccessibleNameForTray()); -} - -void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) { - // Return focus to the login view. See crbug.com/120500. - views::View* v = GetNextFocusableView(); - if (v) - v->AboutToRequestFocusFromTabTraversal(reverse); -} - -std::unique_ptr<views::InkDropRipple> TrayBackgroundView::CreateInkDropRipple() - const { - return base::MakeUnique<views::FloodFillInkDropRipple>( - size(), GetBackgroundInsets(), GetInkDropCenterBasedOnLastEvent(), - GetInkDropBaseColor(), ink_drop_visible_opacity()); -} - -std::unique_ptr<views::InkDropHighlight> -TrayBackgroundView::CreateInkDropHighlight() const { - gfx::Rect bounds = GetBackgroundBounds(); - // Currently, we don't handle view resize. To compensate for that, enlarge the - // bounds by two tray icons so that the hightlight looks good even if two more - // icons are added when it is visible. Note that ink drop mask handles resize - // correctly, so the extra highlight would be clipped. - // TODO(mohsen): Remove this extra size when resize is handled properly (see - // https://crbug.com/669253). - const int icon_size = kTrayIconSize + 2 * kTrayImageItemPadding; - bounds.set_width(bounds.width() + 2 * icon_size); - bounds.set_height(bounds.height() + 2 * icon_size); - std::unique_ptr<views::InkDropHighlight> highlight( - new views::InkDropHighlight(bounds.size(), 0, - gfx::RectF(bounds).CenterPoint(), - GetInkDropBaseColor())); - highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity); - return highlight; -} - -void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) { - // If there is no ink drop, show "touch feedback". - // TODO(mohsen): This is used only in non-MD version. Remove when non-MD code - // is removed (see https://crbug.com/614453). - if (ink_drop_mode() == InkDropMode::OFF) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetIsActive(true); - } else if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN || - event->type() == ui::ET_GESTURE_TAP_CANCEL) { - SetIsActive(false); - } - } - ActionableView::OnGestureEvent(event); -} - -void TrayBackgroundView::SetContents(views::View* contents) { - SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); - AddChildView(contents); -} - -void TrayBackgroundView::SetContentsBackground(bool draws_active) { - background_ = new TrayBackground(this, draws_active); - tray_container_->set_background(background_); -} - -void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) { - shelf_alignment_ = alignment; - tray_container_->SetAlignment(alignment); -} - -void TrayBackgroundView::OnImplicitAnimationsCompleted() { - // If there is another animation in the queue, the reverse animation was - // triggered before the completion of animating to invisible. Do not turn off - // the visibility so that the next animation may render. The value of - // layer()->GetTargetVisibility() can be incorrect if the hide animation was - // aborted to schedule an animation to become visible. As the new animation - // is not yet added to the queue. crbug.com/374236 - if (layer()->GetAnimator()->is_animating() || layer()->GetTargetVisibility()) - return; - views::View::SetVisible(false); -} - -bool TrayBackgroundView::RequiresNotificationWhenAnimatorDestroyed() const { - // This is needed so that OnImplicitAnimationsCompleted() is called even upon - // destruction of the animator. This can occure when parallel animations - // caused by ScreenRotationAnimator end before the animations of - // TrayBackgroundView. This allows for a proper update to the visual state of - // the view. (crbug.com/476667) - return true; -} - -void TrayBackgroundView::HideTransformation() { - gfx::Transform transform; - if (IsHorizontalAlignment(shelf_alignment_)) - transform.Translate(width(), 0.0f); - else - transform.Translate(0.0f, height()); - layer()->SetTransform(transform); -} - -TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const { - if (shelf_alignment_ == SHELF_ALIGNMENT_LEFT) - return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT; - if (shelf_alignment_ == SHELF_ALIGNMENT_RIGHT) - return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT; - return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM; -} - -void TrayBackgroundView::SetIsActive(bool is_active) { - if (is_active_ == is_active) - return; - is_active_ = is_active; - AnimateInkDrop(is_active_ ? views::InkDropState::ACTIVATED - : views::InkDropState::DEACTIVATED, - nullptr); - if (!background_) - return; - // TODO(mohsen): This is needed for non-MD version. Remove when non-MD code is - // removed (see https://crbug.com/614453). - SchedulePaint(); -} - -void TrayBackgroundView::UpdateBubbleViewArrow( - views::TrayBubbleView* bubble_view) { - // Nothing to do here. -} - -void TrayBackgroundView::UpdateShelfItemBackground(SkColor color) { - if (background_) { - background_->set_color(color); - SchedulePaint(); - } -} - -views::View* TrayBackgroundView::GetBubbleAnchor() const { - return tray_container_; -} - -gfx::Insets TrayBackgroundView::GetBubbleAnchorInsets() const { - gfx::Insets anchor_insets = GetBubbleAnchor()->GetInsets(); - gfx::Insets tray_bg_insets = GetInsets(); - if (GetAnchorAlignment() == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) { - return gfx::Insets(-tray_bg_insets.top(), anchor_insets.left(), - -tray_bg_insets.bottom(), anchor_insets.right()); - } else { - return gfx::Insets(anchor_insets.top(), -tray_bg_insets.left(), - anchor_insets.bottom(), -tray_bg_insets.right()); - } -} - -std::unique_ptr<views::InkDropMask> TrayBackgroundView::CreateInkDropMask() - const { - return base::MakeUnique<views::RoundRectInkDropMask>( - size(), GetBackgroundInsets(), kTrayRoundedBorderRadius); -} - -bool TrayBackgroundView::ShouldEnterPushedState(const ui::Event& event) { - if (is_active_) - return false; - - return ActionableView::ShouldEnterPushedState(event); -} - -bool TrayBackgroundView::PerformAction(const ui::Event& event) { - return false; -} - -void TrayBackgroundView::HandlePerformActionResult(bool action_performed, - const ui::Event& event) { - // When an action is performed, ink drop ripple is handled in SetIsActive(). - if (action_performed) - return; - ActionableView::HandlePerformActionResult(action_performed, event); -} - -void TrayBackgroundView::OnPaintFocus(gfx::Canvas* canvas) { - // The tray itself expands to the right and bottom edge of the screen to make - // sure clicking on the edges brings up the popup. However, the focus border - // should be only around the container. - gfx::RectF paint_bounds; - paint_bounds = gfx::RectF(GetBackgroundBounds()); - paint_bounds.Inset(gfx::Insets(-kFocusBorderThickness)); - canvas->DrawSolidFocusRect(paint_bounds, kFocusBorderColor, - kFocusBorderThickness); -} - -void TrayBackgroundView::OnPaint(gfx::Canvas* canvas) { - ActionableView::OnPaint(canvas); - if (shelf()->GetBackgroundType() == - ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT || - !separator_visible_) { - return; - } - // In the given |canvas|, for a horizontal shelf draw a separator line to the - // right or left of the TrayBackgroundView when the system is LTR or RTL - // aligned, respectively. For a vertical shelf draw the separator line - // underneath the items instead. - const gfx::Rect local_bounds = GetLocalBounds(); - const SkColor color = SkColorSetA(SK_ColorWHITE, 0x4D); - - if (IsHorizontalAlignment(shelf_alignment_)) { - const gfx::PointF point( - base::i18n::IsRTL() ? 0 : (local_bounds.width() - kSeparatorWidth), - (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2); - const gfx::Vector2dF vector(0, kTrayItemSize); - canvas->Draw1pxLine(point, point + vector, color); - } else { - const gfx::PointF point((GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2, - local_bounds.height() - kSeparatorWidth); - const gfx::Vector2dF vector(kTrayItemSize, 0); - canvas->Draw1pxLine(point, point + vector, color); - } -} - -gfx::Insets TrayBackgroundView::GetBackgroundInsets() const { - gfx::Insets insets = GetMirroredBackgroundInsets(shelf_alignment_); - - // |insets| are relative to contents bounds. Change them to be relative to - // local bounds. - gfx::Insets local_contents_insets = - GetLocalBounds().InsetsFrom(GetContentsBounds()); - MirrorInsetsIfNecessary(&local_contents_insets); - insets += local_contents_insets; - - return insets; -} - -gfx::Rect TrayBackgroundView::GetBackgroundBounds() const { - gfx::Insets insets = GetBackgroundInsets(); - gfx::Rect bounds = GetLocalBounds(); - bounds.Inset(insets); - return bounds; -} - -} // namespace ash
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h deleted file mode 100644 index 1e5280d..0000000 --- a/ash/system/tray/tray_background_view.h +++ /dev/null
@@ -1,197 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_ -#define ASH_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "ash/system/tray/actionable_view.h" -#include "base/macros.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/views/bubble/tray_bubble_view.h" - -namespace ash { -class TrayEventFilter; -class TrayBackground; -class WmShelf; - -// Base class for children of StatusAreaWidget: SystemTray, WebNotificationTray, -// LogoutButtonTray, OverviewButtonTray. -// This class handles setting and animating the background when the Launcher -// is shown/hidden. It also inherits from ActionableView so that the tray -// items can override PerformAction when clicked on. -class ASH_EXPORT TrayBackgroundView : public ActionableView, - public ui::ImplicitAnimationObserver, - public ShelfBackgroundAnimatorObserver { - public: - static const char kViewClassName[]; - - // Base class for tray containers. Sets the border and layout. The container - // auto-resizes the widget when necessary. - class TrayContainer : public views::View { - public: - explicit TrayContainer(ShelfAlignment alignment); - ~TrayContainer() override {} - - void SetAlignment(ShelfAlignment alignment); - - void SetMargin(int main_axis_margin, int cross_axis_margin); - - protected: - // views::View: - void ChildPreferredSizeChanged(views::View* child) override; - void ChildVisibilityChanged(View* child) override; - void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) override; - - private: - void UpdateLayout(); - - ShelfAlignment alignment_; - int main_axis_margin_ = 0; - int cross_axis_margin_ = 0; - - DISALLOW_COPY_AND_ASSIGN(TrayContainer); - }; - - explicit TrayBackgroundView(WmShelf* wm_shelf); - ~TrayBackgroundView() override; - - // Called after the tray has been added to the widget containing it. - virtual void Initialize(); - - // Initializes animations for the bubble. - static void InitializeBubbleAnimations(views::Widget* bubble_widget); - - // views::View: - void SetVisible(bool visible) override; - const char* GetClassName() const override; - void ChildPreferredSizeChanged(views::View* child) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void AboutToRequestFocusFromTabTraversal(bool reverse) override; - void OnPaint(gfx::Canvas* canvas) override; - - // ActionableView: - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() - const override; - void OnGestureEvent(ui::GestureEvent* event) override; - - // Called whenever the shelf alignment changes. - virtual void SetShelfAlignment(ShelfAlignment alignment); - - // Called when the anchor (tray or bubble) may have moved or changed. - virtual void AnchorUpdated() {} - - // Called from GetAccessibleNodeData, must return a valid accessible name. - virtual base::string16 GetAccessibleNameForTray() = 0; - - // Called when the bubble is resized. - virtual void BubbleResized(const views::TrayBubbleView* bubble_view) {} - - // Hides the bubble associated with |bubble_view|. Called when the widget - // is closed. - virtual void HideBubbleWithView(const views::TrayBubbleView* bubble_view) = 0; - - // Called by the bubble wrapper when a click event occurs outside the bubble. - // May close the bubble. - virtual void ClickedOutsideBubble() = 0; - - // Sets |contents| as a child. - void SetContents(views::View* contents); - - // Creates and sets contents background to |background_|. |draws_active| - // determines if the view's background should be drawn as active when the view - // is in the active state. - void SetContentsBackground(bool draws_active); - - // Returns the bubble anchor alignment based on |shelf_alignment_|. - views::TrayBubbleView::AnchorAlignment GetAnchorAlignment() const; - - void SetIsActive(bool is_active); - bool is_active() const { return is_active_; } - - TrayContainer* tray_container() const { return tray_container_; } - ShelfAlignment shelf_alignment() const { return shelf_alignment_; } - TrayEventFilter* tray_event_filter() { return tray_event_filter_.get(); } - WmShelf* shelf() { return wm_shelf_; } - - // Updates the arrow visibility based on the launcher visibility. - void UpdateBubbleViewArrow(views::TrayBubbleView* bubble_view); - - // ShelfBackgroundAnimatorObserver: - void UpdateShelfItemBackground(SkColor color) override; - - // Updates the visibility of this tray's separator. - void set_separator_visibility(bool visible) { separator_visible_ = visible; } - - // Gets the anchor for bubbles, which is tray_container(). - views::View* GetBubbleAnchor() const; - - // Gets additional insets for positioning bubbles relative to - // tray_container(). - gfx::Insets GetBubbleAnchorInsets() const; - - protected: - // ActionableView: - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; - bool ShouldEnterPushedState(const ui::Event& event) override; - bool PerformAction(const ui::Event& event) override; - void HandlePerformActionResult(bool action_performed, - const ui::Event& event) override; - void OnPaintFocus(gfx::Canvas* canvas) override; - - private: - class TrayWidgetObserver; - - // ui::ImplicitAnimationObserver: - void OnImplicitAnimationsCompleted() override; - bool RequiresNotificationWhenAnimatorDestroyed() const override; - - // Applies transformations to the |layer()| to animate the view when - // SetVisible(false) is called. - void HideTransformation(); - - // Helper function that calculates background insets relative to local bounds. - gfx::Insets GetBackgroundInsets() const; - - // Helper function that calculates background bounds relative to local bounds - // based on background insets returned from GetBackgroundInsets(). - gfx::Rect GetBackgroundBounds() const; - - // The shelf containing the system tray for this view. - WmShelf* wm_shelf_; - - // Convenience pointer to the contents view. - TrayContainer* tray_container_; - - // Shelf alignment. - // TODO(jamescook): Don't cache this, get it from WmShelf. - ShelfAlignment shelf_alignment_; - - // Owned by the view passed to SetContents(). - TrayBackground* background_; - - // Determines if the view is active. This changes how the background is drawn - // in non-MD version and how the ink drop ripples behave in MD version. - bool is_active_; - - // Visibility of this tray's separator which is a line of 1x32px and 4px to - // right of tray. - bool separator_visible_; - - std::unique_ptr<TrayWidgetObserver> widget_observer_; - std::unique_ptr<TrayEventFilter> tray_event_filter_; - - DISALLOW_COPY_AND_ASSIGN(TrayBackgroundView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_BACKGROUND_VIEW_H_
diff --git a/ash/system/tray/tray_bubble_wrapper.cc b/ash/system/tray/tray_bubble_wrapper.cc deleted file mode 100644 index df43f91..0000000 --- a/ash/system/tray/tray_bubble_wrapper.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_bubble_wrapper.h" - -#include "ash/common/wm_window.h" -#include "ash/system/tray/tray_background_view.h" -#include "ash/system/tray/tray_event_filter.h" -#include "ui/views/bubble/tray_bubble_view.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -TrayBubbleWrapper::TrayBubbleWrapper(TrayBackgroundView* tray, - views::TrayBubbleView* bubble_view) - : tray_(tray), bubble_view_(bubble_view) { - bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_); - bubble_widget_->AddObserver(this); - - TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_); - tray_->UpdateBubbleViewArrow(bubble_view_); - bubble_view_->InitializeAndShowBubble(); - - tray->tray_event_filter()->AddWrapper(this); -} - -TrayBubbleWrapper::~TrayBubbleWrapper() { - tray_->tray_event_filter()->RemoveWrapper(this); - if (bubble_widget_) { - bubble_widget_->RemoveObserver(this); - bubble_widget_->Close(); - } -} - -void TrayBubbleWrapper::OnWidgetDestroying(views::Widget* widget) { - CHECK_EQ(bubble_widget_, widget); - bubble_widget_->RemoveObserver(this); - bubble_widget_ = NULL; - - // Although the bubble is already closed, the next mouse release event - // will invoke PerformAction which reopens the bubble again. To prevent the - // reopen, the mouse capture of |tray_| has to be released. - // See crbug.com/177075 - WmWindow::Get(tray_->GetWidget()->GetNativeWindow())->ReleaseCapture(); - - tray_->HideBubbleWithView(bubble_view_); // May destroy |bubble_view_| -} - -void TrayBubbleWrapper::OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) { - DCHECK_EQ(bubble_widget_, widget); - tray_->BubbleResized(bubble_view_); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_bubble_wrapper.h b/ash/system/tray/tray_bubble_wrapper.h deleted file mode 100644 index 2a4f3ffa..0000000 --- a/ash/system/tray/tray_bubble_wrapper.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_ -#define ASH_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_ - -#include "base/macros.h" -#include "ui/views/widget/widget_observer.h" - -namespace views { -class TrayBubbleView; -} - -namespace ash { -class TrayBackgroundView; - -// Creates and manages the Widget and EventFilter components of a bubble. - -class TrayBubbleWrapper : public views::WidgetObserver { - public: - TrayBubbleWrapper(TrayBackgroundView* tray, - views::TrayBubbleView* bubble_view); - ~TrayBubbleWrapper() override; - - // views::WidgetObserver overrides: - void OnWidgetDestroying(views::Widget* widget) override; - void OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) override; - - const TrayBackgroundView* tray() const { return tray_; } - TrayBackgroundView* tray() { return tray_; } - views::TrayBubbleView* bubble_view() { return bubble_view_; } - const views::TrayBubbleView* bubble_view() const { return bubble_view_; } - views::Widget* bubble_widget() { return bubble_widget_; } - const views::Widget* bubble_widget() const { return bubble_widget_; } - - private: - TrayBackgroundView* tray_; - views::TrayBubbleView* bubble_view_; // unowned - views::Widget* bubble_widget_; - - DISALLOW_COPY_AND_ASSIGN(TrayBubbleWrapper); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc deleted file mode 100644 index 71fb49c..0000000 --- a/ash/system/tray/tray_constants.cc +++ /dev/null
@@ -1,115 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_constants.h" - -#include "base/logging.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/color_palette.h" - -namespace ash { - -const int kPaddingFromRightEdgeOfScreenBottomAlignment = 7; -const int kPaddingFromBottomOfScreenBottomAlignment = 7; -const int kPaddingFromOuterEdgeOfLauncherVerticalAlignment = 8; -const int kPaddingFromInnerEdgeOfLauncherVerticalAlignment = 9; -const int kPaddingFromBottomOfScreenVerticalAlignment = 10; - -// Padding used to position the system menu relative to the status area. -const int kBubblePaddingHorizontalBottom = 6; -const int kBubblePaddingHorizontalSide = 10; -const int kBubblePaddingVerticalBottom = 3; -const int kBubblePaddingVerticalSide = 15; - -// Top inset of system tray bubble for bottom anchor alignment. -const int kTrayBubbleAnchorTopInsetBottomAnchor = 3; - -const int kTrayImageItemHorizontalPaddingVerticalAlignment = 1; - -// Size of tray items on the primary axis. -const int kTrayItemSize = 32; - -const int kTrayImageItemPadding = 3; - -const int kTrayLabelItemHorizontalPaddingBottomAlignment = 7; - -// Vertical padding between status tray items when the shelf is vertical. -const int kTrayLabelItemVerticalPaddingVerticalAlignment = 4; - -const int kTrayMenuBottomRowPadding = 3; -const int kTrayMenuBottomRowPaddingBetweenItems = -1; -const int kTrayMenuMinimumWidth = 300; -const int kTrayMenuMinimumWidthMd = 352; - -const int kTrayPopupAutoCloseDelayInSeconds = 2; -const int kTrayPopupAutoCloseDelayForTextInSeconds = 5; -const int kTrayPopupPaddingHorizontal = 18; -const int kTrayPopupPaddingBetweenItems = 10; -const int kTrayPopupButtonEndMargin = 10; -const int kTrayPopupLabelHorizontalPadding = 4; -const int kTrayPopupItemMinHeight = 48; -const int kTrayPopupItemMinStartWidth = 48; -const int kTrayPopupItemMinEndWidth = - kMenuIconSize + 2 * kTrayPopupButtonEndMargin; - -const int kTrayDetailedViewTransitionDelayMs = 100; - -const int kTrayPopupLabelRightPadding = 8; - -const int kTrayPopupDetailsIconWidth = 25; -const int kTrayPopupDetailsLabelExtraLeftMargin = 8; -const SkColor kTrayPopupHoverBackgroundColor = SkColorSetRGB(0xe4, 0xe4, 0xe4); -const int kTrayPopupScrollSeparatorHeight = 15; -const int kTrayRoundedBorderRadius = 2; - -const int kTrayToggleButtonWidth = 68; - -const SkColor kBackgroundColor = SkColorSetRGB(0xfe, 0xfe, 0xfe); -const SkColor kHoverBackgroundColor = SkColorSetRGB(0xf3, 0xf3, 0xf3); -const SkColor kPublicAccountUserCardTextColor = SkColorSetRGB(0x66, 0x66, 0x66); -const SkColor kPublicAccountUserCardNameColor = SK_ColorBLACK; - -const SkColor kHeaderBackgroundColor = SkColorSetRGB(0xf5, 0xf5, 0xf5); - -const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa); -const SkColor kBorderLightColor = SkColorSetRGB(0xeb, 0xeb, 0xeb); -const SkColor kButtonStrokeColor = SkColorSetRGB(0xdd, 0xdd, 0xdd); - -const SkColor kHeaderTextColorNormal = SkColorSetARGB(0x7f, 0, 0, 0); -const SkColor kHeaderTextColorHover = SkColorSetARGB(0xd3, 0, 0, 0); - -const int kTrayPopupMinWidth = 300; -const int kTrayPopupMaxWidth = 500; -const int kNotificationIconWidth = 40; -const int kNotificationButtonWidth = 32; -const int kTrayNotificationContentsWidth = - kTrayPopupMinWidth - (kNotificationIconWidth + kNotificationButtonWidth + - (kTrayPopupPaddingHorizontal / 2) * 3); - -const int kTrayIconSize = 16; -const int kTrayEdgePadding = 6; -const SkColor kTrayIconColor = SK_ColorWHITE; -const int kMenuIconSize = 20; -const SkColor kMenuIconColor = gfx::kChromeIconGrey; -const SkColor kMenuIconColorDisabled = SkColorSetA(gfx::kChromeIconGrey, 0x61); -const int kMenuButtonSize = 48; -const int kMenuSeparatorVerticalPadding = 4; -const int kMenuExtraMarginFromLeftEdge = 4; -const int kMenuEdgeEffectivePadding = - kMenuExtraMarginFromLeftEdge + (kMenuButtonSize - kMenuIconSize) / 2; - -const int kHitRegionPadding = 4; -const int kSeparatorWidth = 1; - -const SkColor kMenuSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); - -const SkColor kTrayPopupInkDropBaseColor = SK_ColorBLACK; -const float kTrayPopupInkDropRippleOpacity = 0.06f; -const float kTrayPopupInkDropHighlightOpacity = 0.08f; -const int kTrayPopupInkDropInset = 4; -const int kTrayPopupInkDropCornerRadius = 2; - -const int kTrayPopupSystemInfoRowHeight = 40; - -} // namespace ash
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h deleted file mode 100644 index 2bd6855..0000000 --- a/ash/system/tray/tray_constants.h +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_CONSTANTS_H_ -#define ASH_SYSTEM_TRAY_TRAY_CONSTANTS_H_ - -#include "ash/ash_export.h" - -typedef unsigned int SkColor; - -namespace ash { - -extern const int kPaddingFromRightEdgeOfScreenBottomAlignment; -extern const int kPaddingFromBottomOfScreenBottomAlignment; -extern const int kPaddingFromOuterEdgeOfLauncherVerticalAlignment; -extern const int kPaddingFromInnerEdgeOfLauncherVerticalAlignment; -extern const int kPaddingFromBottomOfScreenVerticalAlignment; - -extern const int kBubblePaddingHorizontalBottom; -extern const int kBubblePaddingHorizontalSide; -extern const int kBubblePaddingVerticalBottom; -extern const int kBubblePaddingVerticalSide; - -extern const int kTrayBubbleAnchorTopInsetBottomAnchor; - -extern const int kTrayImageItemHorizontalPaddingVerticalAlignment; - -ASH_EXPORT extern const int kTrayItemSize; - -// Extra padding used beside a single icon in the tray area of the shelf. -extern const int kTrayImageItemPadding; - -extern const int kTrayLabelItemHorizontalPaddingBottomAlignment; -extern const int kTrayLabelItemVerticalPaddingVerticalAlignment; - -extern const int kTrayMenuBottomRowPadding; -extern const int kTrayMenuBottomRowPaddingBetweenItems; - -// The minimum width of the tray menu. -extern const int kTrayMenuMinimumWidth; -extern const int kTrayMenuMinimumWidthMd; - -extern const int kTrayPopupAutoCloseDelayInSeconds; -extern const int kTrayPopupAutoCloseDelayForTextInSeconds; -extern const int kTrayPopupPaddingHorizontal; -extern const int kTrayPopupPaddingBetweenItems; -extern const int kTrayPopupButtonEndMargin; -// The padding used on the left and right of labels. This applies to all labels -// in the system menu. -extern const int kTrayPopupLabelHorizontalPadding; - -// The minimum/default height of the rows in the system tray menu. -extern const int kTrayPopupItemMinHeight; - -// The width used for the first region of the row (which holds an image). -extern const int kTrayPopupItemMinStartWidth; - -// The width used for the end region of the row (usually a more arrow). -extern const int kTrayPopupItemMinEndWidth; - -// When transitioning between a detailed and a default view, this delay is used -// before the transition starts. -ASH_EXPORT extern const int kTrayDetailedViewTransitionDelayMs; - -// Padding used on right side of labels to keep minimum distance to the next -// item. This applies to all labels in the system menu. -extern const int kTrayPopupLabelRightPadding; - -extern const int kTrayPopupDetailsIconWidth; -extern const int kTrayPopupDetailsLabelExtraLeftMargin; -extern const SkColor kTrayPopupHoverBackgroundColor; -extern const int kTrayPopupScrollSeparatorHeight; -extern const int kTrayRoundedBorderRadius; - -// The width of ToggleButton views including any border padding. -extern const int kTrayToggleButtonWidth; - -extern const SkColor kBackgroundColor; -extern const SkColor kHoverBackgroundColor; -extern const SkColor kPublicAccountUserCardTextColor; -extern const SkColor kPublicAccountUserCardNameColor; - -extern const SkColor kHeaderBackgroundColor; - -extern const SkColor kBorderDarkColor; -extern const SkColor kBorderLightColor; -extern const SkColor kButtonStrokeColor; - -extern const SkColor kHeaderTextColorNormal; -extern const SkColor kHeaderTextColorHover; - -extern const int kTrayPopupMinWidth; -extern const int kTrayPopupMaxWidth; -extern const int kNotificationIconWidth; -extern const int kNotificationButtonWidth; -extern const int kTrayNotificationContentsWidth; - -// Extra padding used to adjust hitting region around tray items. -extern const int kHitRegionPadding; - -// Width of a line used to separate tray items in the shelf. -ASH_EXPORT extern const int kSeparatorWidth; - -// The color of the separators used in the system menu. -extern const SkColor kMenuSeparatorColor; - -// The size and foreground color of the icons appearing in the material design -// system tray. -extern const int kTrayIconSize; -extern const SkColor kTrayIconColor; - -// The total visual padding at the start and end of the icon/label section -// of the tray. -extern const int kTrayEdgePadding; - -// The size and foreground color of the icons appearing in the material design -// system menu. -extern const int kMenuIconSize; -extern const SkColor kMenuIconColor; -extern const SkColor kMenuIconColorDisabled; -// The size of buttons in the system menu. -ASH_EXPORT extern const int kMenuButtonSize; -// The vertical padding for the system menu separator. -extern const int kMenuSeparatorVerticalPadding; -// The horizontal padding for the system menu separator. -extern const int kMenuExtraMarginFromLeftEdge; -// The visual padding to the left of icons in the system menu. -extern const int kMenuEdgeEffectivePadding; - -// The base color used for all ink drops in the system menu. -extern const SkColor kTrayPopupInkDropBaseColor; - -// The opacity of the ink drop ripples for all ink drops in the system menu. -extern const float kTrayPopupInkDropRippleOpacity; - -// The opacity of the ink drop ripples for all ink highlights in the system -// menu. -extern const float kTrayPopupInkDropHighlightOpacity; - -// The inset applied to clickable surfaces in the system menu that do not have -// the ink drop filling the entire bounds. -extern const int kTrayPopupInkDropInset; - -// The radius used to draw the corners of the rounded rect style ink drops. -extern const int kTrayPopupInkDropCornerRadius; - -// The height of the system info row. -extern const int kTrayPopupSystemInfoRowHeight; - -namespace test { -const int kSettingsTrayItemViewId = 10000; -const int kAccessibilityTrayItemViewId = 10001; -} // namespace test - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_CONSTANTS_H_
diff --git a/ash/system/tray/tray_details_view.cc b/ash/system/tray/tray_details_view.cc deleted file mode 100644 index 54f83fab..0000000 --- a/ash/system/tray/tray_details_view.cc +++ /dev/null
@@ -1,510 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_details_view.h" - -#include "ash/common/ash_view_ids.h" -#include "ash/common/material_design/material_design_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_menu_button.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/containers/adapters.h" -#include "base/memory/ptr_util.h" -#include "third_party/skia/include/core/SkDrawLooper.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/compositor/paint_context.h" -#include "ui/compositor/paint_recorder.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/skia_paint_util.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/progress_bar.h" -#include "ui/views/controls/scroll_view.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/view_targeter.h" -#include "ui/views/view_targeter_delegate.h" - -namespace ash { -namespace { - -bool UseMd() { - return MaterialDesignController::IsSystemTrayMenuMaterial(); -} - -// The index of the horizontal rule below the title row. -const int kTitleRowSeparatorIndex = 1; - -// A view that is used as ScrollView contents. It supports designating some of -// the children as sticky header rows. The sticky header rows are not scrolled -// above the top of the visible viewport until the next one "pushes" it up and -// are painted above other children. To indicate that a child is a sticky header -// row use set_id(VIEW_ID_STICKY_HEADER). -class ScrollContentsView : public views::View { - public: - ScrollContentsView() - : box_layout_(new views::BoxLayout( - views::BoxLayout::kVertical, - 0, - 0, - UseMd() ? 0 : kContentsBetweenChildSpacingNonMd)) { - SetLayoutManager(box_layout_); - } - ~ScrollContentsView() override {} - - protected: - // views::View: - void OnBoundsChanged(const gfx::Rect& previous_bounds) override { - PositionHeaderRows(); - } - - void PaintChildren(const ui::PaintContext& context) override { - views::View::PaintChildren(context); - bool did_draw_shadow = false; - // Paint header row separators. - for (auto& header : headers_) - did_draw_shadow = PaintDelineation(header, context) || did_draw_shadow; - - // Draw a shadow at the top of the viewport when scrolled, but only if a - // header didn't already draw one. Overlap the shadow with the separator - // that's below the header view so we don't get both a separator and a full - // shadow. - if (y() != 0 && !did_draw_shadow) - DrawShadow(context, gfx::Rect(0, 0, width(), -y() - kSeparatorWidth)); - } - - void Layout() override { - views::View::Layout(); - headers_.clear(); - for (int i = 0; i < child_count(); ++i) { - views::View* view = child_at(i); - if (view->id() == VIEW_ID_STICKY_HEADER) - headers_.emplace_back(view); - } - PositionHeaderRows(); - } - - View::Views GetChildrenInZOrder() override { - View::Views children; - // Iterate over regular children and later over the sticky headers to keep - // the sticky headers above in Z-order. - for (int i = 0; i < child_count(); ++i) { - if (child_at(i)->id() != VIEW_ID_STICKY_HEADER) - children.push_back(child_at(i)); - } - for (int i = 0; i < child_count(); ++i) { - if (child_at(i)->id() == VIEW_ID_STICKY_HEADER) - children.push_back(child_at(i)); - } - DCHECK_EQ(child_count(), static_cast<int>(children.size())); - return children; - } - - void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) override { - if (!details.is_add && details.parent == this) { - headers_.erase(std::remove_if(headers_.begin(), headers_.end(), - [details](const Header& header) { - return header.view == details.child; - }), - headers_.end()); - } else if (details.is_add && details.parent == this && - details.child == child_at(0)) { - // We always want padding on the bottom of the scroll contents. - // We only want padding on the top of the scroll contents if the first - // child is not a header (in that case, the padding is built into the - // header). - DCHECK_EQ(box_layout_, GetLayoutManager()); - box_layout_->set_inside_border_insets( - gfx::Insets(details.child->id() == VIEW_ID_STICKY_HEADER - ? 0 - : kMenuSeparatorVerticalPadding, - 0, kMenuSeparatorVerticalPadding, 0)); - } - } - - private: - const int kShadowOffsetY = 2; - const int kShadowBlur = 2; - // TODO(fukino): Remove this constant once we stop maintaining pre-MD design. - // crbug.com/614453. - const int kContentsBetweenChildSpacingNonMd = 1; - - // A structure that keeps the original offset of each header between the - // calls to Layout() to allow keeping track of which view should be sticky. - struct Header { - explicit Header(views::View* view) - : view(view), natural_offset(view->y()), draw_separator_below(false) {} - - // A header View that can be decorated as sticky. - views::View* view; - - // Offset from the top of ScrollContentsView to |view|'s original vertical - // position. - int natural_offset; - - // True when a separator needs to be painted below the header when another - // header is pushing |this| header up. - bool draw_separator_below; - }; - - // Adjusts y-position of header rows allowing one or two rows to stick to the - // top of the visible viewport. - void PositionHeaderRows() { - const int scroll_offset = -y(); - Header* previous_header = nullptr; - for (auto& header : base::Reversed(headers_)) { - views::View* header_view = header.view; - bool draw_separator_below = false; - if (header.natural_offset >= scroll_offset) { - previous_header = &header; - header_view->SetY(header.natural_offset); - } else { - if (previous_header && - previous_header->view->y() <= - scroll_offset + header_view->height()) { - // Lower header displacing the header above. - draw_separator_below = true; - header_view->SetY(previous_header->view->y() - header_view->height()); - } else { - // A header becomes sticky. - header_view->SetY(scroll_offset); - header_view->Layout(); - header_view->SchedulePaint(); - } - } - if (header.draw_separator_below != draw_separator_below) { - header.draw_separator_below = draw_separator_below; - TrayPopupUtils::ShowStickyHeaderSeparator(header_view, - draw_separator_below); - } - if (header.natural_offset < scroll_offset) - break; - } - } - - // Paints a separator for a header view. The separator can be a horizontal - // rule or a horizontal shadow, depending on whether the header is sticking to - // the top of the scroll viewport. The return value indicates whether a shadow - // was drawn. - bool PaintDelineation(const Header& header, const ui::PaintContext& context) { - const View* view = header.view; - - // If the header is where it normally belongs or If the header is pushed by - // a header directly below it, draw nothing. - if (view->y() == header.natural_offset || header.draw_separator_below) - return false; - - // Otherwise, draw a shadow below. - DrawShadow(context, - gfx::Rect(0, 0, view->width(), view->bounds().bottom())); - return true; - } - - // Draws a drop shadow below |shadowed_area|. - void DrawShadow(const ui::PaintContext& context, - const gfx::Rect& shadowed_area) { - ui::PaintRecorder recorder(context, size()); - gfx::Canvas* canvas = recorder.canvas(); - cc::PaintFlags flags; - gfx::ShadowValues shadow; - shadow.emplace_back(gfx::Vector2d(0, kShadowOffsetY), kShadowBlur, - kMenuSeparatorColor); - flags.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow)); - flags.setAntiAlias(true); - canvas->ClipRect(shadowed_area, SkClipOp::kDifference); - canvas->DrawRect(shadowed_area, flags); - } - - views::BoxLayout* box_layout_; - - // Header child views that stick to the top of visible viewport when scrolled. - std::vector<Header> headers_; - - DISALLOW_COPY_AND_ASSIGN(ScrollContentsView); -}; - -// Constants for the title row in material design. -const int kTitleRowVerticalPadding = 4; -const int kTitleRowProgressBarHeight = 2; -const int kTitleRowPaddingTop = kTitleRowVerticalPadding; -const int kTitleRowPaddingBottom = - kTitleRowVerticalPadding - kTitleRowProgressBarHeight; - -class ScrollSeparator : public views::View { - public: - ScrollSeparator() {} - - ~ScrollSeparator() override {} - - private: - // views::View: - void OnPaint(gfx::Canvas* canvas) override { - canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); - } - gfx::Size GetPreferredSize() const override { - return gfx::Size(1, kTrayPopupScrollSeparatorHeight); - } - - DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); -}; - -} // namespace - -class ScrollBorder : public views::Border { - public: - ScrollBorder() {} - ~ScrollBorder() override {} - - void set_visible(bool visible) { visible_ = visible; } - - private: - // views::Border: - void Paint(const views::View& view, gfx::Canvas* canvas) override { - if (!visible_) - return; - canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), - kBorderLightColor); - } - - gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } - - gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } - - bool visible_ = false; - - DISALLOW_COPY_AND_ASSIGN(ScrollBorder); -}; - -TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) - : owner_(owner), - box_layout_(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)), - title_row_(nullptr), - scroller_(nullptr), - scroll_content_(nullptr), - progress_bar_(nullptr), - scroll_border_(nullptr), - tri_view_(nullptr), - back_button_(nullptr) { - SetLayoutManager(box_layout_); - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); -} - -TrayDetailsView::~TrayDetailsView() {} - -void TrayDetailsView::OnViewClicked(views::View* sender) { - if (!UseMd() && title_row_ && sender == title_row_->content()) { - TransitionToDefaultView(); - return; - } - - HandleViewClicked(sender); -} - -void TrayDetailsView::ButtonPressed(views::Button* sender, - const ui::Event& event) { - if (UseMd() && sender == back_button_) { - TransitionToDefaultView(); - return; - } - - HandleButtonPressed(sender, event); -} - -void TrayDetailsView::CreateTitleRow(int string_id) { - DCHECK(!tri_view_); - DCHECK(!title_row_); - - if (UseMd()) { - tri_view_ = TrayPopupUtils::CreateDefaultRowView(); - - back_button_ = CreateBackButton(); - tri_view_->AddView(TriView::Container::START, back_button_); - - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - auto* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(rb.GetLocalizedString(string_id)); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); - style.SetupLabel(label); - tri_view_->AddView(TriView::Container::CENTER, label); - - tri_view_->SetContainerVisible(TriView::Container::END, false); - - tri_view_->SetBorder(views::CreateEmptyBorder(kTitleRowPaddingTop, 0, - kTitleRowPaddingBottom, 0)); - AddChildViewAt(tri_view_, 0); - views::Separator* separator = new views::Separator(); - separator->SetColor(kMenuSeparatorColor); - separator->SetBorder(views::CreateEmptyBorder( - kTitleRowProgressBarHeight - views::Separator::kThickness, 0, 0, 0)); - AddChildViewAt(separator, kTitleRowSeparatorIndex); - } else { - title_row_ = new SpecialPopupRow(); - title_row_->SetTextLabel(string_id, this); - AddChildViewAt(title_row_, child_count()); - } - - CreateExtraTitleRowButtons(); - Layout(); -} - -void TrayDetailsView::CreateScrollableList() { - DCHECK(!scroller_); - scroll_content_ = new ScrollContentsView(); - scroller_ = new views::ScrollView; - scroller_->SetContents(scroll_content_); - // Make the |scroller_| have a layer to clip |scroll_content_|'s children. - // TODO(varkha): Make the sticky rows work with EnableViewPortLayer(). - scroller_->SetPaintToLayer(); - scroller_->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); - scroller_->layer()->SetMasksToBounds(true); - - // Note: |scroller_| takes ownership of |scroll_border_|. - if (!UseMd()) { - // In MD, the scroller is always the last thing, so this border is - // unnecessary and reserves extra space we don't want. - scroll_border_ = new ScrollBorder; - scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); - } - - AddChildView(scroller_); - box_layout_->SetFlexForView(scroller_, 1); -} - -void TrayDetailsView::AddScrollSeparator() { - DCHECK(scroll_content_); - // Do not draw the separator if it is the very first item - // in the scrollable list. - if (scroll_content_->has_children()) - scroll_content_->AddChildView(new ScrollSeparator); -} - -void TrayDetailsView::Reset() { - RemoveAllChildViews(true); - title_row_ = nullptr; - scroller_ = nullptr; - scroll_content_ = nullptr; - progress_bar_ = nullptr; - back_button_ = nullptr; - tri_view_ = nullptr; -} - -void TrayDetailsView::ShowProgress(double value, bool visible) { - DCHECK(UseMd()); - DCHECK(tri_view_); - if (!progress_bar_) { - progress_bar_ = new views::ProgressBar(kTitleRowProgressBarHeight); - progress_bar_->SetVisible(false); - AddChildViewAt(progress_bar_, kTitleRowSeparatorIndex + 1); - } - - progress_bar_->SetValue(value); - progress_bar_->SetVisible(visible); - child_at(kTitleRowSeparatorIndex)->SetVisible(!visible); -} - -views::CustomButton* TrayDetailsView::CreateSettingsButton( - LoginStatus status, - int setting_accessible_name_id) { - DCHECK(UseMd()); - SystemMenuButton* button = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - kSystemMenuSettingsIcon, setting_accessible_name_id); - if (!TrayPopupUtils::CanOpenWebUISettings(status)) - button->SetEnabled(false); - return button; -} - -views::CustomButton* TrayDetailsView::CreateHelpButton(LoginStatus status) { - DCHECK(UseMd()); - SystemMenuButton* button = - new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, - kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); - if (!TrayPopupUtils::CanOpenWebUISettings(status)) - button->SetEnabled(false); - return button; -} - -void TrayDetailsView::HandleViewClicked(views::View* view) { - NOTREACHED(); -} - -void TrayDetailsView::HandleButtonPressed(views::Button* sender, - const ui::Event& event) { - NOTREACHED(); -} - -void TrayDetailsView::CreateExtraTitleRowButtons() {} - -void TrayDetailsView::TransitionToDefaultView() { - if (UseMd()) { - if (back_button_ && back_button_->HasFocus()) - owner_->set_restore_focus(true); - } else { - if (title_row_ && title_row_->content() && - title_row_->content()->HasFocus()) { - owner_->set_restore_focus(true); - } - DoTransitionToDefaultView(); - return; - } - - transition_delay_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kTrayDetailedViewTransitionDelayMs), - this, &TrayDetailsView::DoTransitionToDefaultView); -} - -void TrayDetailsView::DoTransitionToDefaultView() { - // Cache pointer to owner in this function scope. TrayDetailsView will be - // deleted after called ShowDefaultView. - SystemTrayItem* owner = owner_; - owner->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING); - owner->set_restore_focus(false); -} - -views::Button* TrayDetailsView::CreateBackButton() { - DCHECK(UseMd()); - SystemMenuButton* button = new SystemMenuButton( - this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuArrowBackIcon, - IDS_ASH_STATUS_TRAY_PREVIOUS_MENU); - return button; -} - -void TrayDetailsView::Layout() { - views::View::Layout(); - if (scroller_ && !scroller_->is_bounded()) - scroller_->ClipHeightTo(0, scroller_->height()); -} - -int TrayDetailsView::GetHeightForWidth(int width) const { - if (!UseMd() || bounds().IsEmpty()) - return views::View::GetHeightForWidth(width); - - // The height of the bubble that contains this detailed view is set to - // the preferred height of the default view, and that determines the - // initial height of |this|. Always request to stay the same height. - return height(); -} - -void TrayDetailsView::OnPaintBorder(gfx::Canvas* canvas) { - if (scroll_border_) { - int index = GetIndexOf(scroller_); - if (index < child_count() - 1 && child_at(index + 1) != title_row_) - scroll_border_->set_visible(true); - else - scroll_border_->set_visible(false); - } - - views::View::OnPaintBorder(canvas); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_details_view.h b/ash/system/tray/tray_details_view.h deleted file mode 100644 index bddf9a9..0000000 --- a/ash/system/tray/tray_details_view.h +++ /dev/null
@@ -1,145 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_DETAILS_VIEW_H_ -#define ASH_SYSTEM_TRAY_TRAY_DETAILS_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/system/tray/special_popup_row.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/view_click_listener.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" - -namespace views { -class BoxLayout; -class CustomButton; -class ProgressBar; -class ScrollView; -} // namespace views - -namespace ash { -namespace test { -class TrayDetailsViewTest; -} // namespace test - -class ScrollBorder; -class SystemTrayItem; -class TriView; - -class ASH_EXPORT TrayDetailsView : public views::View, - public ViewClickListener, - public views::ButtonListener { - public: - explicit TrayDetailsView(SystemTrayItem* owner); - ~TrayDetailsView() override; - - // ViewClickListener: - // Don't override this --- override HandleViewClicked. - void OnViewClicked(views::View* sender) final; - - // views::ButtonListener: - // Don't override this --- override HandleButtonPressed. - void ButtonPressed(views::Button* sender, const ui::Event& event) final; - - SystemTrayItem* owner() { return owner_; } - SpecialPopupRow* title_row() { return title_row_; } - views::ScrollView* scroller() { return scroller_; } - views::View* scroll_content() { return scroll_content_; } - - protected: - // views::View: - void Layout() override; - int GetHeightForWidth(int width) const override; - void OnPaintBorder(gfx::Canvas* canvas) override; - - // Exposes the layout manager of this view to give control to subclasses. - views::BoxLayout* box_layout() { return box_layout_; } - - // Creates the row containing the back button and title. For material design - // this appears at the top of the view, for non-material design it appears - // at the bottom. - void CreateTitleRow(int string_id); - - // Creates a scrollable list. The list has a border at the bottom if there is - // any other view between the list and the footer row at the bottom. - void CreateScrollableList(); - - // Adds a separator in scrollable list. - void AddScrollSeparator(); - - // Removes (and destroys) all child views. - void Reset(); - - // Shows or hides the progress bar below the title row. It occupies the same - // space as the separator, so when shown the separator is hidden. If - // |progress_bar_| doesn't already exist it will be created. - void ShowProgress(double value, bool visible); - - // Helper functions which create and return the settings and help buttons, - // respectively, used in the material design top-most header row. The caller - // assumes ownership of the returned buttons. - views::CustomButton* CreateSettingsButton(LoginStatus status, - int setting_accessible_name_id); - views::CustomButton* CreateHelpButton(LoginStatus status); - - TriView* tri_view() { return tri_view_; } - - private: - friend class test::TrayDetailsViewTest; - - // Overridden to handle clicks on subclass-specific views. - virtual void HandleViewClicked(views::View* view); - - // Overridden to handle button presses on subclass-specific buttons. - virtual void HandleButtonPressed(views::Button* sender, - const ui::Event& event); - - // Creates and adds subclass-specific buttons to the title row. - virtual void CreateExtraTitleRowButtons(); - - // Transition to default view from details view. If |title_row_| has focus - // before transition, the default view should focus on the owner of this - // details view. - // - // In Material Design the actual transition is intentionally delayed to allow - // the user to perceive the ink drop animation on the clicked target. - void TransitionToDefaultView(); - - // Actually transitions to the default view. - void DoTransitionToDefaultView(); - - // Helper function which creates and returns the back button used in the - // material design top-most header row. The caller assumes ownership of the - // returned button. - views::Button* CreateBackButton(); - - SystemTrayItem* owner_; - views::BoxLayout* box_layout_; - SpecialPopupRow* title_row_; // Not used in material design. - views::ScrollView* scroller_; - views::View* scroll_content_; - views::ProgressBar* progress_bar_; - - ScrollBorder* scroll_border_; // Weak reference - - // The container view for the top-most title row in material design. - TriView* tri_view_; - - // The back button that appears in the material design title row. Not owned. - views::Button* back_button_; - - // Used to delay the transition to the default view. - base::OneShotTimer transition_delay_timer_; - - DISALLOW_COPY_AND_ASSIGN(TrayDetailsView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_DETAILS_VIEW_H_
diff --git a/ash/system/tray/tray_details_view_unittest.cc b/ash/system/tray/tray_details_view_unittest.cc deleted file mode 100644 index 42b150a..0000000 --- a/ash/system/tray/tray_details_view_unittest.cc +++ /dev/null
@@ -1,248 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_details_view.h" - -#include "ash/common/ash_view_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/special_popup_row.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_header_button.h" -#include "ash/system/tray/view_click_listener.h" -#include "ash/test/ash_test_base.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "base/test/scoped_mock_time_message_loop_task_runner.h" -#include "base/test/test_mock_time_task_runner.h" -#include "ui/events/test/event_generator.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace test { - -namespace { - -class TestDetailsView : public TrayDetailsView { - public: - explicit TestDetailsView(SystemTrayItem* owner) : TrayDetailsView(owner) { - // Uses bluetooth label for testing purpose. It can be changed to any - // string_id. - CreateTitleRow(IDS_ASH_STATUS_TRAY_BLUETOOTH); - } - - ~TestDetailsView() override {} - - TrayPopupHeaderButton* tray_popup_header_button() { - return tray_popup_header_button_; - } - - void FocusTitleRow() { title_row()->content()->RequestFocus(); } - - void CreateScrollerViews() { CreateScrollableList(); } - - private: - TrayPopupHeaderButton* tray_popup_header_button_; - - DISALLOW_COPY_AND_ASSIGN(TestDetailsView); -}; - -// Trivial item implementation that tracks its views for testing. -class TestItem : public SystemTrayItem { - public: - TestItem() - : SystemTrayItem(AshTestBase::GetPrimarySystemTray(), UMA_TEST), - tray_view_(nullptr), - default_view_(nullptr), - detailed_view_(nullptr) {} - - // Overridden from SystemTrayItem: - views::View* CreateTrayView(LoginStatus status) override { - tray_view_ = new views::View; - return tray_view_; - } - views::View* CreateDefaultView(LoginStatus status) override { - default_view_ = new views::View; - default_view_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS); - return default_view_; - } - views::View* CreateDetailedView(LoginStatus status) override { - detailed_view_ = new TestDetailsView(this); - return detailed_view_; - } - void DestroyTrayView() override { tray_view_ = NULL; } - void DestroyDefaultView() override { default_view_ = NULL; } - void DestroyDetailedView() override { detailed_view_ = NULL; } - - views::View* tray_view() const { return tray_view_; } - views::View* default_view() const { return default_view_; } - TestDetailsView* detailed_view() const { return detailed_view_; } - - private: - views::View* tray_view_; - views::View* default_view_; - TestDetailsView* detailed_view_; - - DISALLOW_COPY_AND_ASSIGN(TestItem); -}; - -} // namespace - -class TrayDetailsViewTest : public AshTestBase { - public: - TrayDetailsViewTest() {} - ~TrayDetailsViewTest() override {} - - HoverHighlightView* CreateAndShowHoverHighlightView() { - SystemTray* tray = GetPrimarySystemTray(); - TestItem* test_item = new TestItem; - tray->AddTrayItem(base::WrapUnique(test_item)); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - - return static_cast<HoverHighlightView*>( - test_item->detailed_view()->title_row()->content()); - } - - TrayPopupHeaderButton* CreateAndShowTrayPopupHeaderButton() { - SystemTray* tray = GetPrimarySystemTray(); - TestItem* test_item = new TestItem; - tray->AddTrayItem(base::WrapUnique(test_item)); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - - return test_item->detailed_view()->tray_popup_header_button(); - } - - void TransitionFromDetailedToDefaultView(TestDetailsView* detailed) { - detailed->TransitionToDefaultView(); - (*scoped_task_runner_) - ->FastForwardBy(base::TimeDelta::FromMilliseconds( - kTrayDetailedViewTransitionDelayMs)); - } - - void FocusBackButton(TestDetailsView* detailed) { - detailed->back_button_->RequestFocus(); - } - - void SetUp() override { - AshTestBase::SetUp(); - scoped_task_runner_ = - base::MakeUnique<base::ScopedMockTimeMessageLoopTaskRunner>(); - } - - void TearDown() override { - scoped_task_runner_.reset(); - AshTestBase::TearDown(); - } - - private: - // Used to control the |transition_delay_timer_|. - std::unique_ptr<base::ScopedMockTimeMessageLoopTaskRunner> - scoped_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(TrayDetailsViewTest); -}; - -TEST_F(TrayDetailsViewTest, TransitionToDefaultViewTest) { - SystemTray* tray = GetPrimarySystemTray(); - ASSERT_TRUE(tray->GetWidget()); - - TestItem* test_item_1 = new TestItem; - TestItem* test_item_2 = new TestItem; - tray->AddTrayItem(base::WrapUnique(test_item_1)); - tray->AddTrayItem(base::WrapUnique(test_item_2)); - - // Ensure the tray views are created. - ASSERT_TRUE(test_item_1->tray_view() != NULL); - ASSERT_TRUE(test_item_2->tray_view() != NULL); - - // Show the default view. - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - - // Show the detailed view of item 2. - tray->ShowDetailedView(test_item_2, 0, true, BUBBLE_USE_EXISTING); - EXPECT_TRUE(test_item_2->detailed_view()); - RunAllPendingInMessageLoop(); - EXPECT_FALSE(test_item_2->default_view()); - - // Transition back to default view, the default view of item 2 should have - // focus. - tray->GetSystemBubble()->bubble_view()->set_can_activate(true); - FocusBackButton(test_item_2->detailed_view()); - TransitionFromDetailedToDefaultView(test_item_2->detailed_view()); - RunAllPendingInMessageLoop(); - - EXPECT_TRUE(test_item_2->default_view()); - EXPECT_FALSE(test_item_2->detailed_view()); - EXPECT_TRUE(test_item_2->default_view()->HasFocus()); - - // Show the detailed view of item 2 again. - tray->ShowDetailedView(test_item_2, 0, true, BUBBLE_USE_EXISTING); - EXPECT_TRUE(test_item_2->detailed_view()); - RunAllPendingInMessageLoop(); - EXPECT_FALSE(test_item_2->default_view()); - - // Transition back to default view, the default view of item 2 should NOT have - // focus. - TransitionFromDetailedToDefaultView(test_item_2->detailed_view()); - RunAllPendingInMessageLoop(); - - EXPECT_TRUE(test_item_2->default_view()); - EXPECT_FALSE(test_item_2->detailed_view()); - EXPECT_FALSE(test_item_2->default_view()->HasFocus()); -} - -TEST_F(TrayDetailsViewTest, ScrollContentsTest) { - SystemTray* tray = GetPrimarySystemTray(); - TestItem* test_item = new TestItem; - tray->AddTrayItem(base::WrapUnique(test_item)); - tray->ShowDefaultView(BUBBLE_CREATE_NEW); - RunAllPendingInMessageLoop(); - tray->ShowDetailedView(test_item, 0, true, BUBBLE_USE_EXISTING); - RunAllPendingInMessageLoop(); - test_item->detailed_view()->CreateScrollerViews(); - - test_item->detailed_view()->scroll_content()->SetPaintToLayer(); - views::View* view1 = new views::View(); - test_item->detailed_view()->scroll_content()->AddChildView(view1); - views::View* view2 = new views::View(); - view2->SetPaintToLayer(); - test_item->detailed_view()->scroll_content()->AddChildView(view2); - views::View* view3 = new views::View(); - view3->SetPaintToLayer(); - test_item->detailed_view()->scroll_content()->AddChildView(view3); - - // Child layers should have same order as the child views. - const std::vector<ui::Layer*>& layers = - test_item->detailed_view()->scroll_content()->layer()->children(); - EXPECT_EQ(2u, layers.size()); - EXPECT_EQ(view2->layer(), layers[0]); - EXPECT_EQ(view3->layer(), layers[1]); - - // Mark |view2| as sticky and add one more child (which will reorder layers). - view2->set_id(VIEW_ID_STICKY_HEADER); - views::View* view4 = new views::View(); - view4->SetPaintToLayer(); - test_item->detailed_view()->scroll_content()->AddChildView(view4); - - // Sticky header layer should be above the last child's layer. - EXPECT_EQ(3u, layers.size()); - EXPECT_EQ(view3->layer(), layers[0]); - EXPECT_EQ(view4->layer(), layers[1]); - EXPECT_EQ(view2->layer(), layers[2]); -} - -} // namespace test -} // namespace ash
diff --git a/ash/system/tray/tray_event_filter.cc b/ash/system/tray/tray_event_filter.cc deleted file mode 100644 index 3d6d7a1..0000000 --- a/ash/system/tray/tray_event_filter.cc +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_event_filter.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/system/tray/tray_background_view.h" -#include "ash/system/tray/tray_bubble_wrapper.h" -#include "ash/wm/container_finder.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -TrayEventFilter::TrayEventFilter() {} - -TrayEventFilter::~TrayEventFilter() { - DCHECK(wrappers_.empty()); -} - -void TrayEventFilter::AddWrapper(TrayBubbleWrapper* wrapper) { - bool was_empty = wrappers_.empty(); - wrappers_.insert(wrapper); - if (was_empty && !wrappers_.empty()) { - WmShell::Get()->AddPointerWatcher(this, - views::PointerWatcherEventTypes::BASIC); - } -} - -void TrayEventFilter::RemoveWrapper(TrayBubbleWrapper* wrapper) { - wrappers_.erase(wrapper); - if (wrappers_.empty()) - WmShell::Get()->RemovePointerWatcher(this); -} - -void TrayEventFilter::OnPointerEventObserved( - const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) { - if (event.type() == ui::ET_POINTER_DOWN) - ProcessPressedEvent(location_in_screen, target); -} - -void TrayEventFilter::ProcessPressedEvent(const gfx::Point& location_in_screen, - views::Widget* target) { - if (target) { - WmWindow* window = WmWindow::Get(target->GetNativeWindow()); - int container_id = wm::GetContainerForWindow(window)->GetShellWindowId(); - // Don't process events that occurred inside an embedded menu, for example - // the right-click menu in a popup notification. - if (container_id == kShellWindowId_MenuContainer) - return; - // Don't process events that occurred inside a popup notification - // from message center. - if (container_id == kShellWindowId_StatusContainer && - window->GetType() == ui::wm::WINDOW_TYPE_POPUP && - target->IsAlwaysOnTop()) { - return; - } - } - - std::set<TrayBackgroundView*> trays; - // Check the boundary for all wrappers, and do not handle the event if it - // happens inside of any of those wrappers. - for (std::set<TrayBubbleWrapper*>::const_iterator iter = wrappers_.begin(); - iter != wrappers_.end(); ++iter) { - const TrayBubbleWrapper* wrapper = *iter; - const views::Widget* bubble_widget = wrapper->bubble_widget(); - if (!bubble_widget) - continue; - - gfx::Rect bounds = bubble_widget->GetWindowBoundsInScreen(); - bounds.Inset(wrapper->bubble_view()->GetBorderInsets()); - if (bounds.Contains(location_in_screen)) - continue; - if (wrapper->tray()) { - // If the user clicks on the parent tray, don't process the event here, - // let the tray logic handle the event and determine show/hide behavior. - bounds = wrapper->tray()->GetBoundsInScreen(); - if (bounds.Contains(location_in_screen)) - continue; - } - trays.insert((*iter)->tray()); - } - - // Close all bubbles other than the one a user clicked on the tray - // or its bubble. - for (std::set<TrayBackgroundView*>::iterator iter = trays.begin(); - iter != trays.end(); ++iter) { - (*iter)->ClickedOutsideBubble(); - } -} - -} // namespace ash
diff --git a/ash/system/tray/tray_event_filter.h b/ash/system/tray/tray_event_filter.h deleted file mode 100644 index 21e5ebe4..0000000 --- a/ash/system/tray/tray_event_filter.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_ -#define ASH_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_ - -#include <set> - -#include "base/macros.h" -#include "ui/views/pointer_watcher.h" - -namespace gfx { -class Point; -} - -namespace ui { -class PointerEvent; -} - -namespace ash { -class TrayBubbleWrapper; - -// Handles events for a tray bubble, e.g. to close the system tray bubble when -// the user clicks outside it. -class TrayEventFilter : public views::PointerWatcher { - public: - TrayEventFilter(); - ~TrayEventFilter() override; - - void AddWrapper(TrayBubbleWrapper* wrapper); - void RemoveWrapper(TrayBubbleWrapper* wrapper); - - // views::PointerWatcher: - void OnPointerEventObserved(const ui::PointerEvent& event, - const gfx::Point& location_in_screen, - views::Widget* target) override; - - private: - void ProcessPressedEvent(const gfx::Point& location_in_screen, - views::Widget* target); - - std::set<TrayBubbleWrapper*> wrappers_; - - DISALLOW_COPY_AND_ASSIGN(TrayEventFilter); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_
diff --git a/ash/system/tray/tray_image_item.cc b/ash/system/tray/tray_image_item.cc deleted file mode 100644 index 0633b0cb..0000000 --- a/ash/system/tray/tray_image_item.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_image_item.h" - -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_utils.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/layout/box_layout.h" - -namespace ash { - -TrayImageItem::TrayImageItem(SystemTray* system_tray, - const gfx::VectorIcon& icon, - UmaType uma_type) - : SystemTrayItem(system_tray, uma_type), - icon_(icon), - icon_color_(kTrayIconColor), - tray_view_(nullptr) {} - -TrayImageItem::~TrayImageItem() {} - -views::View* TrayImageItem::tray_view() { - return tray_view_; -} - -views::View* TrayImageItem::CreateTrayView(LoginStatus status) { - CHECK(!tray_view_); - tray_view_ = new TrayItemView(this); - tray_view_->CreateImageView(); - UpdateImageOnImageView(); - tray_view_->SetVisible(GetInitialVisibility()); - return tray_view_; -} - -views::View* TrayImageItem::CreateDefaultView(LoginStatus status) { - return nullptr; -} - -views::View* TrayImageItem::CreateDetailedView(LoginStatus status) { - return nullptr; -} - -void TrayImageItem::UpdateAfterLoginStatusChange(LoginStatus status) {} - -void TrayImageItem::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - SetTrayImageItemBorder(tray_view_, alignment); -} - -void TrayImageItem::DestroyTrayView() { - tray_view_ = nullptr; -} - -void TrayImageItem::DestroyDefaultView() {} - -void TrayImageItem::DestroyDetailedView() {} - -void TrayImageItem::SetIconColor(SkColor color) { - icon_color_ = color; - UpdateImageOnImageView(); -} - -void TrayImageItem::UpdateImageOnImageView() { - if (!tray_view_) - return; - - tray_view_->image_view()->SetImage( - gfx::CreateVectorIcon(icon_, kTrayIconSize, icon_color_)); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_image_item.h b/ash/system/tray/tray_image_item.h deleted file mode 100644 index 4a0a9c79..0000000 --- a/ash/system/tray/tray_image_item.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_IMAGE_ITEM_H_ -#define ASH_SYSTEM_TRAY_TRAY_IMAGE_ITEM_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/system_tray_item.h" -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" - -namespace views { -class ImageView; -} - -namespace gfx { -struct VectorIcon; -} - -namespace ash { -class TrayItemView; - -// A system tray item that uses an image as its "tray view" in the status area. -class ASH_EXPORT TrayImageItem : public SystemTrayItem { - public: - TrayImageItem(SystemTray* system_tray, - const gfx::VectorIcon& icon, - UmaType uma_type); - ~TrayImageItem() override; - - views::View* tray_view(); - - protected: - virtual bool GetInitialVisibility() = 0; - - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // Sets the color of the icon to |color|. - void SetIconColor(SkColor color); - - private: - // Sets the current icon on |tray_view_|'s ImageView. - void UpdateImageOnImageView(); - - // The icon and its current color. - const gfx::VectorIcon& icon_; - SkColor icon_color_; - - // The image view in the tray. - TrayItemView* tray_view_; - - DISALLOW_COPY_AND_ASSIGN(TrayImageItem); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_IMAGE_ITEM_H_
diff --git a/ash/system/tray/tray_item_more.cc b/ash/system/tray/tray_item_more.cc deleted file mode 100644 index 89c7795..0000000 --- a/ash/system/tray/tray_item_more.cc +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_item_more.h" - -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/memory/ptr_util.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/gfx/image/image.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { - -TrayItemMore::TrayItemMore(SystemTrayItem* owner) - : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS), - tri_view_(TrayPopupUtils::CreateDefaultRowView()), - icon_(TrayPopupUtils::CreateMainImageView()), - label_(TrayPopupUtils::CreateDefaultLabel()), - more_(TrayPopupUtils::CreateMoreImageView()) { - AddChildView(tri_view_); - SetLayoutManager(new views::FillLayout); - - tri_view_->AddView(TriView::Container::START, icon_); - tri_view_->AddView(TriView::Container::CENTER, label_); - tri_view_->AddView(TriView::Container::END, more_); - - SetInkDropMode(InkDropHostView::InkDropMode::ON); -} - -TrayItemMore::~TrayItemMore() {} - -void TrayItemMore::SetLabel(const base::string16& label) { - label_->SetText(label); - Layout(); - SchedulePaint(); -} - -void TrayItemMore::SetImage(const gfx::ImageSkia& image_skia) { - icon_->SetImage(image_skia); - SchedulePaint(); -} - -void TrayItemMore::SetAccessibleName(const base::string16& name) { - accessible_name_ = name; -} - -std::unique_ptr<TrayPopupItemStyle> TrayItemMore::CreateStyle() const { - std::unique_ptr<TrayPopupItemStyle> style = HandleCreateStyle(); - if (!enabled()) - style->set_color_style(TrayPopupItemStyle::ColorStyle::DISABLED); - return style; -} - -std::unique_ptr<TrayPopupItemStyle> TrayItemMore::HandleCreateStyle() const { - return base::MakeUnique<TrayPopupItemStyle>( - TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); -} - -void TrayItemMore::UpdateStyle() { - std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); - style->SetupLabel(label_); -} - -bool TrayItemMore::PerformAction(const ui::Event& event) { - owner()->TransitionDetailedView(); - return true; -} - -void TrayItemMore::GetAccessibleNodeData(ui::AXNodeData* node_data) { - ActionableView::GetAccessibleNodeData(node_data); - if (!accessible_name_.empty()) - node_data->SetName(accessible_name_); -} - -void TrayItemMore::OnEnabledChanged() { - ActionableView::OnEnabledChanged(); - tri_view_->SetContainerVisible(TriView::Container::END, enabled()); - UpdateStyle(); -} - -void TrayItemMore::OnNativeThemeChanged(const ui::NativeTheme* theme) { - ActionableView::OnNativeThemeChanged(theme); - UpdateStyle(); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_item_more.h b/ash/system/tray/tray_item_more.h deleted file mode 100644 index dc72bb16..0000000 --- a/ash/system/tray/tray_item_more.h +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_ITEM_MORE_H_ -#define ASH_SYSTEM_TRAY_TRAY_ITEM_MORE_H_ - -#include <memory> - -#include "ash/system/tray/actionable_view.h" -#include "base/macros.h" -#include "ui/views/view.h" - -namespace views { -class ImageView; -class Label; -class View; -} - -namespace ash { -class SystemTrayItem; -class TrayPopupItemStyle; -class TriView; - -// A view with a more arrow on the right edge. Clicking on the view brings up -// the detailed view of the tray-item that owns it. If the view is disabled, it -// will not show the more arrow. -class TrayItemMore : public ActionableView { - public: - explicit TrayItemMore(SystemTrayItem* owner); - ~TrayItemMore() override; - - void SetLabel(const base::string16& label); - void SetImage(const gfx::ImageSkia& image_skia); - void SetAccessibleName(const base::string16& name); - - protected: - // Returns a style that will be applied to the elements in the UpdateStyle() - // method if |this| is enabled; otherwise, we force |this| to use - // ColorStyle::DISABLED. - std::unique_ptr<TrayPopupItemStyle> CreateStyle() const; - - // Called by CreateStyle() to give descendants a chance to customize the - // style; e.g. to change the style's ColorStyle based on whether Bluetooth is - // enabled/disabled. - virtual std::unique_ptr<TrayPopupItemStyle> HandleCreateStyle() const; - - // Applies the style created from CreateStyle(). Should be called whenever any - // input state changes that changes the style configuration created by - // CreateStyle(). E.g. if Bluetooth is changed between enabled/disabled then - // a differently configured style will be returned from CreateStyle() and thus - // it will need to be applied. - virtual void UpdateStyle(); - - private: - // Overridden from ActionableView. - bool PerformAction(const ui::Event& event) override; - - // Overridden from views::View. - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void OnEnabledChanged() override; - void OnNativeThemeChanged(const ui::NativeTheme* theme) override; - - TriView* tri_view_; - views::ImageView* icon_; - views::Label* label_; - views::ImageView* more_; - base::string16 accessible_name_; - - DISALLOW_COPY_AND_ASSIGN(TrayItemMore); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_ITEM_MORE_H_
diff --git a/ash/system/tray/tray_item_view.cc b/ash/system/tray/tray_item_view.cc deleted file mode 100644 index 32597ce..0000000 --- a/ash/system/tray/tray_item_view.cc +++ /dev/null
@@ -1,150 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_item_view.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/tray/tray_constants.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/widget/widget.h" - -namespace { -const int kTrayIconHeight = 29; -const int kTrayIconWidth = 29; -const int kTrayItemAnimationDurationMS = 200; - -// Animations can be disabled for testing. -bool animations_enabled = true; -} - -namespace ash { - -TrayItemView::TrayItemView(SystemTrayItem* owner) - : owner_(owner), label_(NULL), image_view_(NULL) { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - SetLayoutManager(new views::FillLayout()); -} - -TrayItemView::~TrayItemView() {} - -// static -void TrayItemView::DisableAnimationsForTest() { - animations_enabled = false; -} - -void TrayItemView::CreateLabel() { - label_ = new views::Label; - AddChildView(label_); - PreferredSizeChanged(); -} - -void TrayItemView::CreateImageView() { - image_view_ = new views::ImageView; - AddChildView(image_view_); - PreferredSizeChanged(); -} - -void TrayItemView::SetVisible(bool set_visible) { - if (!GetWidget() || !animations_enabled) { - views::View::SetVisible(set_visible); - return; - } - - if (!animation_) { - animation_.reset(new gfx::SlideAnimation(this)); - animation_->SetSlideDuration(GetAnimationDurationMS()); - animation_->SetTweenType(gfx::Tween::LINEAR); - animation_->Reset(visible() ? 1.0 : 0.0); - } - - if (!set_visible) { - animation_->Hide(); - AnimationProgressed(animation_.get()); - } else { - animation_->Show(); - AnimationProgressed(animation_.get()); - views::View::SetVisible(true); - } -} - -// static -bool TrayItemView::UseMd() { - return MaterialDesignController::UseMaterialDesignSystemIcons(); -} - -int TrayItemView::GetAnimationDurationMS() { - return kTrayItemAnimationDurationMS; -} - -gfx::Size TrayItemView::GetPreferredSize() const { - DCHECK_EQ(1, child_count()); - gfx::Size size; - if (UseMd()) { - gfx::Size inner_size = views::View::GetPreferredSize(); - if (image_view_) - inner_size = gfx::Size(kTrayIconSize, kTrayIconSize); - gfx::Rect rect(inner_size); - rect.Inset(gfx::Insets(-kTrayImageItemPadding)); - size = rect.size(); - } else { - size = views::View::GetPreferredSize(); - if (IsHorizontalAlignment(owner()->system_tray()->shelf_alignment())) - size.set_height(kTrayIconHeight); - else - size.set_width(kTrayIconWidth); - } - if (!animation_.get() || !animation_->is_animating()) - return size; - if (IsHorizontalAlignment(owner()->system_tray()->shelf_alignment())) { - size.set_width(std::max( - 1, static_cast<int>(size.width() * animation_->GetCurrentValue()))); - } else { - size.set_height(std::max( - 1, static_cast<int>(size.height() * animation_->GetCurrentValue()))); - } - return size; -} - -int TrayItemView::GetHeightForWidth(int width) const { - return GetPreferredSize().height(); -} - -void TrayItemView::ChildPreferredSizeChanged(views::View* child) { - PreferredSizeChanged(); -} - -void TrayItemView::AnimationProgressed(const gfx::Animation* animation) { - gfx::Transform transform; - if (IsHorizontalAlignment(owner()->system_tray()->shelf_alignment())) { - transform.Translate(0, animation->CurrentValueBetween( - static_cast<double>(height()) / 2, 0.)); - } else { - transform.Translate( - animation->CurrentValueBetween(static_cast<double>(width() / 2), 0.), - 0); - } - transform.Scale(animation->GetCurrentValue(), animation->GetCurrentValue()); - layer()->SetTransform(transform); - PreferredSizeChanged(); -} - -void TrayItemView::AnimationEnded(const gfx::Animation* animation) { - if (animation->GetCurrentValue() < 0.1) - views::View::SetVisible(false); -} - -void TrayItemView::AnimationCanceled(const gfx::Animation* animation) { - AnimationEnded(animation); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_item_view.h b/ash/system/tray/tray_item_view.h deleted file mode 100644 index 729d363..0000000 --- a/ash/system/tray/tray_item_view.h +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_ITEM_VIEW_H_ -#define ASH_SYSTEM_TRAY_TRAY_ITEM_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/gfx/animation/animation_delegate.h" -#include "ui/views/view.h" - -namespace gfx { -class SlideAnimation; -} - -namespace views { -class ImageView; -class Label; -} - -namespace ash { -class SystemTrayItem; - -// Base-class for items in the tray. It makes sure the widget is updated -// correctly when the visibility/size of the tray item changes. It also adds -// animation when showing/hiding the item in the tray. -class ASH_EXPORT TrayItemView : public views::View, - public gfx::AnimationDelegate { - public: - explicit TrayItemView(SystemTrayItem* owner); - ~TrayItemView() override; - - static void DisableAnimationsForTest(); - - // Convenience function for creating a child Label or ImageView. - // Only one of the two should be called. - void CreateLabel(); - void CreateImageView(); - - SystemTrayItem* owner() const { return owner_; } - views::Label* label() const { return label_; } - views::ImageView* image_view() const { return image_view_; } - - // Overridden from views::View. - void SetVisible(bool visible) override; - gfx::Size GetPreferredSize() const override; - int GetHeightForWidth(int width) const override; - - protected: - static bool UseMd(); - - // The default animation duration is 200ms. But each view can customize this. - virtual int GetAnimationDurationMS(); - - private: - // Overridden from views::View. - void ChildPreferredSizeChanged(View* child) override; - - // Overridden from gfx::AnimationDelegate. - void AnimationProgressed(const gfx::Animation* animation) override; - void AnimationEnded(const gfx::Animation* animation) override; - void AnimationCanceled(const gfx::Animation* animation) override; - - SystemTrayItem* owner_; - std::unique_ptr<gfx::SlideAnimation> animation_; - // Only one of |label_| and |image_view_| should be non-null. - views::Label* label_; - views::ImageView* image_view_; - - DISALLOW_COPY_AND_ASSIGN(TrayItemView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_ITEM_VIEW_H_
diff --git a/ash/system/tray/tray_notification_view.cc b/ash/system/tray/tray_notification_view.cc deleted file mode 100644 index c374276..0000000 --- a/ash/system/tray/tray_notification_view.cc +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_notification_view.h" - -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/tray/tray_constants.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/resources/grit/ui_resources.h" -#include "ui/views/background.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/layout/grid_layout.h" - -namespace ash { - -namespace { - -// Maps a non-MD PNG resource id to its corresponding MD vector icon. -// TODO(tdanderson): Remove this once material design is enabled by -// default. See crbug.com/614453. -const gfx::VectorIcon& ResourceIdToVectorIcon(int resource_id) { - switch (resource_id) { - case IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK: - return kSystemMenuAccessibilityIcon; - default: - NOTREACHED(); - break; - } - - return gfx::kNoneIcon; -} - -} // namespace - -TrayNotificationView::TrayNotificationView(int icon_id) - : icon_id_(icon_id), icon_(NULL) {} - -TrayNotificationView::~TrayNotificationView() {} - -void TrayNotificationView::InitView(views::View* contents) { - set_background(views::Background::CreateSolidBackground(kBackgroundColor)); - - views::GridLayout* layout = new views::GridLayout(this); - SetLayoutManager(layout); - - views::ImageView* close_button = new views::ImageView(); - close_button->SetImage( - ResourceBundle::GetSharedInstance().GetImageSkiaNamed(IDR_MESSAGE_CLOSE)); - close_button->SetHorizontalAlignment(views::ImageView::CENTER); - close_button->SetVerticalAlignment(views::ImageView::CENTER); - - icon_ = new views::ImageView; - if (icon_id_ != 0) { - icon_->SetImage(gfx::CreateVectorIcon(ResourceIdToVectorIcon(icon_id_), - kMenuIconColor)); - } - - views::ColumnSet* columns = layout->AddColumnSet(0); - - columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2); - - // Icon - columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, - 0, /* resize percent */ - views::GridLayout::FIXED, kNotificationIconWidth, - kNotificationIconWidth); - - columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2); - - // Contents - columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, - 100, /* resize percent */ - views::GridLayout::FIXED, kTrayNotificationContentsWidth, - kTrayNotificationContentsWidth); - - columns->AddPaddingColumn(0, kTrayPopupPaddingHorizontal / 2); - - // Close button - columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::LEADING, - 0, /* resize percent */ - views::GridLayout::FIXED, kNotificationButtonWidth, - kNotificationButtonWidth); - - // Layout rows - layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems); - layout->StartRow(0, 0); - layout->AddView(icon_); - layout->AddView(contents); - layout->AddView(close_button); - layout->AddPaddingRow(0, kTrayPopupPaddingBetweenItems); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_notification_view.h b/ash/system/tray/tray_notification_view.h deleted file mode 100644 index b6179ab..0000000 --- a/ash/system/tray/tray_notification_view.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_NOTIFICATION_VIEW_H_ -#define ASH_SYSTEM_TRAY_TRAY_NOTIFICATION_VIEW_H_ - -#include "ui/views/view.h" - -namespace views { -class ImageView; -} - -namespace ash { - -// A view for closable notification views, laid out like: -// ------------------- -// | icon contents x | -// ----------------v-- -// The close button will call OnClose() when clicked. -class TrayNotificationView : public views::View { - public: - // If icon_id is 0, no icon image will be set. - explicit TrayNotificationView(int icon_id); - ~TrayNotificationView() override; - - // InitView must be called once with the contents to be displayed. - void InitView(views::View* contents); - - private: - int icon_id_; - views::ImageView* icon_; - - DISALLOW_COPY_AND_ASSIGN(TrayNotificationView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_NOTIFICATION_VIEW_H_
diff --git a/ash/system/tray/tray_popup_header_button.cc b/ash/system/tray/tray_popup_header_button.cc deleted file mode 100644 index 146dc0e..0000000 --- a/ash/system/tray/tray_popup_header_button.cc +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_popup_header_button.h" - -#include "ash/common/ash_constants.h" -#include "ash/system/tray/tray_constants.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/views/background.h" -#include "ui/views/painter.h" - -namespace ash { - -namespace { - -const gfx::ImageSkia* GetImageForResourceId(int resource_id) { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - return bundle.GetImageNamed(resource_id).ToImageSkia(); -} - -} // namespace - -// static -const char TrayPopupHeaderButton::kViewClassName[] = - "tray/TrayPopupHeaderButton"; - -TrayPopupHeaderButton::TrayPopupHeaderButton(views::ButtonListener* listener, - const gfx::ImageSkia& icon, - int accessible_name_id) - : views::ToggleImageButton(listener) { - Initialize(icon, accessible_name_id); -} - -TrayPopupHeaderButton::TrayPopupHeaderButton(views::ButtonListener* listener, - int enabled_resource_id, - int disabled_resource_id, - int enabled_resource_id_hover, - int disabled_resource_id_hover, - int accessible_name_id) - : views::ToggleImageButton(listener) { - Initialize(*GetImageForResourceId(enabled_resource_id), accessible_name_id); - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - SetToggledImage(views::Button::STATE_NORMAL, - bundle.GetImageNamed(disabled_resource_id).ToImageSkia()); - SetImage(views::Button::STATE_HOVERED, - *bundle.GetImageNamed(enabled_resource_id_hover).ToImageSkia()); - SetToggledImage( - views::Button::STATE_HOVERED, - bundle.GetImageNamed(disabled_resource_id_hover).ToImageSkia()); -} - -TrayPopupHeaderButton::~TrayPopupHeaderButton() {} - -const char* TrayPopupHeaderButton::GetClassName() const { - return kViewClassName; -} - -gfx::Size TrayPopupHeaderButton::GetPreferredSize() const { - return gfx::Size(kTrayPopupItemMinHeight, kTrayPopupItemMinHeight); -} - -void TrayPopupHeaderButton::StateChanged(ButtonState old_state) { - if (state() == STATE_HOVERED || state() == STATE_PRESSED) { - set_background(views::Background::CreateSolidBackground( - kTrayPopupHoverBackgroundColor)); - } else { - set_background(nullptr); - } - SchedulePaint(); -} - -void TrayPopupHeaderButton::Initialize(const gfx::ImageSkia& icon, - int accessible_name_id) { - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - SetImage(views::Button::STATE_NORMAL, icon); - SetImageAlignment(views::ImageButton::ALIGN_CENTER, - views::ImageButton::ALIGN_MIDDLE); - SetAccessibleName(bundle.GetLocalizedString(accessible_name_id)); - SetFocusForPlatform(); - - SetFocusPainter(views::Painter::CreateSolidFocusPainter( - kFocusBorderColor, gfx::Insets(1, 2, 2, 3))); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_popup_header_button.h b/ash/system/tray/tray_popup_header_button.h deleted file mode 100644 index ad3b89b..0000000 --- a/ash/system/tray/tray_popup_header_button.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_POPUP_HEADER_BUTTON_H_ -#define ASH_SYSTEM_TRAY_TRAY_POPUP_HEADER_BUTTON_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/views/controls/button/image_button.h" - -namespace ash { - -// A ToggleImageButton with fixed size, paddings and hover effects. These -// buttons are used in the header. -class ASH_EXPORT TrayPopupHeaderButton : public views::ToggleImageButton { - public: - static const char kViewClassName[]; - - TrayPopupHeaderButton(views::ButtonListener* listener, - const gfx::ImageSkia& icon, - int accessible_name_id); - TrayPopupHeaderButton(views::ButtonListener* listener, - int enabled_resource_id, - int disabled_resource_id, - int enabled_resource_id_hover, - int disabled_resource_id_hover, - int accessible_name_id); - ~TrayPopupHeaderButton() override; - - private: - // Overridden from views::View: - const char* GetClassName() const override; - gfx::Size GetPreferredSize() const override; - - // Overridden from views::CustomButton: - void StateChanged(ButtonState old_state) override; - - void Initialize(const gfx::ImageSkia& icon, int accessible_name_id); - - DISALLOW_COPY_AND_ASSIGN(TrayPopupHeaderButton); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_POPUP_HEADER_BUTTON_H_
diff --git a/ash/system/tray/tray_popup_ink_drop_style.h b/ash/system/tray/tray_popup_ink_drop_style.h deleted file mode 100644 index aacb41c..0000000 --- a/ash/system/tray/tray_popup_ink_drop_style.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_POPUP_INK_DROP_STYLE_H_ -#define ASH_SYSTEM_TRAY_TRAY_POPUP_INK_DROP_STYLE_H_ - -namespace ash { - -// The different styles of ink drops applied to the system menu. -enum class TrayPopupInkDropStyle { - // Used for targets where the user doesn't need to know the exact targetable - // area and they are expected to target an icon centered in the targetable - // space. Highlight and ripple are drawn as a circle. - HOST_CENTERED, - // Used for targets where the user should know the targetable bounds but - // where the ink drop shouldn't fill the entire bounds. e.g. row of buttons - // separated with separators. - INSET_BOUNDS, - // Used for targets that should indicate to the user what the actual - // targetable bounds are. e.g. a full system menu row. - FILL_BOUNDS -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_POPUP_INK_DROP_STYLE_H_
diff --git a/ash/system/tray/tray_popup_item_container.cc b/ash/system/tray/tray_popup_item_container.cc deleted file mode 100644 index ee6d3d29..0000000 --- a/ash/system/tray/tray_popup_item_container.cc +++ /dev/null
@@ -1,77 +0,0 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_popup_item_container.h" - -#include "ash/system/tray/tray_constants.h" -#include "ui/gfx/canvas.h" -#include "ui/views/layout/box_layout.h" - -namespace ash { - -TrayPopupItemContainer::TrayPopupItemContainer(views::View* view, - bool change_background) - : active_(false), change_background_(change_background) { - set_notify_enter_exit_on_child(true); - views::BoxLayout* layout = - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); - layout->SetDefaultFlex(1); - SetLayoutManager(layout); - if (view->layer()) { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(view->layer()->fills_bounds_opaquely()); - } - AddChildView(view); - SetVisible(view->visible()); -} - -TrayPopupItemContainer::~TrayPopupItemContainer() {} - -void TrayPopupItemContainer::SetActive(bool active) { - if (!change_background_ || active_ == active) - return; - active_ = active; - SchedulePaint(); -} - -void TrayPopupItemContainer::ChildVisibilityChanged(View* child) { - if (visible() == child->visible()) - return; - SetVisible(child->visible()); - PreferredSizeChanged(); -} - -void TrayPopupItemContainer::ChildPreferredSizeChanged(View* child) { - PreferredSizeChanged(); -} - -void TrayPopupItemContainer::OnMouseEntered(const ui::MouseEvent& event) { - SetActive(true); -} - -void TrayPopupItemContainer::OnMouseExited(const ui::MouseEvent& event) { - SetActive(false); -} - -void TrayPopupItemContainer::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP_DOWN) { - SetActive(true); - } else if (event->type() == ui::ET_GESTURE_TAP_CANCEL || - event->type() == ui::ET_GESTURE_TAP) { - SetActive(false); - } -} - -void TrayPopupItemContainer::OnPaintBackground(gfx::Canvas* canvas) { - if (child_count() == 0) - return; - - views::View* view = child_at(0); - if (!view->background()) { - canvas->FillRect(gfx::Rect(size()), - (active_) ? kHoverBackgroundColor : kBackgroundColor); - } -} - -} // namespace ash
diff --git a/ash/system/tray/tray_popup_item_container.h b/ash/system/tray/tray_popup_item_container.h deleted file mode 100644 index 31ebeb3..0000000 --- a/ash/system/tray/tray_popup_item_container.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_POPUP_ITEM_CONTAINER_H_ -#define ASH_SYSTEM_TRAY_TRAY_POPUP_ITEM_CONTAINER_H_ - -#include "base/macros.h" -#include "ui/views/view.h" - -namespace ash { - -// A view which can optionally change the background color when a mouse is -// hovering or a user is interacting via touch. -class TrayPopupItemContainer : public views::View { - public: - TrayPopupItemContainer(views::View* view, bool change_background); - - ~TrayPopupItemContainer() override; - - bool active() { return active_; } - - private: - // Sets whether the active background is to be used, and triggers a paint. - void SetActive(bool active); - - // views::View: - void ChildVisibilityChanged(views::View* child) override; - void ChildPreferredSizeChanged(views::View* child) override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - void OnPaintBackground(gfx::Canvas* canvas) override; - - // True if either a mouse is hovering over this view, or if a user has touched - // down. - bool active_; - - // True if mouse hover and touch feedback can alter the background color of - // the container. - bool change_background_; - - DISALLOW_COPY_AND_ASSIGN(TrayPopupItemContainer); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_POPUP_ITEM_CONTAINER_H_
diff --git a/ash/system/tray/tray_popup_item_style.cc b/ash/system/tray/tray_popup_item_style.cc deleted file mode 100644 index e7a7cd4..0000000 --- a/ash/system/tray/tray_popup_item_style.cc +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_popup_item_style.h" - -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/font.h" -#include "ui/gfx/font_list.h" -#include "ui/native_theme/native_theme.h" -#include "ui/views/controls/label.h" - -namespace ash { -namespace { - -const int kInactiveAlpha = 0x8A; -const int kDisabledAlpha = 0x61; - -} // namespace - -// static -SkColor TrayPopupItemStyle::GetIconColor(ColorStyle color_style) { - switch (color_style) { - case ColorStyle::ACTIVE: - return gfx::kChromeIconGrey; - case ColorStyle::INACTIVE: - return SkColorSetA(gfx::kChromeIconGrey, kInactiveAlpha); - case ColorStyle::DISABLED: - return SkColorSetA(gfx::kChromeIconGrey, kDisabledAlpha); - case ColorStyle::CONNECTED: - return gfx::kPlaceholderColor; - } - NOTREACHED(); - return gfx::kPlaceholderColor; -} - -TrayPopupItemStyle::TrayPopupItemStyle(FontStyle font_style) - : font_style_(font_style), color_style_(ColorStyle::ACTIVE) { - if (font_style_ == FontStyle::SYSTEM_INFO) - color_style_ = ColorStyle::INACTIVE; -} - -TrayPopupItemStyle::~TrayPopupItemStyle() {} - -SkColor TrayPopupItemStyle::GetTextColor() const { - const SkColor kBaseTextColor = SkColorSetA(SK_ColorBLACK, 0xDE); - - switch (color_style_) { - case ColorStyle::ACTIVE: - return kBaseTextColor; - case ColorStyle::INACTIVE: - return SkColorSetA(kBaseTextColor, kInactiveAlpha); - case ColorStyle::DISABLED: - return SkColorSetA(kBaseTextColor, kDisabledAlpha); - case ColorStyle::CONNECTED: - return gfx::kGoogleGreen700; - } - NOTREACHED(); - return gfx::kPlaceholderColor; -} - -SkColor TrayPopupItemStyle::GetIconColor() const { - return GetIconColor(color_style_); -} - -void TrayPopupItemStyle::SetupLabel(views::Label* label) const { - label->SetEnabledColor(GetTextColor()); - - const gfx::FontList& base_font_list = views::Label::GetDefaultFontList(); - switch (font_style_) { - case FontStyle::TITLE: - label->SetFontList(base_font_list.Derive(2, gfx::Font::NORMAL, - gfx::Font::Weight::MEDIUM)); - break; - case FontStyle::DEFAULT_VIEW_LABEL: - label->SetFontList(base_font_list.Derive(2, gfx::Font::NORMAL, - gfx::Font::Weight::NORMAL)); - break; - case FontStyle::SUB_HEADER: - label->SetFontList(base_font_list.Derive(1, gfx::Font::NORMAL, - gfx::Font::Weight::MEDIUM)); - label->SetEnabledColor(label->GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor)); - label->SetAutoColorReadabilityEnabled(false); - break; - case FontStyle::DETAILED_VIEW_LABEL: - case FontStyle::SYSTEM_INFO: - label->SetFontList(base_font_list.Derive(1, gfx::Font::NORMAL, - gfx::Font::Weight::NORMAL)); - break; - case FontStyle::BUTTON: - label->SetFontList(base_font_list.Derive(0, gfx::Font::NORMAL, - gfx::Font::Weight::MEDIUM)); - break; - case FontStyle::CAPTION: - label->SetFontList(base_font_list.Derive(0, gfx::Font::NORMAL, - gfx::Font::Weight::NORMAL)); - break; - } -} - -} // namespace ash
diff --git a/ash/system/tray/tray_popup_item_style.h b/ash/system/tray/tray_popup_item_style.h deleted file mode 100644 index a58fb02..0000000 --- a/ash/system/tray/tray_popup_item_style.h +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_POPUP_ITEM_STYLE_H_ -#define ASH_SYSTEM_TRAY_TRAY_POPUP_ITEM_STYLE_H_ - -#include "base/macros.h" -#include "third_party/skia/include/core/SkColor.h" - -namespace views { -class Label; -} // namespace views - -namespace ash { - -// Central style provider for the system tray menu. Makes it easier to ensure -// all visuals are consistent and easily updated in one spot instead of being -// defined in multiple places throughout the code. -class TrayPopupItemStyle { - public: - // The different visual styles that a row can have. - enum class ColorStyle { - // Active and clickable. - ACTIVE, - // Inactive but clickable. - INACTIVE, - // Disabled and not clickable. - DISABLED, - // Color for "Connected" labels. - CONNECTED, - }; - - // The different font styles that row text can have. - enum class FontStyle { - // Topmost header rows for default view and detailed view. - TITLE, - // Main text used by default view rows. - DEFAULT_VIEW_LABEL, - // Text in sub-section header rows in detailed views. - SUB_HEADER, - // Main text used by detailed view rows. - DETAILED_VIEW_LABEL, - // System information text (e.g. date/time, battery status, etc). - SYSTEM_INFO, - // Child buttons within rows that have a visible border (e.g. Cast's - // "Stop", etc). - BUTTON, - // Sub text within a row (e.g. user name in user row). - CAPTION, - }; - - static SkColor GetIconColor(ColorStyle color_style); - - explicit TrayPopupItemStyle(FontStyle font_style); - ~TrayPopupItemStyle(); - - ColorStyle color_style() const { return color_style_; } - - void set_color_style(ColorStyle color_style) { color_style_ = color_style; } - - FontStyle font_style() const { return font_style_; } - - void set_font_style(FontStyle font_style) { font_style_ = font_style; } - - SkColor GetTextColor() const; - - SkColor GetIconColor() const; - - // Configures a Label as per the style (e.g. color, font). - void SetupLabel(views::Label* label) const; - - private: - FontStyle font_style_; - - ColorStyle color_style_; - - DISALLOW_COPY_AND_ASSIGN(TrayPopupItemStyle); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_POPUP_ITEM_STYLE_H_
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc deleted file mode 100644 index 8393e04..0000000 --- a/ash/system/tray/tray_popup_utils.cc +++ /dev/null
@@ -1,437 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_popup_utils.h" - -#include <algorithm> -#include <utility> - -#include "ash/common/ash_constants.h" -#include "ash/common/ash_view_ids.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/size_range_layout.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "base/memory/ptr_util.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop_highlight.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_mask.h" -#include "ui/views/animation/square_ink_drop_ripple.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/button/md_text_button.h" -#include "ui/views/controls/button/toggle_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/controls/slider.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/painter.h" - -namespace ash { - -namespace { - -// Creates a layout manager that positions Views vertically. The Views will be -// stretched horizontally and centered vertically. -std::unique_ptr<views::LayoutManager> CreateDefaultCenterLayoutManager() { - // TODO(bruthig): Use constants instead of magic numbers. - auto box_layout = - base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical, 4, 8, 0); - box_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); - box_layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); - return std::move(box_layout); -} - -// Creates a layout manager that positions Views horizontally. The Views will be -// centered along the horizontal and vertical axis. -std::unique_ptr<views::LayoutManager> CreateDefaultEndsLayoutManager() { - auto box_layout = base::MakeUnique<views::BoxLayout>( - views::BoxLayout::kHorizontal, 0, 0, 0); - box_layout->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); - box_layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - return std::move(box_layout); -} - -std::unique_ptr<views::LayoutManager> CreateDefaultLayoutManager( - TriView::Container container) { - switch (container) { - case TriView::Container::START: - case TriView::Container::END: - return CreateDefaultEndsLayoutManager(); - case TriView::Container::CENTER: - return CreateDefaultCenterLayoutManager(); - } - // Required by some compilers. - NOTREACHED(); - return nullptr; -} - -// Configures the default size and flex value for the specified |container| -// of the given |tri_view|. Used by CreateDefaultRowView(). -void ConfigureDefaultSizeAndFlex(TriView* tri_view, - TriView::Container container) { - int min_width = 0; - switch (container) { - case TriView::Container::START: - min_width = kTrayPopupItemMinStartWidth; - break; - case TriView::Container::CENTER: - tri_view->SetFlexForContainer(TriView::Container::CENTER, 1.f); - break; - case TriView::Container::END: - min_width = kTrayPopupItemMinEndWidth; - break; - } - - tri_view->SetMinSize(container, - gfx::Size(min_width, kTrayPopupItemMinHeight)); - constexpr int kTrayPopupItemMaxHeight = 144; - tri_view->SetMaxSize( - container, - gfx::Size(SizeRangeLayout::kAbsoluteMaxSize, kTrayPopupItemMaxHeight)); -} - -class BorderlessLabelButton : public views::LabelButton { - public: - BorderlessLabelButton(views::ButtonListener* listener, - const base::string16& text) - : LabelButton(listener, text) { - const int kHorizontalPadding = 20; - SetBorder(views::CreateEmptyBorder(gfx::Insets(0, kHorizontalPadding))); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::BUTTON); - style.SetupLabel(label()); - SetHorizontalAlignment(gfx::ALIGN_CENTER); - SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); - - TrayPopupUtils::ConfigureTrayPopupButton(this); - } - - ~BorderlessLabelButton() override {} - - // views::LabelButton: - int GetHeightForWidth(int width) const override { return kMenuButtonSize; } - - private: - // TODO(estade,bruthig): there's a lot in common here with ActionableView. - // Find a way to share. See related TODO on InkDropHostView::SetInkDropMode(). - std::unique_ptr<views::InkDrop> CreateInkDrop() override { - return TrayPopupUtils::CreateInkDrop(TrayPopupInkDropStyle::INSET_BOUNDS, - this); - } - - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override { - return TrayPopupUtils::CreateInkDropRipple( - TrayPopupInkDropStyle::INSET_BOUNDS, this, - GetInkDropCenterBasedOnLastEvent()); - } - - std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() - const override { - return TrayPopupUtils::CreateInkDropHighlight( - TrayPopupInkDropStyle::INSET_BOUNDS, this); - } - - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override { - return TrayPopupUtils::CreateInkDropMask( - TrayPopupInkDropStyle::INSET_BOUNDS, this); - } - - DISALLOW_COPY_AND_ASSIGN(BorderlessLabelButton); -}; - -} // namespace - -TriView* TrayPopupUtils::CreateDefaultRowView() { - TriView* tri_view = CreateMultiTargetRowView(); - - tri_view->SetContainerLayout( - TriView::Container::START, - CreateDefaultLayoutManager(TriView::Container::START)); - tri_view->SetContainerLayout( - TriView::Container::CENTER, - CreateDefaultLayoutManager(TriView::Container::CENTER)); - tri_view->SetContainerLayout( - TriView::Container::END, - CreateDefaultLayoutManager(TriView::Container::END)); - - return tri_view; -} - -TriView* TrayPopupUtils::CreateSubHeaderRowView() { - TriView* tri_view = CreateMultiTargetRowView(); - tri_view->SetInsets(gfx::Insets(0, kTrayPopupPaddingHorizontal, 0, 0)); - tri_view->SetContainerVisible(TriView::Container::START, false); - tri_view->SetContainerLayout( - TriView::Container::END, - CreateDefaultLayoutManager(TriView::Container::END)); - return tri_view; -} - -TriView* TrayPopupUtils::CreateMultiTargetRowView() { - TriView* tri_view = new TriView(0 /* padding_between_items */); - - tri_view->SetInsets(gfx::Insets(0, kMenuExtraMarginFromLeftEdge, 0, 0)); - - ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::START); - ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::CENTER); - ConfigureDefaultSizeAndFlex(tri_view, TriView::Container::END); - - tri_view->SetContainerLayout(TriView::Container::START, - base::MakeUnique<views::FillLayout>()); - tri_view->SetContainerLayout(TriView::Container::CENTER, - base::MakeUnique<views::FillLayout>()); - tri_view->SetContainerLayout(TriView::Container::END, - base::MakeUnique<views::FillLayout>()); - - return tri_view; -} - -views::Label* TrayPopupUtils::CreateDefaultLabel() { - views::Label* label = new views::Label(); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - label->SetBorder( - views::CreateEmptyBorder(0, 0, 0, kTrayPopupLabelRightPadding)); - // Frequently the label will paint to a layer that's non-opaque, so subpixel - // rendering won't work unless we explicitly set a background. See - // crbug.com/686363 - label->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); - label->SetBackgroundColor(kBackgroundColor); - return label; -} - -views::ImageView* TrayPopupUtils::CreateMainImageView() { - return new FixedSizedImageView(kTrayPopupItemMinStartWidth, - kTrayPopupItemMinHeight); -} - -views::ImageView* TrayPopupUtils::CreateMoreImageView() { - views::ImageView* image = - new FixedSizedImageView(kMenuIconSize, kMenuIconSize); - image->EnableCanvasFlippingForRTLUI(true); - image->SetImage( - gfx::CreateVectorIcon(kSystemMenuArrowRightIcon, kMenuIconColor)); - return image; -} - -views::Slider* TrayPopupUtils::CreateSlider(views::SliderListener* listener) { - views::Slider* slider = new views::Slider(listener); - slider->SetBorder(views::CreateEmptyBorder(gfx::Insets(0, 16))); - return slider; -} - -views::ToggleButton* TrayPopupUtils::CreateToggleButton( - views::ButtonListener* listener, - int accessible_name_id) { - views::ToggleButton* toggle = new views::ToggleButton(listener); - const gfx::Size toggle_size(toggle->GetPreferredSize()); - const int vertical_padding = (kMenuButtonSize - toggle_size.height()) / 2; - const int horizontal_padding = - (kTrayToggleButtonWidth - toggle_size.width()) / 2; - toggle->SetBorder(views::CreateEmptyBorder( - gfx::Insets(vertical_padding, horizontal_padding))); - toggle->SetFocusPainter(CreateFocusPainter()); - toggle->SetAccessibleName(l10n_util::GetStringUTF16(accessible_name_id)); - return toggle; -} - -std::unique_ptr<views::Painter> TrayPopupUtils::CreateFocusPainter() { - return views::Painter::CreateSolidFocusPainter( - kFocusBorderColor, kFocusBorderThickness, gfx::InsetsF()); -} - -void TrayPopupUtils::ConfigureTrayPopupButton(views::CustomButton* button) { - // All buttons that call into here want this focus painter, but - // SetFocusPainter is defined separately on derived classes and isn't part of - // CustomButton. TODO(estade): Address this. - // button->SetFocusPainter(TrayPopupUtils::CreateFocusPainter()); - button->SetFocusForPlatform(); - - button->SetInkDropMode(views::InkDropHostView::InkDropMode::ON); - button->set_has_ink_drop_action_on_click(true); - button->set_ink_drop_base_color(kTrayPopupInkDropBaseColor); - button->set_ink_drop_visible_opacity(kTrayPopupInkDropRippleOpacity); -} - -void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) { - view->set_id(VIEW_ID_STICKY_HEADER); - view->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); - view->SetBorder( - views::CreateEmptyBorder(gfx::Insets(kMenuSeparatorVerticalPadding, 0))); - view->SetPaintToLayer(); - view->layer()->SetFillsBoundsOpaquely(false); -} - -void TrayPopupUtils::ShowStickyHeaderSeparator(views::View* view, - bool show_separator) { - if (show_separator) { - view->SetBorder(views::CreatePaddedBorder( - views::CreateSolidSidedBorder(0, 0, kSeparatorWidth, 0, - kMenuSeparatorColor), - gfx::Insets(kMenuSeparatorVerticalPadding, 0, - kMenuSeparatorVerticalPadding - kSeparatorWidth, 0))); - } else { - view->SetBorder(views::CreateEmptyBorder( - gfx::Insets(kMenuSeparatorVerticalPadding, 0))); - } - view->SchedulePaint(); -} - -void TrayPopupUtils::ConfigureContainer(TriView::Container container, - views::View* container_view) { - container_view->SetLayoutManager( - CreateDefaultLayoutManager(container).release()); -} - -views::LabelButton* TrayPopupUtils::CreateTrayPopupBorderlessButton( - views::ButtonListener* listener, - const base::string16& text) { - return new BorderlessLabelButton(listener, text); -} - -views::LabelButton* TrayPopupUtils::CreateTrayPopupButton( - views::ButtonListener* listener, - const base::string16& text) { - auto* button = views::MdTextButton::Create(listener, text); - button->SetProminent(true); - return button; -} - -views::Separator* TrayPopupUtils::CreateVerticalSeparator() { - views::Separator* separator = new views::Separator(); - separator->SetPreferredHeight(24); - separator->SetColor(kMenuSeparatorColor); - return separator; -} - -std::unique_ptr<views::InkDrop> TrayPopupUtils::CreateInkDrop( - TrayPopupInkDropStyle ink_drop_style, - views::InkDropHostView* host) { - std::unique_ptr<views::InkDropImpl> ink_drop = - base::MakeUnique<views::InkDropImpl>(host, host->size()); - ink_drop->SetAutoHighlightMode( - views::InkDropImpl::AutoHighlightMode::SHOW_ON_RIPPLE); - ink_drop->SetShowHighlightOnHover(false); - - return std::move(ink_drop); -} - -std::unique_ptr<views::InkDropRipple> TrayPopupUtils::CreateInkDropRipple( - TrayPopupInkDropStyle ink_drop_style, - const views::View* host, - const gfx::Point& center_point, - SkColor color) { - return base::MakeUnique<views::FloodFillInkDropRipple>( - host->size(), TrayPopupUtils::GetInkDropInsets(ink_drop_style), - center_point, color, kTrayPopupInkDropRippleOpacity); -} - -std::unique_ptr<views::InkDropHighlight> TrayPopupUtils::CreateInkDropHighlight( - TrayPopupInkDropStyle ink_drop_style, - const views::View* host, - SkColor color) { - const gfx::Rect bounds = - TrayPopupUtils::GetInkDropBounds(ink_drop_style, host); - std::unique_ptr<views::InkDropHighlight> highlight( - new views::InkDropHighlight(bounds.size(), 0, - gfx::PointF(bounds.CenterPoint()), color)); - highlight->set_visible_opacity(kTrayPopupInkDropHighlightOpacity); - return highlight; -} - -std::unique_ptr<views::InkDropMask> TrayPopupUtils::CreateInkDropMask( - TrayPopupInkDropStyle ink_drop_style, - const views::View* host) { - if (ink_drop_style == TrayPopupInkDropStyle::FILL_BOUNDS) - return nullptr; - - const gfx::Size layer_size = host->size(); - switch (ink_drop_style) { - case TrayPopupInkDropStyle::HOST_CENTERED: { - const gfx::Rect mask_bounds = - GetInkDropBounds(TrayPopupInkDropStyle::HOST_CENTERED, host); - const int radius = - std::min(mask_bounds.width(), mask_bounds.height()) / 2; - return base::MakeUnique<views::CircleInkDropMask>( - layer_size, mask_bounds.CenterPoint(), radius); - } - case TrayPopupInkDropStyle::INSET_BOUNDS: { - const gfx::Insets mask_insets = - GetInkDropInsets(TrayPopupInkDropStyle::INSET_BOUNDS); - return base::MakeUnique<views::RoundRectInkDropMask>( - layer_size, mask_insets, kTrayPopupInkDropCornerRadius); - } - case TrayPopupInkDropStyle::FILL_BOUNDS: - // Handled by quick return above. - break; - } - // Required by some compilers. - NOTREACHED(); - return nullptr; -} - -gfx::Insets TrayPopupUtils::GetInkDropInsets( - TrayPopupInkDropStyle ink_drop_style) { - gfx::Insets insets; - if (ink_drop_style == TrayPopupInkDropStyle::HOST_CENTERED || - ink_drop_style == TrayPopupInkDropStyle::INSET_BOUNDS) { - insets.Set(kTrayPopupInkDropInset, kTrayPopupInkDropInset, - kTrayPopupInkDropInset, kTrayPopupInkDropInset); - } - return insets; -} - -gfx::Rect TrayPopupUtils::GetInkDropBounds(TrayPopupInkDropStyle ink_drop_style, - const views::View* host) { - gfx::Rect bounds = host->GetLocalBounds(); - bounds.Inset(GetInkDropInsets(ink_drop_style)); - return bounds; -} - -views::Separator* TrayPopupUtils::CreateListItemSeparator(bool left_inset) { - views::Separator* separator = new views::Separator(); - separator->SetColor(kMenuSeparatorColor); - separator->SetBorder(views::CreateEmptyBorder( - kMenuSeparatorVerticalPadding - views::Separator::kThickness, - left_inset - ? kMenuExtraMarginFromLeftEdge + kMenuButtonSize + - kTrayPopupLabelHorizontalPadding - : 0, - kMenuSeparatorVerticalPadding, 0)); - return separator; -} - -views::Separator* TrayPopupUtils::CreateListSubHeaderSeparator() { - views::Separator* separator = new views::Separator(); - separator->SetColor(kMenuSeparatorColor); - separator->SetBorder(views::CreateEmptyBorder( - kMenuSeparatorVerticalPadding - views::Separator::kThickness, 0, 0, 0)); - return separator; -} - -bool TrayPopupUtils::CanOpenWebUISettings(LoginStatus status) { - // TODO(tdanderson): Consider moving this into WmShell, or introduce a - // CanShowSettings() method in each delegate type that has a - // ShowSettings() method. - return status != LoginStatus::NOT_LOGGED_IN && - status != LoginStatus::LOCKED && - !WmShell::Get()->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); -} - -} // namespace ash
diff --git a/ash/system/tray/tray_popup_utils.h b/ash/system/tray/tray_popup_utils.h deleted file mode 100644 index 53c1ea8..0000000 --- a/ash/system/tray/tray_popup_utils.h +++ /dev/null
@@ -1,221 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_POPUP_UTILS_H_ -#define ASH_SYSTEM_TRAY_TRAY_POPUP_UTILS_H_ - -#include <memory> - -#include "ash/common/login_status.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_ink_drop_style.h" -#include "ash/system/tray/tri_view.h" -#include "base/strings/string16.h" - -namespace views { -class ButtonListener; -class CustomButton; -class ImageView; -class InkDrop; -class InkDropRipple; -class InkDropHighlight; -class InkDropHostView; -class InkDropMask; -class Label; -class LabelButton; -class Painter; -class Separator; -class Slider; -class SliderListener; -class ToggleButton; -} // namespace views - -namespace ash { - -// Factory/utility functions used by the system menu. -class TrayPopupUtils { - public: - // Creates a default container view to be used by system menu rows that are - // either a single targetable area or not targetable at all. The caller takes - // over ownership of the created view. - // - // The returned view consists of 3 regions: START, CENTER, and END. Any child - // Views added to the START and END containers will be added horizontally and - // any Views added to the CENTER container will be added vertically. - // - // The START and END containers have a fixed minimum width but can grow into - // the CENTER container if space is required and available. - // - // The CENTER container has a flexible width. - static TriView* CreateDefaultRowView(); - - // Creates a container view to be used by system menu sub-section header rows. - // The caller takes over ownership of the created view. - // - // The returned view consists of 2 regions: CENTER, and END having the same - // properties as when using |CreateMultiTargetRowView|. The START container is - // hidden. - // The END container has a fixed minimum width but can grow into the CENTER - // container if space is required and available. The CENTER container has a - // flexible width. - static TriView* CreateSubHeaderRowView(); - - // Creates a container view to be used by system menu rows that want to embed - // a targetable area within one (or more) of the containers OR by any row - // that requires a non-default layout within the container views. The returned - // view will have the following configurations: - // - default minimum row height - // - default minimum width for the START and END containers - // - default left and right insets - // - default container flex values - // - Each container view will have a FillLayout installed on it - // - // The caller takes over ownership of the created view. - // - // The START and END containers have a fixed minimum width but can grow into - // the CENTER container if space is required and available. The CENTER - // container has a flexible width. - // - // Clients can use ConfigureContainer() to configure their own container views - // before adding them to the returned TriView. - static TriView* CreateMultiTargetRowView(); - - // Returns a label that has been configured for system menu layout. This - // should be used by all rows that require a label, i.e. both default and - // detailed rows should use this. - // - // TODO(bruthig): Update all system menu rows to use this. - static views::Label* CreateDefaultLabel(); - - // Returns an image view to be used in the main image region of a system menu - // row. This should be used by all rows that have a main image, i.e. both - // default and detailed rows should use this. - // - // TODO(bruthig): Update all system menu rows to use this. - static views::ImageView* CreateMainImageView(); - - // Returns an image view to be used in the 'more' region of default rows. This - // is used for all 'more' images as well as other images that appear in this - // region, e.g. audio output icon. - // - // TODO(bruthig): Update all default rows to use this. - static views::ImageView* CreateMoreImageView(); - - // Returns a slider configured for proper layout within a TriView container - // with a FillLayout. - static views::Slider* CreateSlider(views::SliderListener* listener); - - // Returns a ToggleButton that has been configured for system menu layout. - static views::ToggleButton* CreateToggleButton( - views::ButtonListener* listener, - int accessible_name_id); - - // Creates a default focus painter used for most things in tray popups. - static std::unique_ptr<views::Painter> CreateFocusPainter(); - - // Common setup for various buttons in the system menu. - static void ConfigureTrayPopupButton(views::CustomButton* button); - - // Sets up |view| to be a sticky header in a tray detail scroll view. - static void ConfigureAsStickyHeader(views::View* view); - - // Configures a |view| to have a visible separator below. - static void ShowStickyHeaderSeparator(views::View* view, bool show_separator); - - // Configures |container_view| just like CreateDefaultRowView() would - // configure |container| on its returned TriView. To be used when mutliple - // targetable areas are required within a single row. - static void ConfigureContainer(TriView::Container container, - views::View* container_view); - - // Creates a button for use in the system menu that only has a visible border - // when being hovered/clicked. Caller assumes ownership. - static views::LabelButton* CreateTrayPopupBorderlessButton( - views::ButtonListener* listener, - const base::string16& text); - - // Creates a button for use in the system menu. For MD, this is a prominent - // text - // button. For non-MD, this does the same thing as the above. Caller assumes - // ownership. - static views::LabelButton* CreateTrayPopupButton( - views::ButtonListener* listener, - const base::string16& text); - - // Creates and returns a vertical separator to be used between two items in a - // material design system menu row. The caller assumes ownership of the - // returned separator. - static views::Separator* CreateVerticalSeparator(); - - // Creates in InkDrop instance for |host| according to the |ink_drop_style|. - // All styles are configured to show the highlight when the ripple is visible. - // - // All targetable views in the system menu should delegate - // InkDropHost::CreateInkDrop() calls here. - static std::unique_ptr<views::InkDrop> CreateInkDrop( - TrayPopupInkDropStyle ink_drop_style, - views::InkDropHostView* host); - - // Creates an InkDropRipple instance for |host| according to the - // |ink_drop_style|. The ripple will be centered on |center_point|. - // - // All targetable views in the system menu should delegate - // InkDropHost::CreateInkDropRipple() calls here. - static std::unique_ptr<views::InkDropRipple> CreateInkDropRipple( - TrayPopupInkDropStyle ink_drop_style, - const views::View* host, - const gfx::Point& center_point, - SkColor color = kTrayPopupInkDropBaseColor); - - // Creates in InkDropHighlight instance for |host| according to the - // |ink_drop_style|. - // - // All targetable views in the system menu should delegate - // InkDropHost::CreateInkDropHighlight() calls here. - static std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight( - TrayPopupInkDropStyle ink_drop_style, - const views::View* host, - SkColor color = kTrayPopupInkDropBaseColor); - - // Creates in InkDropMask instance for |host| according to the - // |ink_drop_style|. May return null. - // - // All targetable views in the system menu should delegate - // InkDropHost::CreateInkDropMask() calls here. - static std::unique_ptr<views::InkDropMask> CreateInkDropMask( - TrayPopupInkDropStyle ink_drop_style, - const views::View* host); - - // Creates and returns a horizontal separator line to be drawn between rows - // in a detailed view. If |left_inset| is true, then the separator is inset on - // the left by the width normally occupied by an icon. Caller assumes - // ownership of the returned separator. - static views::Separator* CreateListItemSeparator(bool left_inset); - - // Creates and returns a horizontal separator line to be drawn between rows - // in a detailed view above the sub-header rows. Caller assumes ownership of - // the returned separator. - static views::Separator* CreateListSubHeaderSeparator(); - - // Returns true if it is possible to open WebUI settings in a browser window, - // i.e., the user is logged in, not on the lock screen, and not in a secondary - // account flow. - static bool CanOpenWebUISettings(LoginStatus status); - - private: - // Returns the effective ink drop insets for |host| according to the - // |ink_drop_style|. - static gfx::Insets GetInkDropInsets(TrayPopupInkDropStyle ink_drop_style); - - // Returns the effective ink drop bounds for |host| according to the - // |ink_drop_style|. - static gfx::Rect GetInkDropBounds(TrayPopupInkDropStyle ink_drop_style, - const views::View* host); - - DISALLOW_IMPLICIT_CONSTRUCTORS(TrayPopupUtils); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_POPUP_UTILS_H_
diff --git a/ash/system/tray/tray_utils.cc b/ash/system/tray/tray_utils.cc deleted file mode 100644 index 5a42c80..0000000 --- a/ash/system/tray/tray_utils.cc +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tray_utils.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_view.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/views/border.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/button/md_text_button.h" -#include "ui/views/controls/label.h" - -namespace ash { - -void SetupLabelForTray(views::Label* label) { - if (MaterialDesignController::IsShelfMaterial()) { - // The text is drawn on an transparent bg, so we must disable subpixel - // rendering. - label->SetSubpixelRenderingEnabled(false); - label->SetFontList(gfx::FontList().Derive(2, gfx::Font::NORMAL, - gfx::Font::Weight::MEDIUM)); - } else { - label->SetFontList( - gfx::FontList().Derive(1, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)); - label->SetShadows(gfx::ShadowValues( - 1, - gfx::ShadowValue(gfx::Vector2d(0, 1), 0, SkColorSetARGB(64, 0, 0, 0)))); - label->SetAutoColorReadabilityEnabled(false); - label->SetEnabledColor(SK_ColorWHITE); - label->SetBackgroundColor(SkColorSetARGB(0, 255, 255, 255)); - } -} - -void SetTrayImageItemBorder(views::View* tray_view, ShelfAlignment alignment) { - if (MaterialDesignController::IsShelfMaterial()) - return; - - if (IsHorizontalAlignment(alignment)) { - tray_view->SetBorder( - views::CreateEmptyBorder(gfx::Insets(0, kTrayImageItemPadding))); - } else { - tray_view->SetBorder(views::CreateEmptyBorder(gfx::Insets( - kTrayImageItemPadding, - kTrayImageItemHorizontalPaddingVerticalAlignment))); - } -} - -void SetTrayLabelItemBorder(TrayItemView* tray_view, ShelfAlignment alignment) { - if (MaterialDesignController::IsShelfMaterial()) - return; - - if (IsHorizontalAlignment(alignment)) { - tray_view->SetBorder(views::CreateEmptyBorder( - 0, kTrayLabelItemHorizontalPaddingBottomAlignment, 0, - kTrayLabelItemHorizontalPaddingBottomAlignment)); - } else { - // Center the label for vertical launcher alignment. - int horizontal_padding = - std::max(0, (tray_view->GetPreferredSize().width() - - tray_view->label()->GetPreferredSize().width()) / - 2); - tray_view->SetBorder(views::CreateEmptyBorder( - kTrayLabelItemVerticalPaddingVerticalAlignment, horizontal_padding, - kTrayLabelItemVerticalPaddingVerticalAlignment, horizontal_padding)); - } -} - -} // namespace ash
diff --git a/ash/system/tray/tray_utils.h b/ash/system/tray/tray_utils.h deleted file mode 100644 index 9794c4f..0000000 --- a/ash/system/tray/tray_utils.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRAY_UTILS_H_ -#define ASH_SYSTEM_TRAY_TRAY_UTILS_H_ - -#include <vector> - -#include "ash/public/cpp/shelf_types.h" -#include "base/strings/string16.h" - -namespace views { -class Label; -class View; -} - -namespace ash { - -class TrayItemView; - -// Sets up a Label properly for the tray (sets color, font etc.). -void SetupLabelForTray(views::Label* label); - -// TODO(jennyz): refactor these two functions to SystemTrayItem. -// Sets the empty border of an image tray item for adjusting the space -// around it. -void SetTrayImageItemBorder(views::View* tray_view, ShelfAlignment alignment); -// Sets the empty border around a label tray item for adjusting the space -// around it. -void SetTrayLabelItemBorder(TrayItemView* tray_view, ShelfAlignment alignment); - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRAY_UTILS_H_
diff --git a/ash/system/tray/tri_view.cc b/ash/system/tray/tri_view.cc deleted file mode 100644 index a25ce00..0000000 --- a/ash/system/tray/tri_view.cc +++ /dev/null
@@ -1,179 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray/tri_view.h" - -#include "ash/system/tray/size_range_layout.h" -#include "base/logging.h" -#include "ui/views/border.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/layout/layout_manager.h" - -namespace ash { -namespace { - -// Converts TriView::Orientation values to views::BoxLayout::Orientation values. -views::BoxLayout::Orientation GetOrientation(TriView::Orientation orientation) { - switch (orientation) { - case TriView::Orientation::HORIZONTAL: - return views::BoxLayout::kHorizontal; - case TriView::Orientation::VERTICAL: - return views::BoxLayout::kVertical; - } - // Required for some compilers. - NOTREACHED(); - return views::BoxLayout::kHorizontal; -} - -// A View that will perform a layout if a child view's preferred size changes. -class RelayoutView : public views::View { - public: - RelayoutView() {} - - // views::View: - void ChildPreferredSizeChanged(View* child) override { Layout(); } - - private: - DISALLOW_COPY_AND_ASSIGN(RelayoutView); -}; - -} // namespace - -TriView::TriView() : TriView(0) {} - -TriView::TriView(int padding_between_containers) - : TriView(Orientation::HORIZONTAL, padding_between_containers) {} - -TriView::TriView(Orientation orientation) : TriView(orientation, 0) {} - -TriView::TriView(Orientation orientation, int padding_between_containers) - : box_layout_(new views::BoxLayout(GetOrientation(orientation), - 0, - 0, - padding_between_containers)), - start_container_layout_manager_(new SizeRangeLayout), - center_container_layout_manager_(new SizeRangeLayout), - end_container_layout_manager_(new SizeRangeLayout) { - AddChildView(new RelayoutView); - AddChildView(new RelayoutView); - AddChildView(new RelayoutView); - - GetContainer(Container::START) - ->SetLayoutManager(GetLayoutManager(Container::START)); - GetContainer(Container::CENTER) - ->SetLayoutManager(GetLayoutManager(Container::CENTER)); - GetContainer(Container::END) - ->SetLayoutManager(GetLayoutManager(Container::END)); - - box_layout_->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); - SetLayoutManager(box_layout_); - - enable_hierarchy_changed_dcheck_ = true; -} - -TriView::~TriView() { - enable_hierarchy_changed_dcheck_ = false; -} - -void TriView::SetMinHeight(int height) { - gfx::Size min_size; - - min_size = GetMinSize(TriView::Container::START); - min_size.set_height(height); - SetMinSize(TriView::Container::START, min_size); - - min_size = GetMinSize(TriView::Container::CENTER); - min_size.set_height(height); - SetMinSize(TriView::Container::CENTER, min_size); - - min_size = GetMinSize(TriView::Container::END); - min_size.set_height(height); - SetMinSize(TriView::Container::END, min_size); -} - -void TriView::SetMinSize(Container container, const gfx::Size& size) { - GetLayoutManager(container)->SetMinSize(size); -} - -gfx::Size TriView::GetMinSize(Container container) { - return GetLayoutManager(container)->min_size(); -} - -void TriView::SetMaxSize(Container container, const gfx::Size& size) { - GetLayoutManager(container)->SetMaxSize(size); -} - -void TriView::AddView(Container container, views::View* view) { - GetContainer(container)->AddChildView(view); -} - -void TriView::RemoveAllChildren(Container container, bool delete_children) { - GetContainer(container)->RemoveAllChildViews(delete_children); -} - -void TriView::SetInsets(const gfx::Insets& insets) { - box_layout_->set_inside_border_insets(insets); -} - -void TriView::SetContainerBorder(Container container, - std::unique_ptr<views::Border> border) { - GetContainer(container)->SetBorder(std::move(border)); -} - -void TriView::SetContainerVisible(Container container, bool visible) { - GetContainer(container)->SetVisible(visible); -} - -void TriView::SetFlexForContainer(Container container, int flex) { - box_layout_->SetFlexForView(GetContainer(container), flex); -} - -void TriView::SetContainerLayout( - Container container, - std::unique_ptr<views::LayoutManager> layout_manager) { - GetLayoutManager(container)->SetLayoutManager(std::move(layout_manager)); -} - -void TriView::ViewHierarchyChanged( - const views::View::ViewHierarchyChangedDetails& details) { - views::View::ViewHierarchyChanged(details); - if (!enable_hierarchy_changed_dcheck_) - return; - - if (details.parent == this) { - if (details.is_add) { - DCHECK(false) - << "Child views should not be added directly. They should be added " - "using TriView::AddView()."; - } else { - DCHECK(false) << "Container views should not be removed."; - } - } -} - -const char* TriView::GetClassName() const { - return "TriView"; -} - -views::View* TriView::GetContainer(Container container) { - return child_at(static_cast<int>(container)); -} - -SizeRangeLayout* TriView::GetLayoutManager(Container container) { - switch (container) { - case Container::START: - return start_container_layout_manager_; - case Container::CENTER: - return center_container_layout_manager_; - case Container::END: - return end_container_layout_manager_; - } - // Required for some compilers. - NOTREACHED(); - return nullptr; -} - -} // namespace ash
diff --git a/ash/system/tray/tri_view.h b/ash/system/tray/tri_view.h deleted file mode 100644 index 86359aa..0000000 --- a/ash/system/tray/tri_view.h +++ /dev/null
@@ -1,157 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRI_VIEW_H_ -#define ASH_SYSTEM_TRAY_TRI_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/size.h" -#include "ui/views/view.h" - -namespace views { -class Border; -class BoxLayout; -class LayoutManager; -} // namespace views - -namespace ash { -class SizeRangeLayout; - -// A View which has 3 child containers (START, CENTER, END) which can be -// arranged vertically or horizontally. The child containers can have minimum -// and/or maximum preferred size defined as well as a flex weight that is used -// to distribute excess space across the main axis, i.e. flexible width for the -// horizontal orientation. By default all the containers have a flex weight of -// 0, meaning no flexibility, and no minimum or maximum size. -// -// Child views should not be added to |this| directly via View::AddChildView() -// or View::AddChildViewAt() and will fail a DCHECK() if attempted. -// -// Views added to the containers are laid out as per the LayoutManager that has -// been installed on that container. By default a BoxLayout manager is installed -// on each container with the same orientation as |this| has been created with. -// The default BoxLayout will use a center alignment for both the main axis and -// cross axis alignment. -class ASH_EXPORT TriView : public views::View { - public: - enum class Orientation { - HORIZONTAL, - VERTICAL, - }; - - // The different containers that child Views can be added to. - enum class Container { START = 0, CENTER = 1, END = 2 }; - - // Constructs a layout with horizontal orientation and 0 padding between - // containers. - TriView(); - - // Creates |this| with a Horizontal orientation and the specified padding - // between containers. - // - // TODO(bruthig): The |padding_between_containers| can only be set on - // BoxLayouts during construction. Investigate whether this can be a mutable - // property of BoxLayouts and if so consider dropping it as a constructor - // parameter here. - explicit TriView(int padding_between_containers); - - // Creates |this| with the specified orientation and 0 padding between - // containers. - explicit TriView(Orientation orientation); - - // Creates this with the specified |orientation| and - // |padding_between_containers|. - TriView(Orientation orientation, int padding_between_containers); - - ~TriView() override; - - // Set the minimum height for all containers to |height|. - void SetMinHeight(int height); - - // Set the minimum size for the given |container|. - void SetMinSize(Container container, const gfx::Size& size); - - // Get the minimum size for the given |container|. - gfx::Size GetMinSize(Container container); - - // Set the maximum size for the given |container|. - void SetMaxSize(Container container, const gfx::Size& size); - - // Adds the child |view| to the specified |container|. - void AddView(Container container, views::View* view); - - // Removes all the children from the specified |container|. If - // |delete_children| is true, the views are deleted, unless marked as not - // parent owned. - void RemoveAllChildren(Container container, bool delete_children); - - // During layout the |insets| are applied to the host views entire space - // before allocating the remaining space to the container views. - void SetInsets(const gfx::Insets& insets); - - // Sets the border for the given |container|. - void SetContainerBorder(Container container, - std::unique_ptr<views::Border> border); - - // Sets whether the |container| is visible. During a layout the space will be - // allocated to the visible containers only. i.e. non-visible containers will - // not be allocated any space. - void SetContainerVisible(Container container, bool visible); - - // Sets the flex weight for the given |container|. Using the preferred size as - // the basis, free space along the main axis is distributed to views in the - // ratio of their flex weights. Similarly, if the views will overflow the - // parent, space is subtracted in these ratios. - // - // A flex of 0 means this view is not resized. Flex values must not be - // negative. - // - // Note that non-zero flex values will take precedence over size constraints. - // i.e. even if |container| has a max size set the space allocated during - // layout may be larger if |flex| > 0 and similar for min size constraints. - void SetFlexForContainer(Container container, int flex); - - // Sets the |layout_manager| used by the given |container|. - void SetContainerLayout(Container container, - std::unique_ptr<views::LayoutManager> layout_manager); - - protected: - // View: - void ViewHierarchyChanged( - const views::View::ViewHierarchyChangedDetails& details) override; - const char* GetClassName() const override; - - private: - friend class TriViewTest; - - // Returns the View for the given |container|. - views::View* GetContainer(Container container); - - // Returns the layout manager for the given |container|. - SizeRangeLayout* GetLayoutManager(Container container); - - // Type spcific layout manager installed on |this|. Responsible for laying out - // the container Views. - views::BoxLayout* box_layout_; - - SizeRangeLayout* start_container_layout_manager_; - SizeRangeLayout* center_container_layout_manager_; - SizeRangeLayout* end_container_layout_manager_; - - // In order to detect direct manipulation of child views the - // ViewHierarchyChanged() event override fails on a DCHECK. However, we need - // to manipulate the child views during construction/destruction so this flag - // is used to disable the DCHECK during construction/destruction. - bool enable_hierarchy_changed_dcheck_ = false; - - DISALLOW_COPY_AND_ASSIGN(TriView); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRI_VIEW_H_
diff --git a/ash/system/tray/tri_view_unittest.cc b/ash/system/tray/tri_view_unittest.cc deleted file mode 100644 index ed5b82f0..0000000 --- a/ash/system/tray/tri_view_unittest.cc +++ /dev/null
@@ -1,380 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <memory> - -#include "ash/system/tray/tri_view.h" -#include "base/memory/ptr_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/rect_conversions.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/test/test_layout_manager.h" -#include "ui/views/test/test_views.h" -#include "ui/views/view.h" - -namespace ash { -namespace { - -// Returns a layout manager that will size views according to their preferred -// size. -std::unique_ptr<views::LayoutManager> CreatePreferredSizeLayoutManager() { - auto layout = base::MakeUnique<views::BoxLayout>( - views::BoxLayout::kHorizontal, 0, 0, 0); - layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); - return std::move(layout); -} - -} // namespace - -class TriViewTest : public testing::Test { - public: - TriViewTest(); - - protected: - // Convenience function to get the minimum height of |container|. - int GetMinHeight(TriView::Container container) const; - - // Returns the bounds of |child| in the coordinate space of - // |tri_view_|. - gfx::Rect GetBoundsInHost(const views::View* child) const; - - // Wrapper functions to access the internals of |tri_view_|. - views::View* GetContainer(TriView::Container container) const; - - // The test target. - std::unique_ptr<TriView> tri_view_; - - private: - DISALLOW_COPY_AND_ASSIGN(TriViewTest); -}; - -TriViewTest::TriViewTest() : tri_view_(base::MakeUnique<TriView>()) {} - -int TriViewTest::GetMinHeight(TriView::Container container) const { - return tri_view_->GetMinSize(container).height(); -} - -gfx::Rect TriViewTest::GetBoundsInHost(const views::View* child) const { - gfx::RectF rect_f(child->bounds()); - views::View::ConvertRectToTarget(child, tri_view_.get(), &rect_f); - return ToNearestRect(rect_f); -} - -views::View* TriViewTest::GetContainer(TriView::Container container) const { - return tri_view_->GetContainer(container); -} - -TEST_F(TriViewTest, PaddingBetweenContainers) { - const int kPaddingBetweenContainers = 3; - const int kViewWidth = 10; - const int kViewHeight = 10; - const gfx::Size kViewSize(kViewWidth, kViewHeight); - const int kStartChildExpectedX = 0; - const int kCenterChildExpectedX = - kStartChildExpectedX + kViewWidth + kPaddingBetweenContainers; - const int kEndChildExpectedX = - kCenterChildExpectedX + kViewWidth + kPaddingBetweenContainers; - - tri_view_ = base::MakeUnique<TriView>(kPaddingBetweenContainers); - tri_view_->SetBounds(0, 0, 100, 10); - - views::View* start_child = new views::StaticSizedView(kViewSize); - views::View* center_child = new views::StaticSizedView(kViewSize); - views::View* end_child = new views::StaticSizedView(kViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->Layout(); - - EXPECT_EQ(kStartChildExpectedX, GetBoundsInHost(start_child).x()); - EXPECT_EQ(kCenterChildExpectedX, GetBoundsInHost(center_child).x()); - EXPECT_EQ(kEndChildExpectedX, GetBoundsInHost(end_child).x()); -} - -TEST_F(TriViewTest, VerticalOrientation) { - const int kViewWidth = 10; - const int kViewHeight = 10; - const gfx::Size kViewSize(kViewWidth, kViewHeight); - - tri_view_ = base::MakeUnique<TriView>(TriView::Orientation::VERTICAL); - tri_view_->SetBounds(0, 0, 10, 100); - - views::View* start_child = new views::StaticSizedView(kViewSize); - views::View* center_child = new views::StaticSizedView(kViewSize); - views::View* end_child = new views::StaticSizedView(kViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->Layout(); - - EXPECT_EQ(0, GetBoundsInHost(start_child).y()); - EXPECT_EQ(kViewWidth, GetBoundsInHost(center_child).y()); - EXPECT_EQ(kViewWidth * 2, GetBoundsInHost(end_child).y()); -} - -TEST_F(TriViewTest, MainAxisMinSize) { - tri_view_->SetBounds(0, 0, 100, 10); - const gfx::Size kMinSize(15, 10); - tri_view_->SetMinSize(TriView::Container::START, kMinSize); - views::View* child = new views::StaticSizedView(gfx::Size(10, 10)); - tri_view_->AddView(TriView::Container::CENTER, child); - - tri_view_->Layout(); - - EXPECT_EQ(kMinSize.width(), GetBoundsInHost(child).x()); -} - -TEST_F(TriViewTest, MainAxisMaxSize) { - tri_view_->SetBounds(0, 0, 100, 10); - const gfx::Size kMaxSize(10, 10); - - tri_view_->SetMaxSize(TriView::Container::START, kMaxSize); - views::View* start_child = new views::StaticSizedView(gfx::Size(20, 20)); - tri_view_->AddView(TriView::Container::START, start_child); - - views::View* center_child = new views::StaticSizedView(gfx::Size(10, 10)); - tri_view_->AddView(TriView::Container::CENTER, center_child); - - tri_view_->Layout(); - - EXPECT_EQ(kMaxSize.width(), GetBoundsInHost(center_child).x()); -} - -TEST_F(TriViewTest, ViewsAddedToCorrectContainers) { - views::View* start_child = new views::StaticSizedView(); - views::View* center_child = new views::StaticSizedView(); - views::View* end_child = new views::StaticSizedView(); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(start_child)); - EXPECT_EQ(1, GetContainer(TriView::Container::START)->child_count()); - - EXPECT_TRUE(GetContainer(TriView::Container::CENTER)->Contains(center_child)); - EXPECT_EQ(1, GetContainer(TriView::Container::CENTER)->child_count()); - - EXPECT_TRUE(GetContainer(TriView::Container::END)->Contains(end_child)); - EXPECT_EQ(1, GetContainer(TriView::Container::END)->child_count()); -} - -TEST_F(TriViewTest, MultipleViewsAddedToTheSameContainer) { - views::View* child1 = new views::StaticSizedView(); - views::View* child2 = new views::StaticSizedView(); - - tri_view_->AddView(TriView::Container::START, child1); - tri_view_->AddView(TriView::Container::START, child2); - - EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child1)); - EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child2)); -} - -TEST_F(TriViewTest, ViewsRemovedOnRemoveAllChildren) { - views::View* child1 = new views::StaticSizedView(); - views::View* child2 = new views::StaticSizedView(); - - tri_view_->AddView(TriView::Container::START, child1); - tri_view_->AddView(TriView::Container::START, child2); - - EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child1)); - EXPECT_TRUE(GetContainer(TriView::Container::START)->Contains(child2)); - EXPECT_EQ(2, GetContainer(TriView::Container::START)->child_count()); - - tri_view_->RemoveAllChildren(TriView::Container::START, false); - - EXPECT_FALSE(GetContainer(TriView::Container::START)->Contains(child1)); - EXPECT_FALSE(GetContainer(TriView::Container::START)->Contains(child2)); - EXPECT_EQ(0, GetContainer(TriView::Container::START)->child_count()); - - delete child1; - delete child2; -} - -TEST_F(TriViewTest, Insets) { - const int kInset = 3; - const int kViewHeight = 10; - const int kExpectedViewHeight = kViewHeight - 2 * kInset; - const gfx::Size kStartViewSize(10, kViewHeight); - const gfx::Size kCenterViewSize(100, kViewHeight); - const gfx::Size kEndViewSize(10, kViewHeight); - const int kHostWidth = 100; - - tri_view_->SetBounds(0, 0, kHostWidth, kViewHeight); - tri_view_->SetInsets(gfx::Insets(kInset)); - - views::View* start_child = new views::StaticSizedView(kStartViewSize); - views::View* center_child = new views::StaticSizedView(kCenterViewSize); - views::View* end_child = new views::StaticSizedView(kEndViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); - tri_view_->Layout(); - - EXPECT_EQ( - gfx::Rect(kInset, kInset, kStartViewSize.width(), kExpectedViewHeight), - GetBoundsInHost(start_child)); - EXPECT_EQ(gfx::Rect(kInset + kStartViewSize.width(), kInset, - kHostWidth - kStartViewSize.width() - - kEndViewSize.width() - 2 * kInset, - kExpectedViewHeight), - GetBoundsInHost(center_child)); - EXPECT_EQ(gfx::Rect(kHostWidth - kEndViewSize.width() - kInset, kInset, - kEndViewSize.width(), kExpectedViewHeight), - GetBoundsInHost(end_child)); -} - -TEST_F(TriViewTest, InvisibleContainerDoesntTakeUpSpace) { - const int kViewWidth = 10; - const int kViewHeight = 10; - const gfx::Size kViewSize(kViewWidth, kViewHeight); - - tri_view_->SetBounds(0, 0, 30, 10); - - views::View* start_child = new views::StaticSizedView(kViewSize); - views::View* center_child = new views::StaticSizedView(kViewSize); - views::View* end_child = new views::StaticSizedView(kViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->SetContainerVisible(TriView::Container::START, false); - tri_view_->Layout(); - - EXPECT_EQ(gfx::Rect(0, 0, 0, 0), GetBoundsInHost(start_child)); - EXPECT_EQ(0, GetBoundsInHost(center_child).x()); - EXPECT_EQ(kViewWidth, GetBoundsInHost(end_child).x()); - - tri_view_->SetContainerVisible(TriView::Container::START, true); - tri_view_->Layout(); - - EXPECT_EQ(0, GetBoundsInHost(start_child).x()); - EXPECT_EQ(kViewWidth, GetBoundsInHost(center_child).x()); - EXPECT_EQ(kViewWidth * 2, GetBoundsInHost(end_child).x()); -} - -TEST_F(TriViewTest, NonZeroFlex) { - const int kHostWidth = 100; - const gfx::Size kDefaultViewSize(10, 10); - const gfx::Size kCenterViewSize(100, 10); - const gfx::Size kExpectedCenterViewSize( - kHostWidth - 2 * kDefaultViewSize.width(), 10); - - tri_view_->SetBounds(0, 0, kHostWidth, 10); - - views::View* start_child = new views::StaticSizedView(kDefaultViewSize); - views::View* center_child = new views::StaticSizedView(kCenterViewSize); - views::View* end_child = new views::StaticSizedView(kDefaultViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); - tri_view_->Layout(); - - EXPECT_EQ(kDefaultViewSize, GetBoundsInHost(start_child).size()); - EXPECT_EQ(kExpectedCenterViewSize, GetBoundsInHost(center_child).size()); - EXPECT_EQ(kDefaultViewSize, GetBoundsInHost(end_child).size()); -} - -TEST_F(TriViewTest, NonZeroFlexTakesPrecedenceOverMinSize) { - const int kHostWidth = 25; - const gfx::Size kViewSize(10, 10); - const gfx::Size kMinCenterSize = kViewSize; - const gfx::Size kExpectedCenterSize(kHostWidth - 2 * kViewSize.width(), 10); - - tri_view_->SetBounds(0, 0, kHostWidth, 10); - - views::View* start_child = new views::StaticSizedView(kViewSize); - views::View* center_child = new views::StaticSizedView(kViewSize); - views::View* end_child = new views::StaticSizedView(kViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); - tri_view_->SetMinSize(TriView::Container::CENTER, kMinCenterSize); - tri_view_->Layout(); - - EXPECT_EQ(kViewSize, GetBoundsInHost(start_child).size()); - EXPECT_EQ(kExpectedCenterSize, - GetBoundsInHost(GetContainer(TriView::Container::CENTER)).size()); - EXPECT_EQ(kViewSize, GetBoundsInHost(end_child).size()); -} - -TEST_F(TriViewTest, NonZeroFlexTakesPrecedenceOverMaxSize) { - const int kHostWidth = 100; - const gfx::Size kViewSize(10, 10); - const gfx::Size kMaxCenterSize(20, 10); - const gfx::Size kExpectedCenterSize(kHostWidth - 2 * kViewSize.width(), 10); - - tri_view_->SetBounds(0, 0, kHostWidth, 10); - - views::View* start_child = new views::StaticSizedView(kViewSize); - views::View* center_child = new views::StaticSizedView(kViewSize); - views::View* end_child = new views::StaticSizedView(kViewSize); - - tri_view_->AddView(TriView::Container::START, start_child); - tri_view_->AddView(TriView::Container::CENTER, center_child); - tri_view_->AddView(TriView::Container::END, end_child); - - tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); - tri_view_->SetMaxSize(TriView::Container::CENTER, kMaxCenterSize); - tri_view_->Layout(); - - EXPECT_EQ(kViewSize, GetBoundsInHost(start_child).size()); - EXPECT_EQ(kExpectedCenterSize, - GetBoundsInHost(GetContainer(TriView::Container::CENTER)).size()); - EXPECT_EQ(kViewSize, GetBoundsInHost(end_child).size()); -} - -TEST_F(TriViewTest, ChildViewsPreferredSizeChanged) { - const int kHostWidth = 500; - const gfx::Size kMinStartSize(100, 10); - - tri_view_->SetBounds(0, 0, kHostWidth, 10); - tri_view_->SetMinSize(TriView::Container::START, kMinStartSize); - tri_view_->SetContainerLayout(TriView::Container::START, - CreatePreferredSizeLayoutManager()); - tri_view_->SetFlexForContainer(TriView::Container::CENTER, 1.f); - tri_view_->Layout(); - - views::ProportionallySizedView* child_view = - new views::ProportionallySizedView(1); - tri_view_->AddView(TriView::Container::START, child_view); - - child_view->SetPreferredWidth(1); - EXPECT_EQ(child_view->GetPreferredSize(), child_view->size()); - - child_view->SetPreferredWidth(2); - EXPECT_EQ(child_view->GetPreferredSize(), child_view->size()); -} - -TEST_F(TriViewTest, SetMinHeight) { - const int kMinHeight = 10; - - EXPECT_NE(kMinHeight, GetMinHeight(TriView::Container::START)); - EXPECT_NE(kMinHeight, GetMinHeight(TriView::Container::CENTER)); - EXPECT_NE(kMinHeight, GetMinHeight(TriView::Container::END)); - - tri_view_->SetMinHeight(kMinHeight); - - EXPECT_EQ(kMinHeight, GetMinHeight(TriView::Container::START)); - EXPECT_EQ(kMinHeight, GetMinHeight(TriView::Container::CENTER)); - EXPECT_EQ(kMinHeight, GetMinHeight(TriView::Container::END)); -} - -} // namespace ash
diff --git a/ash/system/tray/view_click_listener.h b/ash/system/tray/view_click_listener.h deleted file mode 100644 index 3e7cf263..0000000 --- a/ash/system/tray/view_click_listener.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_VIEW_CLICK_LISTENER_H_ -#define ASH_SYSTEM_TRAY_VIEW_CLICK_LISTENER_H_ - -#include "ash/ash_export.h" - -namespace views { -class View; -} - -namespace ash { - -class ASH_EXPORT ViewClickListener { - public: - virtual void OnViewClicked(views::View* sender) = 0; - - protected: - virtual ~ViewClickListener() {} -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_VIEW_CLICK_LISTENER_H_
diff --git a/ash/system/tray_accessibility.cc b/ash/system/tray_accessibility.cc deleted file mode 100644 index 901c25b0..0000000 --- a/ash/system/tray_accessibility.cc +++ /dev/null
@@ -1,444 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray_accessibility.h" - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/accessibility_types.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_item_more.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/views/controls/button/custom_button.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -enum AccessibilityState { - A11Y_NONE = 0, - A11Y_SPOKEN_FEEDBACK = 1 << 0, - A11Y_HIGH_CONTRAST = 1 << 1, - A11Y_SCREEN_MAGNIFIER = 1 << 2, - A11Y_LARGE_CURSOR = 1 << 3, - A11Y_AUTOCLICK = 1 << 4, - A11Y_VIRTUAL_KEYBOARD = 1 << 5, - A11Y_BRAILLE_DISPLAY_CONNECTED = 1 << 6, -}; - -uint32_t GetAccessibilityState() { - AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); - uint32_t state = A11Y_NONE; - if (delegate->IsSpokenFeedbackEnabled()) - state |= A11Y_SPOKEN_FEEDBACK; - if (delegate->IsHighContrastEnabled()) - state |= A11Y_HIGH_CONTRAST; - if (delegate->IsMagnifierEnabled()) - state |= A11Y_SCREEN_MAGNIFIER; - if (delegate->IsLargeCursorEnabled()) - state |= A11Y_LARGE_CURSOR; - if (delegate->IsAutoclickEnabled()) - state |= A11Y_AUTOCLICK; - if (delegate->IsVirtualKeyboardEnabled()) - state |= A11Y_VIRTUAL_KEYBOARD; - if (delegate->IsBrailleDisplayConnected()) - state |= A11Y_BRAILLE_DISPLAY_CONNECTED; - return state; -} - -LoginStatus GetCurrentLoginStatus() { - return WmShell::Get()->system_tray_delegate()->GetUserLoginStatus(); -} - -} // namespace - -namespace tray { - -class DefaultAccessibilityView : public TrayItemMore { - public: - explicit DefaultAccessibilityView(SystemTrayItem* owner) - : TrayItemMore(owner) { - base::string16 label = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY); - SetLabel(label); - SetAccessibleName(label); - set_id(test::kAccessibilityTrayItemViewId); - } - - ~DefaultAccessibilityView() override {} - - protected: - // TrayItemMore: - void UpdateStyle() override { - TrayItemMore::UpdateStyle(); - std::unique_ptr<TrayPopupItemStyle> style = CreateStyle(); - SetImage(gfx::CreateVectorIcon(kSystemMenuAccessibilityIcon, - style->GetIconColor())); - } - - private: - DISALLOW_COPY_AND_ASSIGN(DefaultAccessibilityView); -}; - -//////////////////////////////////////////////////////////////////////////////// -// ash::tray::AccessibilityPopupView - -AccessibilityPopupView::AccessibilityPopupView(uint32_t enabled_state_bits) - : TrayNotificationView(IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK), - label_(CreateLabel(enabled_state_bits)) { - InitView(label_); -} - -views::Label* AccessibilityPopupView::CreateLabel(uint32_t enabled_state_bits) { - DCHECK((enabled_state_bits & - (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED)) != 0); - base::string16 text; - if (enabled_state_bits & A11Y_BRAILLE_DISPLAY_CONNECTED) { - text.append(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_BRAILLE_DISPLAY_CONNECTED_BUBBLE)); - } - if (enabled_state_bits & A11Y_SPOKEN_FEEDBACK) { - if (!text.empty()) - text.append(base::ASCIIToUTF16(" ")); - text.append(l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_SPOKEN_FEEDBACK_ENABLED_BUBBLE)); - } - views::Label* label = new views::Label(text); - label->SetMultiLine(true); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - return label; -} - -//////////////////////////////////////////////////////////////////////////////// -// ash::tray::AccessibilityDetailedView - -AccessibilityDetailedView::AccessibilityDetailedView(SystemTrayItem* owner, - LoginStatus login) - : TrayDetailsView(owner), - spoken_feedback_view_(nullptr), - high_contrast_view_(nullptr), - screen_magnifier_view_(nullptr), - large_cursor_view_(nullptr), - help_view_(nullptr), - settings_view_(nullptr), - autoclick_view_(nullptr), - virtual_keyboard_view_(nullptr), - spoken_feedback_enabled_(false), - high_contrast_enabled_(false), - screen_magnifier_enabled_(false), - large_cursor_enabled_(false), - autoclick_enabled_(false), - virtual_keyboard_enabled_(false), - login_(login) { - Reset(); - AppendAccessibilityList(); - CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE); - Layout(); -} - -void AccessibilityDetailedView::AppendAccessibilityList() { - CreateScrollableList(); - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - - AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); - spoken_feedback_enabled_ = delegate->IsSpokenFeedbackEnabled(); - spoken_feedback_view_ = - AddScrollListItem(bundle.GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SPOKEN_FEEDBACK), - spoken_feedback_enabled_, spoken_feedback_enabled_, - kSystemMenuAccessibilityChromevoxIcon); - - // Large Cursor item is shown only in Login screen. - if (login_ == LoginStatus::NOT_LOGGED_IN) { - large_cursor_enabled_ = delegate->IsLargeCursorEnabled(); - large_cursor_view_ = - AddScrollListItem(bundle.GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_LARGE_CURSOR), - large_cursor_enabled_, large_cursor_enabled_, - kSystemMenuAccessibilityLargeCursorIcon); - } - - high_contrast_enabled_ = delegate->IsHighContrastEnabled(); - high_contrast_view_ = AddScrollListItem( - bundle.GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_HIGH_CONTRAST_MODE), - high_contrast_enabled_, high_contrast_enabled_, - kSystemMenuAccessibilityContrastIcon); - screen_magnifier_enabled_ = delegate->IsMagnifierEnabled(); - screen_magnifier_view_ = - AddScrollListItem(bundle.GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SCREEN_MAGNIFIER), - screen_magnifier_enabled_, screen_magnifier_enabled_, - kSystemMenuAccessibilityScreenMagnifierIcon); - - // Don't show autoclick option at login screen. - if (login_ != LoginStatus::NOT_LOGGED_IN) { - autoclick_enabled_ = delegate->IsAutoclickEnabled(); - autoclick_view_ = AddScrollListItem( - bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_AUTOCLICK), - autoclick_enabled_, autoclick_enabled_, - kSystemMenuAccessibilityAutoClickIcon); - } - - virtual_keyboard_enabled_ = delegate->IsVirtualKeyboardEnabled(); - virtual_keyboard_view_ = - AddScrollListItem(bundle.GetLocalizedString( - IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD), - virtual_keyboard_enabled_, virtual_keyboard_enabled_, - kSystemMenuKeyboardIcon); -} - -HoverHighlightView* AccessibilityDetailedView::AddScrollListItem( - const base::string16& text, - bool highlight, - bool checked, - const gfx::VectorIcon& icon) { - HoverHighlightView* container = new HoverHighlightView(this); - gfx::ImageSkia image = CreateVectorIcon(icon, kMenuIconColor); - const int padding = (kMenuButtonSize - image.width()) / 2; - container->AddIconAndLabelCustomSize( - image, text, highlight, image.width() + kMenuSeparatorVerticalPadding * 2, - padding, padding); - - if (checked) { - gfx::ImageSkia check_mark = - CreateVectorIcon(gfx::VectorIconId::CHECK_CIRCLE, gfx::kGoogleGreen700); - container->AddRightIcon(check_mark, check_mark.width()); - container->SetRightViewVisible(true); - container->SetAccessiblityState( - HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX); - } else { - container->SetAccessiblityState( - HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX); - } - - scroll_content()->AddChildView(container); - return container; -} - -void AccessibilityDetailedView::HandleViewClicked(views::View* view) { - AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); - UserMetricsAction user_action; - if (view == spoken_feedback_view_) { - user_action = delegate->IsSpokenFeedbackEnabled() - ? ash::UMA_STATUS_AREA_DISABLE_SPOKEN_FEEDBACK - : ash::UMA_STATUS_AREA_ENABLE_SPOKEN_FEEDBACK; - delegate->ToggleSpokenFeedback(A11Y_NOTIFICATION_NONE); - } else if (view == high_contrast_view_) { - user_action = delegate->IsHighContrastEnabled() - ? ash::UMA_STATUS_AREA_DISABLE_HIGH_CONTRAST - : ash::UMA_STATUS_AREA_ENABLE_HIGH_CONTRAST; - delegate->ToggleHighContrast(); - } else if (view == screen_magnifier_view_) { - user_action = delegate->IsMagnifierEnabled() - ? ash::UMA_STATUS_AREA_DISABLE_MAGNIFIER - : ash::UMA_STATUS_AREA_ENABLE_MAGNIFIER; - delegate->SetMagnifierEnabled(!delegate->IsMagnifierEnabled()); - } else if (large_cursor_view_ && view == large_cursor_view_) { - user_action = delegate->IsLargeCursorEnabled() - ? ash::UMA_STATUS_AREA_DISABLE_LARGE_CURSOR - : ash::UMA_STATUS_AREA_ENABLE_LARGE_CURSOR; - delegate->SetLargeCursorEnabled(!delegate->IsLargeCursorEnabled()); - } else if (autoclick_view_ && view == autoclick_view_) { - user_action = delegate->IsAutoclickEnabled() - ? ash::UMA_STATUS_AREA_DISABLE_AUTO_CLICK - : ash::UMA_STATUS_AREA_ENABLE_AUTO_CLICK; - delegate->SetAutoclickEnabled(!delegate->IsAutoclickEnabled()); - } else if (virtual_keyboard_view_ && view == virtual_keyboard_view_) { - user_action = delegate->IsVirtualKeyboardEnabled() - ? ash::UMA_STATUS_AREA_DISABLE_VIRTUAL_KEYBOARD - : ash::UMA_STATUS_AREA_ENABLE_VIRTUAL_KEYBOARD; - delegate->SetVirtualKeyboardEnabled(!delegate->IsVirtualKeyboardEnabled()); - } else { - return; - } - WmShell::Get()->RecordUserMetricsAction(user_action); -} - -void AccessibilityDetailedView::HandleButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender == help_view_) - ShowHelp(); - else if (sender == settings_view_) - ShowSettings(); -} - -void AccessibilityDetailedView::CreateExtraTitleRowButtons() { - DCHECK(!help_view_); - DCHECK(!settings_view_); - - tri_view()->SetContainerVisible(TriView::Container::END, true); - - help_view_ = CreateHelpButton(login_); - settings_view_ = - CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS); - tri_view()->AddView(TriView::Container::END, help_view_); - tri_view()->AddView(TriView::Container::END, settings_view_); -} - -void AccessibilityDetailedView::ShowSettings() { - if (TrayPopupUtils::CanOpenWebUISettings(login_)) { - WmShell::Get()->system_tray_controller()->ShowAccessibilitySettings(); - owner()->system_tray()->CloseSystemBubble(); - } -} - -void AccessibilityDetailedView::ShowHelp() { - if (TrayPopupUtils::CanOpenWebUISettings(login_)) { - WmShell::Get()->system_tray_controller()->ShowAccessibilityHelp(); - owner()->system_tray()->CloseSystemBubble(); - } -} - -} // namespace tray - -//////////////////////////////////////////////////////////////////////////////// -// ash::TrayAccessibility - -TrayAccessibility::TrayAccessibility(SystemTray* system_tray) - : TrayImageItem(system_tray, - kSystemTrayAccessibilityIcon, - UMA_ACCESSIBILITY), - default_(NULL), - detailed_popup_(NULL), - detailed_menu_(NULL), - request_popup_view_state_(A11Y_NONE), - tray_icon_visible_(false), - login_(GetCurrentLoginStatus()), - previous_accessibility_state_(GetAccessibilityState()), - show_a11y_menu_on_lock_screen_(true) { - DCHECK(system_tray); - WmShell::Get()->system_tray_notifier()->AddAccessibilityObserver(this); -} - -TrayAccessibility::~TrayAccessibility() { - WmShell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this); -} - -void TrayAccessibility::SetTrayIconVisible(bool visible) { - if (tray_view()) - tray_view()->SetVisible(visible); - tray_icon_visible_ = visible; -} - -tray::AccessibilityDetailedView* TrayAccessibility::CreateDetailedMenu() { - return new tray::AccessibilityDetailedView(this, login_); -} - -bool TrayAccessibility::GetInitialVisibility() { - // Shows accessibility icon if any accessibility feature is enabled. - // Otherwise, doen't show it. - return GetAccessibilityState() != A11Y_NONE; -} - -views::View* TrayAccessibility::CreateDefaultView(LoginStatus status) { - CHECK(default_ == NULL); - - // Shows accessibility menu if: - // - on login screen (not logged in); - // - "Enable accessibility menu" on chrome://settings is checked; - // - or any of accessibility features is enabled - // Otherwise, not shows it. - AccessibilityDelegate* delegate = WmShell::Get()->accessibility_delegate(); - if (login_ != LoginStatus::NOT_LOGGED_IN && - !delegate->ShouldShowAccessibilityMenu() && - // On login screen, keeps the initial visibility of the menu. - (status != LoginStatus::LOCKED || !show_a11y_menu_on_lock_screen_)) - return NULL; - - CHECK(default_ == NULL); - default_ = new tray::DefaultAccessibilityView(this); - - return default_; -} - -views::View* TrayAccessibility::CreateDetailedView(LoginStatus status) { - CHECK(detailed_popup_ == NULL); - CHECK(detailed_menu_ == NULL); - - if (request_popup_view_state_) { - detailed_popup_ = - new tray::AccessibilityPopupView(request_popup_view_state_); - request_popup_view_state_ = A11Y_NONE; - return detailed_popup_; - } else { - WmShell::Get()->RecordUserMetricsAction( - ash::UMA_STATUS_AREA_DETAILED_ACCESSABILITY); - detailed_menu_ = CreateDetailedMenu(); - return detailed_menu_; - } -} - -void TrayAccessibility::DestroyDefaultView() { - default_ = NULL; -} - -void TrayAccessibility::DestroyDetailedView() { - detailed_popup_ = NULL; - detailed_menu_ = NULL; -} - -void TrayAccessibility::UpdateAfterLoginStatusChange(LoginStatus status) { - // Stores the a11y feature status on just entering the lock screen. - if (login_ != LoginStatus::LOCKED && status == LoginStatus::LOCKED) - show_a11y_menu_on_lock_screen_ = (GetAccessibilityState() != A11Y_NONE); - - login_ = status; - SetTrayIconVisible(GetInitialVisibility()); -} - -void TrayAccessibility::OnAccessibilityModeChanged( - AccessibilityNotificationVisibility notify) { - SetTrayIconVisible(GetInitialVisibility()); - - uint32_t accessibility_state = GetAccessibilityState(); - // We'll get an extra notification if a braille display is connected when - // spoken feedback wasn't already enabled. This is because the braille - // connection state is already updated when spoken feedback is enabled so - // that the notifications can be consolidated into one. Therefore, we - // return early if there's no change in the state that we keep track of. - if (accessibility_state == previous_accessibility_state_) - return; - // Contains bits for spoken feedback and braille display connected currently - // being enabled. - uint32_t being_enabled = - (accessibility_state & ~previous_accessibility_state_) & - (A11Y_SPOKEN_FEEDBACK | A11Y_BRAILLE_DISPLAY_CONNECTED); - if ((notify == A11Y_NOTIFICATION_SHOW) && being_enabled != A11Y_NONE) { - // Shows popup if |notify| is true and the spoken feedback is being enabled. - request_popup_view_state_ = being_enabled; - PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); - } else { - if (detailed_popup_) - detailed_popup_->GetWidget()->Close(); - if (detailed_menu_) - detailed_menu_->GetWidget()->Close(); - } - - previous_accessibility_state_ = accessibility_state; -} - -} // namespace ash
diff --git a/ash/system/tray_accessibility.h b/ash/system/tray_accessibility.h deleted file mode 100644 index bf28c1b..0000000 --- a/ash/system/tray_accessibility.h +++ /dev/null
@@ -1,151 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_ACCESSIBILITY_H_ -#define ASH_SYSTEM_TRAY_ACCESSIBILITY_H_ - -#include <stdint.h> - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/shell_observer.h" -#include "ash/system/accessibility_observer.h" -#include "ash/system/tray/tray_details_view.h" -#include "ash/system/tray/tray_image_item.h" -#include "ash/system/tray/tray_notification_view.h" -#include "base/macros.h" -#include "ui/gfx/font.h" -#include "ui/views/controls/button/button.h" - -namespace chromeos { -class TrayAccessibilityTest; -} - -namespace gfx { -struct VectorIcon; -} - -namespace views { -class Button; -class CustomButton; -class Label; -class View; -} - -namespace ash { -class HoverHighlightView; -class SystemTrayItem; - -namespace tray { - -class AccessibilityPopupView : public TrayNotificationView { - public: - explicit AccessibilityPopupView(uint32_t enabled_state_bits); - - const views::Label* label_for_test() const { return label_; } - - private: - views::Label* CreateLabel(uint32_t enabled_state_bits); - - views::Label* label_; - - DISALLOW_COPY_AND_ASSIGN(AccessibilityPopupView); -}; - -// Create the detailed view of accessibility tray. -class AccessibilityDetailedView : public TrayDetailsView, - public ShellObserver { - public: - AccessibilityDetailedView(SystemTrayItem* owner, LoginStatus login); - ~AccessibilityDetailedView() override {} - - private: - // TrayDetailsView: - void HandleViewClicked(views::View* view) override; - void HandleButtonPressed(views::Button* sender, - const ui::Event& event) override; - void CreateExtraTitleRowButtons() override; - - // Launches the WebUI settings in a browser and closes the system menu. - void ShowSettings(); - - // Launches the a11y help article in a browser and closes the system menu. - void ShowHelp(); - - // Add the accessibility feature list. - void AppendAccessibilityList(); - - // Helper function to create entries in the detailed accessibility view. - HoverHighlightView* AddScrollListItem(const base::string16& text, - bool highlight, - bool checked, - const gfx::VectorIcon& icon); - - views::View* spoken_feedback_view_; - views::View* high_contrast_view_; - views::View* screen_magnifier_view_; - views::View* large_cursor_view_; - views::CustomButton* help_view_; - views::CustomButton* settings_view_; - views::View* autoclick_view_; - views::View* virtual_keyboard_view_; - - bool spoken_feedback_enabled_; - bool high_contrast_enabled_; - bool screen_magnifier_enabled_; - bool large_cursor_enabled_; - bool autoclick_enabled_; - bool virtual_keyboard_enabled_; - LoginStatus login_; - - friend class chromeos::TrayAccessibilityTest; - DISALLOW_COPY_AND_ASSIGN(AccessibilityDetailedView); -}; - -} // namespace tray - -class TrayAccessibility : public TrayImageItem, public AccessibilityObserver { - public: - explicit TrayAccessibility(SystemTray* system_tray); - ~TrayAccessibility() override; - - private: - void SetTrayIconVisible(bool visible); - tray::AccessibilityDetailedView* CreateDetailedMenu(); - - // Overridden from TrayImageItem. - bool GetInitialVisibility() override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - - // Overridden from AccessibilityObserver. - void OnAccessibilityModeChanged( - AccessibilityNotificationVisibility notify) override; - - views::View* default_; - tray::AccessibilityPopupView* detailed_popup_; - tray::AccessibilityDetailedView* detailed_menu_; - - // Bitmap of fvalues from AccessibilityState. Can contain any or - // both of A11Y_SPOKEN_FEEDBACK A11Y_BRAILLE_DISPLAY_CONNECTED. - uint32_t request_popup_view_state_; - - bool tray_icon_visible_; - LoginStatus login_; - - // Bitmap of values from AccessibilityState enum. - uint32_t previous_accessibility_state_; - - // A11y feature status on just entering the lock screen. - bool show_a11y_menu_on_lock_screen_; - - friend class chromeos::TrayAccessibilityTest; - DISALLOW_COPY_AND_ASSIGN(TrayAccessibility); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_ACCESSIBILITY_H_
diff --git a/ash/system/tray_caps_lock.cc b/ash/system/tray_caps_lock.cc deleted file mode 100644 index e918f48..0000000 --- a/ash/system/tray_caps_lock.cc +++ /dev/null
@@ -1,232 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray_caps_lock.h" - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "base/sys_info.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/ime/chromeos/ime_keyboard.h" -#include "ui/base/ime/chromeos/input_method_manager.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/border.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -// Padding used to position the caption in the caps lock default view row. -const int kCaptionRightPadding = 6; - -bool CapsLockIsEnabled() { - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - return (ime && ime->GetImeKeyboard()) - ? ime->GetImeKeyboard()->CapsLockIsEnabled() - : false; -} -} - -class CapsLockDefaultView : public ActionableView { - public: - CapsLockDefaultView() - : ActionableView(nullptr, TrayPopupInkDropStyle::FILL_BOUNDS), - text_label_(TrayPopupUtils::CreateDefaultLabel()), - shortcut_label_(TrayPopupUtils::CreateDefaultLabel()) { - shortcut_label_->SetEnabled(false); - - TriView* tri_view(TrayPopupUtils::CreateDefaultRowView()); - SetLayoutManager(new views::FillLayout); - AddChildView(tri_view); - - auto* image = TrayPopupUtils::CreateMainImageView(); - image->SetEnabled(enabled()); - TrayPopupItemStyle default_view_style( - TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - image->SetImage(gfx::CreateVectorIcon(kSystemMenuCapsLockIcon, - default_view_style.GetIconColor())); - default_view_style.SetupLabel(text_label_); - - TrayPopupItemStyle caption_style(TrayPopupItemStyle::FontStyle::CAPTION); - caption_style.SetupLabel(shortcut_label_); - - SetInkDropMode(InkDropHostView::InkDropMode::ON); - - tri_view->AddView(TriView::Container::START, image); - tri_view->AddView(TriView::Container::CENTER, text_label_); - tri_view->AddView(TriView::Container::END, shortcut_label_); - tri_view->SetContainerBorder( - TriView::Container::END, - views::CreateEmptyBorder(0, 0, 0, kCaptionRightPadding)); - } - - ~CapsLockDefaultView() override {} - - // Updates the label text and the shortcut text. - void Update(bool caps_lock_enabled) { - const int text_string_id = caps_lock_enabled - ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_ENABLED - : IDS_ASH_STATUS_TRAY_CAPS_LOCK_DISABLED; - text_label_->SetText(l10n_util::GetStringUTF16(text_string_id)); - - int shortcut_string_id = 0; - bool search_mapped_to_caps_lock = - WmShell::Get()->system_tray_delegate()->IsSearchKeyMappedToCapsLock(); - if (caps_lock_enabled) { - shortcut_string_id = - search_mapped_to_caps_lock - ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_SEARCH_OR_SHIFT - : IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_ALT_SEARCH_OR_SHIFT; - } else { - shortcut_string_id = - search_mapped_to_caps_lock - ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_SEARCH - : IDS_ASH_STATUS_TRAY_CAPS_LOCK_SHORTCUT_ALT_SEARCH; - } - shortcut_label_->SetText(l10n_util::GetStringUTF16(shortcut_string_id)); - - Layout(); - } - - private: - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->role = ui::AX_ROLE_BUTTON; - node_data->SetName(text_label_->text()); - } - - // ActionableView: - bool PerformAction(const ui::Event& event) override { - chromeos::input_method::ImeKeyboard* keyboard = - chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard(); - if (keyboard) { - WmShell::Get()->RecordUserMetricsAction( - keyboard->CapsLockIsEnabled() - ? UMA_STATUS_AREA_CAPS_LOCK_DISABLED_BY_CLICK - : UMA_STATUS_AREA_CAPS_LOCK_ENABLED_BY_CLICK); - keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled()); - } - return true; - } - - // It indicates whether the Caps Lock is on or off. - views::Label* text_label_; - - // It indicates the shortcut can be used to turn on or turn off Caps Lock. - views::Label* shortcut_label_; - - DISALLOW_COPY_AND_ASSIGN(CapsLockDefaultView); -}; - -TrayCapsLock::TrayCapsLock(SystemTray* system_tray) - : TrayImageItem(system_tray, kSystemTrayCapsLockIcon, UMA_CAPS_LOCK), - default_(nullptr), - detailed_(nullptr), - caps_lock_enabled_(CapsLockIsEnabled()), - message_shown_(false) { - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - if (ime && ime->GetImeKeyboard()) - ime->GetImeKeyboard()->AddObserver(this); -} - -TrayCapsLock::~TrayCapsLock() { - chromeos::input_method::InputMethodManager* ime = - chromeos::input_method::InputMethodManager::Get(); - if (ime && ime->GetImeKeyboard()) - ime->GetImeKeyboard()->RemoveObserver(this); -} - -void TrayCapsLock::OnCapsLockChanged(bool enabled) { - caps_lock_enabled_ = enabled; - - // Send an a11y alert. - WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert( - enabled ? A11Y_ALERT_CAPS_ON : A11Y_ALERT_CAPS_OFF); - - if (tray_view()) - tray_view()->SetVisible(caps_lock_enabled_); - - if (default_) { - default_->Update(caps_lock_enabled_); - } else { - if (caps_lock_enabled_) { - if (!message_shown_) { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_CAPS_LOCK_POPUP); - PopupDetailedView(kTrayPopupAutoCloseDelayForTextInSeconds, false); - message_shown_ = true; - } - } else if (detailed_) { - detailed_->GetWidget()->Close(); - } - } -} - -bool TrayCapsLock::GetInitialVisibility() { - return CapsLockIsEnabled(); -} - -views::View* TrayCapsLock::CreateDefaultView(LoginStatus status) { - if (!caps_lock_enabled_) - return nullptr; - DCHECK(!default_); - default_ = new CapsLockDefaultView; - default_->Update(caps_lock_enabled_); - return default_; -} - -views::View* TrayCapsLock::CreateDetailedView(LoginStatus status) { - DCHECK(!detailed_); - detailed_ = new views::View; - - detailed_->SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kHorizontal, kTrayPopupPaddingHorizontal, 10, - kTrayPopupPaddingBetweenItems)); - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - views::ImageView* image = new views::ImageView; - image->SetImage( - CreateVectorIcon(kSystemMenuCapsLockIcon, kMenuIconSize, kMenuIconColor)); - detailed_->AddChildView(image); - - const int string_id = - WmShell::Get()->system_tray_delegate()->IsSearchKeyMappedToCapsLock() - ? IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_SEARCH - : IDS_ASH_STATUS_TRAY_CAPS_LOCK_CANCEL_BY_ALT_SEARCH; - views::Label* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(bundle.GetLocalizedString(string_id)); - label->SetMultiLine(true); - label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - detailed_->AddChildView(label); - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_CAPS_LOCK_DETAILED); - - return detailed_; -} - -void TrayCapsLock::DestroyDefaultView() { - default_ = nullptr; -} - -void TrayCapsLock::DestroyDetailedView() { - detailed_ = nullptr; -} - -} // namespace ash
diff --git a/ash/system/tray_caps_lock.h b/ash/system/tray_caps_lock.h deleted file mode 100644 index 4b614931..0000000 --- a/ash/system/tray_caps_lock.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_CAPS_LOCK_H_ -#define ASH_SYSTEM_TRAY_CAPS_LOCK_H_ - -#include "ash/system/tray/tray_image_item.h" -#include "base/macros.h" -#include "ui/base/ime/chromeos/ime_keyboard.h" -#include "ui/events/event_handler.h" - -namespace views { -class View; -} - -namespace ash { -class CapsLockDefaultView; - -class TrayCapsLock : public TrayImageItem, - public chromeos::input_method::ImeKeyboard::Observer { - public: - explicit TrayCapsLock(SystemTray* system_tray); - ~TrayCapsLock() override; - - private: - // Overriden from chromeos::input_method::ImeKeyboard::Observer: - void OnCapsLockChanged(bool enabled) override; - - // Overridden from TrayImageItem. - bool GetInitialVisibility() override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - - CapsLockDefaultView* default_; - views::View* detailed_; - - bool caps_lock_enabled_; - bool message_shown_; - - DISALLOW_COPY_AND_ASSIGN(TrayCapsLock); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_CAPS_LOCK_H_
diff --git a/ash/system/tray_tracing.cc b/ash/system/tray_tracing.cc deleted file mode 100644 index 1f787ea8..0000000 --- a/ash/system/tray_tracing.cc +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/tray_tracing.h" - -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/tray/tri_view.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { -namespace tray { - -class DefaultTracingView : public ActionableView { - public: - explicit DefaultTracingView(SystemTrayItem* owner) - : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS) { - SetLayoutManager(new views::FillLayout); - TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view); - - auto* image = TrayPopupUtils::CreateMainImageView(); - tri_view->AddView(TriView::Container::START, image); - - auto* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetMultiLine(true); - label->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_TRACING)); - tri_view->AddView(TriView::Container::CENTER, label); - - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - style.SetupLabel(label); - image->SetImage( - gfx::CreateVectorIcon(kSystemMenuTracingIcon, style.GetIconColor())); - - SetInkDropMode(InkDropHostView::InkDropMode::ON); - } - - ~DefaultTracingView() override {} - - private: - bool PerformAction(const ui::Event& event) override { - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_TRACING_DEFAULT_SELECTED); - WmShell::Get()->system_tray_controller()->ShowChromeSlow(); - CloseSystemBubble(); - return true; - } - - DISALLOW_COPY_AND_ASSIGN(DefaultTracingView); -}; - -} // namespace tray - -//////////////////////////////////////////////////////////////////////////////// -// ash::TrayTracing - -TrayTracing::TrayTracing(SystemTray* system_tray) - : TrayImageItem(system_tray, kSystemTrayTracingIcon, UMA_TRACING), - default_(nullptr) { - DCHECK(system_tray); - WmShell::Get()->system_tray_notifier()->AddTracingObserver(this); -} - -TrayTracing::~TrayTracing() { - WmShell::Get()->system_tray_notifier()->RemoveTracingObserver(this); -} - -void TrayTracing::SetTrayIconVisible(bool visible) { - if (tray_view()) - tray_view()->SetVisible(visible); -} - -bool TrayTracing::GetInitialVisibility() { - return false; -} - -views::View* TrayTracing::CreateDefaultView(LoginStatus status) { - CHECK(default_ == NULL); - if (tray_view() && tray_view()->visible()) - default_ = new tray::DefaultTracingView(this); - return default_; -} - -views::View* TrayTracing::CreateDetailedView(LoginStatus status) { - return NULL; -} - -void TrayTracing::DestroyDefaultView() { - default_ = NULL; -} - -void TrayTracing::DestroyDetailedView() {} - -void TrayTracing::OnTracingModeChanged(bool value) { - SetTrayIconVisible(value); -} - -} // namespace ash
diff --git a/ash/system/tray_tracing.h b/ash/system/tray_tracing.h deleted file mode 100644 index d32077b7..0000000 --- a/ash/system/tray_tracing.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_TRAY_TRACING_H_ -#define ASH_SYSTEM_TRAY_TRACING_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/tray_image_item.h" -#include "base/macros.h" - -namespace views { -class View; -} - -namespace ash { - -class ASH_EXPORT TracingObserver { - public: - virtual ~TracingObserver() {} - - // Notifies when tracing mode changes. - virtual void OnTracingModeChanged(bool value) = 0; -}; - -// This is the item that displays when users enable performance tracing at -// chrome://slow. It alerts them that this mode is running, and provides an -// easy way to open the page to disable it. -class TrayTracing : public TrayImageItem, public TracingObserver { - public: - explicit TrayTracing(SystemTray* system_tray); - ~TrayTracing() override; - - private: - void SetTrayIconVisible(bool visible); - - // Overridden from TrayImageItem. - bool GetInitialVisibility() override; - views::View* CreateDefaultView(LoginStatus status) override; - views::View* CreateDetailedView(LoginStatus status) override; - void DestroyDefaultView() override; - void DestroyDetailedView() override; - - // Overridden from TracingObserver. - void OnTracingModeChanged(bool value) override; - - views::View* default_; - - DISALLOW_COPY_AND_ASSIGN(TrayTracing); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_TRAY_TRACING_H_
diff --git a/ash/system/update/tray_update.cc b/ash/system/update/tray_update.cc deleted file mode 100644 index ccbb434..0000000 --- a/ash/system/update/tray_update.cc +++ /dev/null
@@ -1,136 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/update/tray_update.h" - -#include "ash/common/wm_shell.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/public/interfaces/update.mojom.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/fixed_sized_image_view.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { -namespace { - -// Returns the color to use for the update icon when the update severity is -// |severity|. If |for_menu| is true, the icon color for the system menu is -// given, otherwise the icon color for the system tray is given. -SkColor IconColorForUpdateSeverity(mojom::UpdateSeverity severity, - bool for_menu) { - const SkColor default_color = for_menu ? kMenuIconColor : kTrayIconColor; - switch (severity) { - case mojom::UpdateSeverity::NONE: - return default_color; - case mojom::UpdateSeverity::LOW: - return for_menu ? gfx::kGoogleGreen700 : kTrayIconColor; - case mojom::UpdateSeverity::ELEVATED: - return for_menu ? gfx::kGoogleYellow700 : gfx::kGoogleYellow300; - case mojom::UpdateSeverity::HIGH: - case mojom::UpdateSeverity::SEVERE: - case mojom::UpdateSeverity::CRITICAL: - return for_menu ? gfx::kGoogleRed700 : gfx::kGoogleRed300; - default: - NOTREACHED(); - break; - } - return default_color; -} - -} // namespace - -// static -bool TrayUpdate::update_required_ = false; -// static -mojom::UpdateSeverity TrayUpdate::severity_ = mojom::UpdateSeverity::NONE; -// static -bool TrayUpdate::factory_reset_required_ = false; - -// The "restart to update" item in the system tray menu. -class TrayUpdate::UpdateView : public ActionableView { - public: - explicit UpdateView(TrayUpdate* owner) - : ActionableView(owner, TrayPopupInkDropStyle::FILL_BOUNDS) { - SetLayoutManager(new views::FillLayout); - - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - TriView* tri_view = TrayPopupUtils::CreateDefaultRowView(); - AddChildView(tri_view); - views::ImageView* image = TrayPopupUtils::CreateMainImageView(); - image->SetImage(gfx::CreateVectorIcon( - kSystemMenuUpdateIcon, - IconColorForUpdateSeverity(owner->severity_, true))); - tri_view->AddView(TriView::Container::START, image); - - base::string16 label_text = - owner->factory_reset_required_ - ? bundle.GetLocalizedString( - IDS_ASH_STATUS_TRAY_RESTART_AND_POWERWASH_TO_UPDATE) - : bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_UPDATE); - SetAccessibleName(label_text); - auto* label = TrayPopupUtils::CreateDefaultLabel(); - label->SetText(label_text); - TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - style.SetupLabel(label); - tri_view->AddView(TriView::Container::CENTER, label); - - SetInkDropMode(InkDropHostView::InkDropMode::ON); - } - - ~UpdateView() override {} - - private: - // Overridden from ActionableView. - bool PerformAction(const ui::Event& event) override { - WmShell::Get()->system_tray_controller()->RequestRestartForUpdate(); - WmShell::Get()->RecordUserMetricsAction( - UMA_STATUS_AREA_OS_UPDATE_DEFAULT_SELECTED); - CloseSystemBubble(); - return true; - } - - DISALLOW_COPY_AND_ASSIGN(UpdateView); -}; - -TrayUpdate::TrayUpdate(SystemTray* system_tray) - : TrayImageItem(system_tray, kSystemTrayUpdateIcon, UMA_UPDATE) {} - -TrayUpdate::~TrayUpdate() {} - -bool TrayUpdate::GetInitialVisibility() { - // If chrome tells ash there is an update available before this item's system - // tray is constructed then show the icon. - return update_required_; -} - -views::View* TrayUpdate::CreateDefaultView(LoginStatus status) { - return update_required_ ? new UpdateView(this) : nullptr; -} - -void TrayUpdate::ShowUpdateIcon(mojom::UpdateSeverity severity, - bool factory_reset_required) { - // Cache update info so we can create the default view when the menu opens. - update_required_ = true; - severity_ = severity; - factory_reset_required_ = factory_reset_required; - - // Show the icon in the tray. - SetIconColor(IconColorForUpdateSeverity(severity_, false)); - tray_view()->SetVisible(true); -} - -} // namespace ash
diff --git a/ash/system/update/tray_update.h b/ash/system/update/tray_update.h deleted file mode 100644 index 70c970e..0000000 --- a/ash/system/update/tray_update.h +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_UPDATE_TRAY_UPDATE_H_ -#define ASH_SYSTEM_UPDATE_TRAY_UPDATE_H_ - -#include "ash/ash_export.h" -#include "ash/system/tray/tray_image_item.h" -#include "base/macros.h" - -namespace views { -class View; -} - -namespace ash { - -namespace mojom { -enum class UpdateSeverity; -} - -// The system update tray item. The tray icon stays visible once an update -// notification is received. The icon only disappears after a reboot to apply -// the update. Exported for test. -class ASH_EXPORT TrayUpdate : public TrayImageItem { - public: - explicit TrayUpdate(SystemTray* system_tray); - ~TrayUpdate() override; - - // Shows an icon in the system tray indicating that a software update is - // available. Once shown the icon persists until reboot. |severity| and - // |factory_reset_required| are used to set the icon, color, and tooltip. - void ShowUpdateIcon(mojom::UpdateSeverity severity, - bool factory_reset_required); - - private: - class UpdateView; - - // Overridden from TrayImageItem. - bool GetInitialVisibility() override; - views::View* CreateDefaultView(LoginStatus status) override; - - // If an external monitor is connected then the system tray may be created - // after the update data is sent from chrome, so share the update info between - // all instances. - static bool update_required_; - static mojom::UpdateSeverity severity_; - static bool factory_reset_required_; - - DISALLOW_COPY_AND_ASSIGN(TrayUpdate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_UPDATE_TRAY_UPDATE_H_
diff --git a/ash/system/update/tray_update_unittest.cc b/ash/system/update/tray_update_unittest.cc deleted file mode 100644 index c33947f..0000000 --- a/ash/system/update/tray_update_unittest.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/update/tray_update.h" - -#include "ash/common/wm_shell.h" -#include "ash/public/interfaces/update.mojom.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/test/ash_test.h" - -namespace ash { - -using TrayUpdateTest = AshTest; - -// Tests that the update icon becomes visible when an update becomes -// available. -TEST_F(TrayUpdateTest, VisibilityAfterUpdate) { - TrayUpdate* tray_update = GetPrimarySystemTray()->tray_update(); - - // The system starts with no update pending, so the icon isn't visible. - EXPECT_FALSE(tray_update->tray_view()->visible()); - - // Simulate an update. - WmShell::Get()->system_tray_controller()->ShowUpdateIcon( - mojom::UpdateSeverity::LOW, false); - - // Tray item is now visible. - EXPECT_TRUE(tray_update->tray_view()->visible()); -} - -} // namespace ash
diff --git a/ash/system/user/button_from_view.cc b/ash/system/user/button_from_view.cc deleted file mode 100644 index a7e1ea99..0000000 --- a/ash/system/user/button_from_view.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/user/button_from_view.h" - -#include <vector> - -#include "ash/common/ash_constants.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/gfx/canvas.h" -#include "ui/views/animation/flood_fill_ink_drop_ripple.h" -#include "ui/views/animation/ink_drop.h" -#include "ui/views/animation/ink_drop_highlight.h" -#include "ui/views/animation/ink_drop_impl.h" -#include "ui/views/animation/ink_drop_mask.h" -#include "ui/views/layout/fill_layout.h" - -namespace ash { -namespace tray { - -ButtonFromView::ButtonFromView(views::View* content, - views::ButtonListener* listener, - TrayPopupInkDropStyle ink_drop_style) - : CustomButton(listener), - content_(content), - ink_drop_style_(ink_drop_style), - button_hovered_(false), - ink_drop_container_(nullptr) { - set_has_ink_drop_action_on_click(true); - set_notify_enter_exit_on_child(true); - ink_drop_container_ = new views::InkDropContainerView(); - AddChildView(ink_drop_container_); - SetLayoutManager(new views::FillLayout()); - SetInkDropMode(InkDropHostView::InkDropMode::ON); - AddChildView(content_); - // Only make it focusable when we are active/interested in clicks. - if (listener) - SetFocusForPlatform(); -} - -ButtonFromView::~ButtonFromView() {} - -void ButtonFromView::OnMouseEntered(const ui::MouseEvent& event) { - button_hovered_ = true; -} - -void ButtonFromView::OnMouseExited(const ui::MouseEvent& event) { - button_hovered_ = false; -} - -void ButtonFromView::OnPaint(gfx::Canvas* canvas) { - View::OnPaint(canvas); - if (HasFocus()) { - gfx::RectF rect(GetLocalBounds()); - canvas->DrawSolidFocusRect(rect, kFocusBorderColor, kFocusBorderThickness); - } -} - -void ButtonFromView::OnFocus() { - View::OnFocus(); - // Adding focus frame. - SchedulePaint(); -} - -void ButtonFromView::OnBlur() { - View::OnBlur(); - // Removing focus frame. - SchedulePaint(); -} - -void ButtonFromView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - views::CustomButton::GetAccessibleNodeData(node_data); - // If no label has been explicitly set via CustomButton::SetAccessibleName(), - // use the content's label. - if (node_data->GetStringAttribute(ui::AX_ATTR_NAME).empty()) { - ui::AXNodeData content_data; - content_->GetAccessibleNodeData(&content_data); - node_data->SetName(content_data.GetStringAttribute(ui::AX_ATTR_NAME)); - } -} - -void ButtonFromView::Layout() { - CustomButton::Layout(); - if (ink_drop_container_) - ink_drop_container_->SetBoundsRect(GetLocalBounds()); -} - -void ButtonFromView::AddInkDropLayer(ui::Layer* ink_drop_layer) { - // TODO(bruthig): Rework InkDropHostView so that it can still manage the - // creation/application of the mask while allowing subclasses to use an - // InkDropContainer. - ink_drop_mask_ = CreateInkDropMask(); - if (ink_drop_mask_) - ink_drop_layer->SetMaskLayer(ink_drop_mask_->layer()); - ink_drop_container_->AddInkDropLayer(ink_drop_layer); -} - -void ButtonFromView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) { - // TODO(bruthig): Rework InkDropHostView so that it can still manage the - // creation/application of the mask while allowing subclasses to use an - // InkDropContainer. - // Layers safely handle destroying a mask layer before the masked layer. - ink_drop_mask_.reset(); - ink_drop_container_->RemoveInkDropLayer(ink_drop_layer); -} - -std::unique_ptr<views::InkDrop> ButtonFromView::CreateInkDrop() { - return TrayPopupUtils::CreateInkDrop(TrayPopupInkDropStyle::INSET_BOUNDS, - this); -} - -std::unique_ptr<views::InkDropRipple> ButtonFromView::CreateInkDropRipple() - const { - return TrayPopupUtils::CreateInkDropRipple( - ink_drop_style_, this, GetInkDropCenterBasedOnLastEvent()); -} - -std::unique_ptr<views::InkDropHighlight> -ButtonFromView::CreateInkDropHighlight() const { - return TrayPopupUtils::CreateInkDropHighlight(ink_drop_style_, this); -} - -std::unique_ptr<views::InkDropMask> ButtonFromView::CreateInkDropMask() const { - return TrayPopupUtils::CreateInkDropMask(ink_drop_style_, this); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/user/button_from_view.h b/ash/system/user/button_from_view.h deleted file mode 100644 index d50f10e0..0000000 --- a/ash/system/user/button_from_view.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_BUTTON_FROM_VIEW_H_ -#define ASH_SYSTEM_USER_BUTTON_FROM_VIEW_H_ - -#include <memory> - -#include "ash/system/tray/tray_popup_ink_drop_style.h" -#include "base/macros.h" -#include "ui/views/controls/button/custom_button.h" - -namespace views { -class InkDropContainerView; -} // namespace views - -namespace ash { -namespace tray { - -// This view is used to wrap it's content and transform it into button. -class ButtonFromView : public views::CustomButton { - public: - // The |content| is the content which is shown within the button. The - // |button_listener| will be informed - if provided - when a button was - // pressed. - ButtonFromView(views::View* content, - views::ButtonListener* listener, - TrayPopupInkDropStyle ink_drop_style); - ~ButtonFromView() override; - - // views::View: - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; - void OnPaint(gfx::Canvas* canvas) override; - void OnFocus() override; - void OnBlur() override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - void Layout() override; - - // Check if the item is hovered. - bool is_hovered_for_test() { return button_hovered_; } - - protected: - // views::CustomButton: - void AddInkDropLayer(ui::Layer* ink_drop_layer) override; - void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override; - std::unique_ptr<views::InkDrop> CreateInkDrop() override; - std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override; - std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight() - const override; - std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override; - - private: - // Content of button. - views::View* content_; - - // Defines the flavor of ink drop ripple/highlight that should be constructed. - TrayPopupInkDropStyle ink_drop_style_; - - // True if button is hovered. - bool button_hovered_; - - // A separate view is necessary to hold the ink drop layer so that |this| can - // host labels with subpixel anti-aliasing enabled. - views::InkDropContainerView* ink_drop_container_; - - std::unique_ptr<views::InkDropMask> ink_drop_mask_; - - DISALLOW_COPY_AND_ASSIGN(ButtonFromView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_USER_BUTTON_FROM_VIEW_H_
diff --git a/ash/system/user/login_status.cc b/ash/system/user/login_status.cc deleted file mode 100644 index d129034..0000000 --- a/ash/system/user/login_status.cc +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/user/login_status.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/strings/grit/ash_strings.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/resource/resource_bundle.h" - -namespace ash { -namespace user { - -base::string16 GetLocalizedSignOutStringForStatus(LoginStatus status, - bool multiline) { - int message_id; - switch (status) { - case LoginStatus::GUEST: - message_id = IDS_ASH_STATUS_TRAY_EXIT_GUEST; - break; - case LoginStatus::PUBLIC: - message_id = IDS_ASH_STATUS_TRAY_EXIT_PUBLIC; - break; - default: - message_id = - WmShell::Get()->GetSessionStateDelegate()->NumberOfLoggedInUsers() > 1 - ? IDS_ASH_STATUS_TRAY_SIGN_OUT_ALL - : IDS_ASH_STATUS_TRAY_SIGN_OUT; - break; - } - base::string16 message = - ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id); - // Desirable line breaking points are marked using \n. As the resource - // framework does not evaluate escape sequences, the \n need to be explicitly - // handled. Depending on the value of |multiline|, actual line breaks or - // spaces are substituted. - base::string16 newline = - multiline ? base::ASCIIToUTF16("\n") : base::ASCIIToUTF16(" "); - base::ReplaceSubstringsAfterOffset(&message, 0, base::ASCIIToUTF16("\\n"), - newline); - return message; -} - -} // namespace user -} // namespace ash
diff --git a/ash/system/user/login_status.h b/ash/system/user/login_status.h deleted file mode 100644 index 672389a..0000000 --- a/ash/system/user/login_status.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_LOGIN_STATUS_H_ -#define ASH_SYSTEM_USER_LOGIN_STATUS_H_ - -#include "ash/common/login_status.h" -#include "base/strings/string16.h" - -namespace ash { -namespace user { - -base::string16 GetLocalizedSignOutStringForStatus(LoginStatus status, - bool multiline); - -} // namespace user -} // namespace ash - -#endif // ASH_SYSTEM_USER_LOGIN_STATUS_H_
diff --git a/ash/system/user/rounded_image_view.cc b/ash/system/user/rounded_image_view.cc deleted file mode 100644 index 27b6381..0000000 --- a/ash/system/user/rounded_image_view.cc +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/user/rounded_image_view.h" - -#include "skia/ext/image_operations.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/gfx/skia_util.h" - -namespace ash { -namespace tray { - -RoundedImageView::RoundedImageView(int corner_radius) { - for (int i = 0; i < 4; ++i) - corner_radius_[i] = corner_radius; -} - -RoundedImageView::~RoundedImageView() {} - -void RoundedImageView::SetImage(const gfx::ImageSkia& img, - const gfx::Size& size) { - image_ = img; - image_size_ = size; - - // Try to get the best image quality for the avatar. - resized_ = gfx::ImageSkiaOperations::CreateResizedImage( - image_, skia::ImageOperations::RESIZE_BEST, size); - if (GetWidget() && visible()) { - PreferredSizeChanged(); - SchedulePaint(); - } -} - -void RoundedImageView::SetCornerRadii(int top_left, - int top_right, - int bottom_right, - int bottom_left) { - corner_radius_[0] = top_left; - corner_radius_[1] = top_right; - corner_radius_[2] = bottom_right; - corner_radius_[3] = bottom_left; -} - -gfx::Size RoundedImageView::GetPreferredSize() const { - return gfx::Size(image_size_.width() + GetInsets().width(), - image_size_.height() + GetInsets().height()); -} - -void RoundedImageView::OnPaint(gfx::Canvas* canvas) { - View::OnPaint(canvas); - gfx::Rect image_bounds(size()); - image_bounds.ClampToCenteredSize(GetPreferredSize()); - image_bounds.Inset(GetInsets()); - const SkScalar kRadius[8] = { - SkIntToScalar(corner_radius_[0]), SkIntToScalar(corner_radius_[0]), - SkIntToScalar(corner_radius_[1]), SkIntToScalar(corner_radius_[1]), - SkIntToScalar(corner_radius_[2]), SkIntToScalar(corner_radius_[2]), - SkIntToScalar(corner_radius_[3]), SkIntToScalar(corner_radius_[3])}; - SkPath path; - path.addRoundRect(gfx::RectToSkRect(image_bounds), kRadius); - cc::PaintFlags flags; - flags.setAntiAlias(true); - canvas->DrawImageInPath(resized_, image_bounds.x(), image_bounds.y(), path, - flags); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/user/rounded_image_view.h b/ash/system/user/rounded_image_view.h deleted file mode 100644 index 0685ab5..0000000 --- a/ash/system/user/rounded_image_view.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_ROUNDED_IMAGE_VIEW_H_ -#define ASH_SYSTEM_USER_ROUNDED_IMAGE_VIEW_H_ - -#include "base/macros.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/view.h" - -namespace ash { -namespace tray { - -// A custom image view with rounded edges. -class RoundedImageView : public views::View { - public: - // Constructs a new rounded image view with rounded corners of radius - // |corner_radius|. - explicit RoundedImageView(int corner_radius); - ~RoundedImageView() override; - - // Set the image that should be displayed. The image contents is copied to the - // receiver's image. - void SetImage(const gfx::ImageSkia& img, const gfx::Size& size); - - // Set the radii of the corners independently. - void SetCornerRadii(int top_left, - int top_right, - int bottom_right, - int bottom_left); - - // Overridden from views::View. - gfx::Size GetPreferredSize() const override; - void OnPaint(gfx::Canvas* canvas) override; - - private: - gfx::ImageSkia image_; - gfx::ImageSkia resized_; - gfx::Size image_size_; - int corner_radius_[4]; - - DISALLOW_COPY_AND_ASSIGN(RoundedImageView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_USER_ROUNDED_IMAGE_VIEW_H_
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc deleted file mode 100644 index 0dfa5233..0000000 --- a/ash/system/user/tray_user.cc +++ /dev/null
@@ -1,262 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/user/tray_user.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_item_view.h" -#include "ash/system/tray/tray_utils.h" -#include "ash/system/user/rounded_image_view.h" -#include "ash/system/user/user_view.h" -#include "base/logging.h" -#include "base/strings/string16.h" -#include "components/signin/core/account_id/account_id.h" -#include "components/user_manager/user_info.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace { - -const int kUserLabelToIconPadding = 5; - -} // namespace - -namespace ash { - -TrayUser::TrayUser(SystemTray* system_tray, UserIndex index) - : SystemTrayItem(system_tray, UMA_USER), - user_index_(index), - user_(nullptr), - layout_view_(nullptr), - avatar_(nullptr), - label_(nullptr) { - WmShell::Get()->system_tray_notifier()->AddUserObserver(this); -} - -TrayUser::~TrayUser() { - WmShell::Get()->system_tray_notifier()->RemoveUserObserver(this); -} - -TrayUser::TestState TrayUser::GetStateForTest() const { - if (!user_) - return HIDDEN; - return user_->GetStateForTest(); -} - -gfx::Size TrayUser::GetLayoutSizeForTest() const { - return layout_view_ ? layout_view_->size() : gfx::Size(); -} - -gfx::Rect TrayUser::GetUserPanelBoundsInScreenForTest() const { - DCHECK(user_); - return user_->GetBoundsInScreenOfUserButtonForTest(); -} - -void TrayUser::UpdateAfterLoginStatusChangeForTest(LoginStatus status) { - UpdateAfterLoginStatusChange(status); -} - -views::View* TrayUser::CreateTrayView(LoginStatus status) { - CHECK(layout_view_ == nullptr); - - layout_view_ = new views::View; - UpdateAfterLoginStatusChange(status); - return layout_view_; -} - -views::View* TrayUser::CreateDefaultView(LoginStatus status) { - if (status == LoginStatus::NOT_LOGGED_IN) - return nullptr; - const SessionStateDelegate* session_state_delegate = - WmShell::Get()->GetSessionStateDelegate(); - - // If the screen is locked or a system modal dialog box is shown, show only - // the currently active user. - if (user_index_ && (session_state_delegate->IsUserSessionBlocked() || - WmShell::Get()->IsSystemModalWindowOpen())) - return nullptr; - - CHECK(user_ == nullptr); - - int logged_in_users = session_state_delegate->NumberOfLoggedInUsers(); - - // Do not show more UserView's then there are logged in users. - if (user_index_ >= logged_in_users) - return nullptr; - - user_ = new tray::UserView(this, status, user_index_); - return user_; -} - -void TrayUser::DestroyTrayView() { - layout_view_ = nullptr; - avatar_ = nullptr; - label_ = nullptr; -} - -void TrayUser::DestroyDefaultView() { - user_ = nullptr; -} - -void TrayUser::UpdateAfterLoginStatusChange(LoginStatus status) { - // Only the active user is represented in the tray. - if (!layout_view_) - return; - if (user_index_ > 0) - return; - bool need_label = false; - bool need_avatar = false; - SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate(); - if (delegate->IsUserSupervised()) - need_label = true; - switch (status) { - case LoginStatus::LOCKED: - case LoginStatus::USER: - case LoginStatus::OWNER: - case LoginStatus::PUBLIC: - need_avatar = true; - break; - case LoginStatus::SUPERVISED: - need_avatar = true; - need_label = true; - break; - case LoginStatus::GUEST: - need_label = true; - break; - case LoginStatus::KIOSK_APP: - case LoginStatus::ARC_KIOSK_APP: - case LoginStatus::NOT_LOGGED_IN: - break; - } - - if ((need_avatar != (avatar_ != nullptr)) || - (need_label != (label_ != nullptr))) { - delete label_; - delete avatar_; - - if (need_label) { - label_ = new views::Label; - SetupLabelForTray(label_); - layout_view_->AddChildView(label_); - } else { - label_ = nullptr; - } - if (need_avatar) { - avatar_ = new tray::RoundedImageView(kTrayRoundedBorderRadius); - avatar_->SetPaintToLayer(); - avatar_->layer()->SetFillsBoundsOpaquely(false); - layout_view_->AddChildView(avatar_); - } else { - avatar_ = nullptr; - } - } - - if (delegate->IsUserSupervised()) { - label_->SetText( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL)); - } else if (status == LoginStatus::GUEST) { - label_->SetText(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL)); - } - - UpdateAvatarImage(status); - - // Update layout after setting label_ and avatar_ with new login status. - UpdateLayoutOfItem(); -} - -void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) { - // Inactive users won't have a layout. - if (!layout_view_) - return; - if (IsHorizontalAlignment(alignment)) { - if (avatar_) { - avatar_->SetCornerRadii(0, kTrayRoundedBorderRadius, - kTrayRoundedBorderRadius, 0); - } - if (label_) { - // If label_ hasn't figured out its size yet, do that first. - if (label_->GetContentsBounds().height() == 0) - label_->SizeToPreferredSize(); - int height = label_->GetContentsBounds().height(); - int vertical_pad = (kTrayItemSize - height) / 2; - int remainder = height % 2; - label_->SetBorder(views::CreateEmptyBorder( - vertical_pad + remainder, - kTrayLabelItemHorizontalPaddingBottomAlignment, vertical_pad, - kTrayLabelItemHorizontalPaddingBottomAlignment)); - } - layout_view_->SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kHorizontal, 0, 0, kUserLabelToIconPadding)); - } else { - if (avatar_) { - avatar_->SetCornerRadii(0, 0, kTrayRoundedBorderRadius, - kTrayRoundedBorderRadius); - } - if (label_) { - label_->SetBorder(views::CreateEmptyBorder( - kTrayLabelItemVerticalPaddingVerticalAlignment, - kTrayLabelItemHorizontalPaddingBottomAlignment, - kTrayLabelItemVerticalPaddingVerticalAlignment, - kTrayLabelItemHorizontalPaddingBottomAlignment)); - } - layout_view_->SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kVertical, 0, 0, kUserLabelToIconPadding)); - } -} - -void TrayUser::OnUserUpdate() { - UpdateAvatarImage( - WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()); -} - -void TrayUser::OnUserAddedToSession() { - SessionStateDelegate* session_state_delegate = - WmShell::Get()->GetSessionStateDelegate(); - // Only create views for user items which are logged in. - if (user_index_ >= session_state_delegate->NumberOfLoggedInUsers()) - return; - - // Enforce a layout change that newly added items become visible. - UpdateLayoutOfItem(); - - // Update the user item. - UpdateAvatarImage( - WmShell::Get()->system_tray_delegate()->GetUserLoginStatus()); -} - -void TrayUser::UpdateAvatarImage(LoginStatus status) { - SessionStateDelegate* session_state_delegate = - WmShell::Get()->GetSessionStateDelegate(); - if (!avatar_ || - user_index_ >= session_state_delegate->NumberOfLoggedInUsers()) - return; - - const user_manager::UserInfo* user_info = - session_state_delegate->GetUserInfo(user_index_); - CHECK(user_info); - avatar_->SetImage(user_info->GetImage(), - gfx::Size(kTrayItemSize, kTrayItemSize)); - - // Unit tests might come here with no images for some users. - if (avatar_->size().IsEmpty()) - avatar_->SetSize(gfx::Size(kTrayItemSize, kTrayItemSize)); -} - -void TrayUser::UpdateLayoutOfItem() { - UpdateAfterShelfAlignmentChange(system_tray()->shelf_alignment()); -} - -} // namespace ash
diff --git a/ash/system/user/tray_user.h b/ash/system/user/tray_user.h deleted file mode 100644 index d7aa60e..0000000 --- a/ash/system/user/tray_user.h +++ /dev/null
@@ -1,95 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_TRAY_USER_H_ -#define ASH_SYSTEM_USER_TRAY_USER_H_ - -#include "ash/ash_export.h" -#include "ash/public/cpp/session_types.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/user/user_observer.h" -#include "base/macros.h" - -namespace gfx { -class Rect; -class Size; -} - -namespace views { -class Label; -} - -namespace ash { - -namespace tray { -class RoundedImageView; -class UserView; -} - -class ASH_EXPORT TrayUser : public SystemTrayItem, public UserObserver { - public: - // The given |index| is the user index in a multi profile scenario. Index #0 - // is the active user, the other indices are other logged in users (if there - // are any). Depending on the multi user mode, there will be either one (index - // #0) or all users be visible in the system tray. - TrayUser(SystemTray* system_tray, UserIndex index); - ~TrayUser() override; - - // Allows unit tests to see if the item was created. - enum TestState { - HIDDEN, // The item is hidden. - SHOWN, // The item gets presented to the user. - HOVERED, // The item is hovered and presented to the user. - ACTIVE, // The item was clicked and can add a user. - ACTIVE_BUT_DISABLED // The item was clicked anc cannot add a user. - }; - TestState GetStateForTest() const; - - // Returns the size of layout_view_. - gfx::Size GetLayoutSizeForTest() const; - - // Returns the bounds of the user panel in screen coordinates. - // Note: This only works when the panel shown. - gfx::Rect GetUserPanelBoundsInScreenForTest() const; - - // Update the TrayUser as if the current LoginStatus is |status|. - void UpdateAfterLoginStatusChangeForTest(LoginStatus status); - - // Use for access inside of tests. - tray::UserView* user_view_for_test() const { return user_; } - - private: - // Overridden from SystemTrayItem. - views::View* CreateTrayView(LoginStatus status) override; - views::View* CreateDefaultView(LoginStatus status) override; - void DestroyTrayView() override; - void DestroyDefaultView() override; - void UpdateAfterLoginStatusChange(LoginStatus status) override; - void UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) override; - - // Overridden from UserObserver. - void OnUserUpdate() override; - void OnUserAddedToSession() override; - - void UpdateAvatarImage(LoginStatus status); - - // Updates the layout of this item. - void UpdateLayoutOfItem(); - - // The user index to use. - UserIndex user_index_; - - tray::UserView* user_; - - // View that contains label and/or avatar. - views::View* layout_view_; - tray::RoundedImageView* avatar_; - views::Label* label_; - - DISALLOW_COPY_AND_ASSIGN(TrayUser); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_USER_TRAY_USER_H_
diff --git a/ash/system/user/tray_user_unittest.cc b/ash/system/user/tray_user_unittest.cc deleted file mode 100644 index cb3bceb..0000000 --- a/ash/system/user/tray_user_unittest.cc +++ /dev/null
@@ -1,254 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <vector> - -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/user/tray_user.h" -#include "ash/system/user/user_view.h" -#include "ash/test/ash_test_base.h" -#include "ash/test/ash_test_helper.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/test/test_shell_delegate.h" -#include "base/memory/ptr_util.h" -#include "base/strings/utf_string_conversions.h" -#include "components/signin/core/account_id/account_id.h" -#include "components/user_manager/user_info.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/events/test/event_generator.h" -#include "ui/gfx/animation/animation_container_element.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -namespace { - -class TrayUserTest : public test::AshTestBase { - public: - TrayUserTest() = default; - - // testing::Test: - void SetUp() override; - - // This has to be called prior to first use with the proper configuration. - void InitializeParameters(int users_logged_in, bool multiprofile); - - // Show the system tray menu using the provided event generator. - void ShowTrayMenu(ui::test::EventGenerator* generator); - - // Move the mouse over the user item. - void MoveOverUserItem(ui::test::EventGenerator* generator, int index); - - // Click on the user item. Note that the tray menu needs to be shown. - void ClickUserItem(ui::test::EventGenerator* generator, int index); - - // Accessors to various system components. - SystemTray* tray() { return tray_; } - test::TestSessionStateDelegate* delegate() { return delegate_; } - TrayUser* tray_user(int index) { return tray_user_[index]; } - - private: - SystemTray* tray_ = nullptr; - test::TestSessionStateDelegate* delegate_ = nullptr; - - // Note that the ownership of these items is on the shelf. - std::vector<TrayUser*> tray_user_; - - DISALLOW_COPY_AND_ASSIGN(TrayUserTest); -}; - -void TrayUserTest::SetUp() { - test::AshTestBase::SetUp(); - tray_ = GetPrimarySystemTray(); - delegate_ = test::AshTestHelper::GetTestSessionStateDelegate(); -} - -void TrayUserTest::InitializeParameters(int users_logged_in, - bool multiprofile) { - // Set our default assumptions. Note that it is sufficient to set these - // after everything was created. - delegate_->set_logged_in_users(users_logged_in); - test::TestShellDelegate* shell_delegate = - static_cast<test::TestShellDelegate*>(WmShell::Get()->delegate()); - shell_delegate->set_multi_profiles_enabled(multiprofile); - - // Instead of using the existing tray panels we create new ones which makes - // the access easier. - for (int i = 0; i < delegate_->GetMaximumNumberOfLoggedInUsers(); i++) { - tray_user_.push_back(new TrayUser(tray_, i)); - tray_->AddTrayItem(base::WrapUnique(tray_user_[i])); - } -} - -void TrayUserTest::ShowTrayMenu(ui::test::EventGenerator* generator) { - gfx::Point center = tray()->GetBoundsInScreen().CenterPoint(); - - generator->MoveMouseTo(center.x(), center.y()); - EXPECT_FALSE(tray()->IsSystemBubbleVisible()); - generator->ClickLeftButton(); -} - -void TrayUserTest::MoveOverUserItem(ui::test::EventGenerator* generator, - int index) { - gfx::Point center = - tray_user(index)->GetUserPanelBoundsInScreenForTest().CenterPoint(); - - generator->MoveMouseTo(center.x(), center.y()); -} - -void TrayUserTest::ClickUserItem(ui::test::EventGenerator* generator, - int index) { - MoveOverUserItem(generator, index); - generator->ClickLeftButton(); -} - -} // namespace - -// Make sure that we show items for all users in the tray accordingly. -TEST_F(TrayUserTest, CheckTrayItemSize) { - InitializeParameters(1, false); - tray_user(0)->UpdateAfterLoginStatusChangeForTest(LoginStatus::GUEST); - gfx::Size size = tray_user(0)->GetLayoutSizeForTest(); - EXPECT_EQ(kTrayItemSize, size.height()); - tray_user(0)->UpdateAfterLoginStatusChangeForTest(LoginStatus::USER); - size = tray_user(0)->GetLayoutSizeForTest(); - EXPECT_EQ(kTrayItemSize, size.height()); -} - -// Make sure that in single user mode the user panel cannot be activated. -TEST_F(TrayUserTest, SingleUserModeDoesNotAllowAddingUser) { - InitializeParameters(1, false); - - // Move the mouse over the status area and click to open the status menu. - ui::test::EventGenerator& generator = GetEventGenerator(); - - EXPECT_FALSE(tray()->IsSystemBubbleVisible()); - - for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) - EXPECT_EQ(TrayUser::HIDDEN, tray_user(i)->GetStateForTest()); - - ShowTrayMenu(&generator); - - EXPECT_TRUE(tray()->HasSystemBubble()); - EXPECT_TRUE(tray()->IsSystemBubbleVisible()); - - for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) - EXPECT_EQ(i == 0 ? TrayUser::SHOWN : TrayUser::HIDDEN, - tray_user(i)->GetStateForTest()); - tray()->CloseSystemBubble(); -} - -TEST_F(TrayUserTest, AccessibleLabelContainsSingleUserInfo) { - InitializeParameters(1, false); - ui::test::EventGenerator& generator = GetEventGenerator(); - ShowTrayMenu(&generator); - - views::View* view = - tray_user(0)->user_view_for_test()->user_card_view_for_test(); - ui::AXNodeData node_data; - view->GetAccessibleNodeData(&node_data); - EXPECT_EQ( - base::UTF8ToUTF16("Über tray Über tray Über tray Über tray First@tray"), - node_data.GetString16Attribute(ui::AX_ATTR_NAME)); - EXPECT_EQ(ui::AX_ROLE_STATIC_TEXT, node_data.role); -} - -TEST_F(TrayUserTest, AccessibleLabelContainsMultiUserInfo) { - InitializeParameters(1, true); - ui::test::EventGenerator& generator = GetEventGenerator(); - ShowTrayMenu(&generator); - - views::View* view = - tray_user(0)->user_view_for_test()->user_card_view_for_test(); - ui::AXNodeData node_data; - view->GetAccessibleNodeData(&node_data); - EXPECT_EQ( - base::UTF8ToUTF16("Über tray Über tray Über tray Über tray First@tray"), - node_data.GetString16Attribute(ui::AX_ATTR_NAME)); - EXPECT_EQ(ui::AX_ROLE_BUTTON, node_data.role); -} - -// Make sure that in multi user mode the user panel can be activated and there -// will be one panel for each user. -// Note: the mouse watcher (for automatic closing upon leave) cannot be tested -// here since it does not work with the event system in unit tests. -TEST_F(TrayUserTest, MultiUserModeDoesNotAllowToAddUser) { - InitializeParameters(1, true); - - // Move the mouse over the status area and click to open the status menu. - ui::test::EventGenerator& generator = GetEventGenerator(); - generator.set_async(false); - - int max_users = delegate()->GetMaximumNumberOfLoggedInUsers(); - // Checking now for each amount of users that the correct is done. - for (int j = 1; j < max_users; j++) { - // Set the number of logged in users. - delegate()->set_logged_in_users(j); - - // Verify that nothing is shown. - EXPECT_FALSE(tray()->IsSystemBubbleVisible()); - for (int i = 0; i < max_users; i++) - EXPECT_FALSE(tray_user(i)->GetStateForTest()); - // After clicking on the tray the menu should get shown and for each logged - // in user we should get a visible item. - ShowTrayMenu(&generator); - - EXPECT_TRUE(tray()->HasSystemBubble()); - EXPECT_TRUE(tray()->IsSystemBubbleVisible()); - for (int i = 0; i < max_users; i++) { - EXPECT_EQ(i < j ? TrayUser::SHOWN : TrayUser::HIDDEN, - tray_user(i)->GetStateForTest()); - } - - // Move the mouse over the user item and it should hover. - MoveOverUserItem(&generator, 0); - EXPECT_EQ(TrayUser::HOVERED, tray_user(0)->GetStateForTest()); - for (int i = 1; i < max_users; i++) { - EXPECT_EQ(i < j ? TrayUser::SHOWN : TrayUser::HIDDEN, - tray_user(i)->GetStateForTest()); - } - - // Check that clicking the button allows to add item if we have still room - // for one more user. - ClickUserItem(&generator, 0); - EXPECT_EQ(j == max_users ? TrayUser::ACTIVE_BUT_DISABLED : TrayUser::ACTIVE, - tray_user(0)->GetStateForTest()); - - // Click the button again to see that the menu goes away. - ClickUserItem(&generator, 0); - MoveOverUserItem(&generator, 0); - EXPECT_EQ(TrayUser::HOVERED, tray_user(0)->GetStateForTest()); - - // Close and check that everything is deleted. - tray()->CloseSystemBubble(); - EXPECT_FALSE(tray()->IsSystemBubbleVisible()); - for (int i = 0; i < delegate()->GetMaximumNumberOfLoggedInUsers(); i++) - EXPECT_EQ(TrayUser::HIDDEN, tray_user(i)->GetStateForTest()); - } -} - -// Make sure that user changing gets properly executed. -TEST_F(TrayUserTest, MultiUserModeButtonClicks) { - // Have two users. - InitializeParameters(2, true); - ui::test::EventGenerator& generator = GetEventGenerator(); - ShowTrayMenu(&generator); - - // Switch to a new user - which has a capitalized name. - ClickUserItem(&generator, 1); - const user_manager::UserInfo* active_user = delegate()->GetActiveUserInfo(); - const user_manager::UserInfo* second_user = delegate()->GetUserInfo(1); - EXPECT_EQ(active_user->GetAccountId(), second_user->GetAccountId()); - // Since the name is capitalized, the email should be different than the - // user_id. - EXPECT_NE(active_user->GetAccountId().GetUserEmail(), - second_user->GetDisplayEmail()); - tray()->CloseSystemBubble(); -} - -} // namespace ash
diff --git a/ash/system/user/user_card_view.cc b/ash/system/user/user_card_view.cc deleted file mode 100644 index ddc8c72..0000000 --- a/ash/system/user/user_card_view.cc +++ /dev/null
@@ -1,470 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/user/user_card_view.h" - -#include <algorithm> -#include <memory> -#include <vector> - -#include "ash/common/ash_view_ids.h" -#include "ash/common/login_status.h" -#include "ash/common/media_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/user/rounded_image_view.h" -#include "base/i18n/rtl.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string16.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "components/user_manager/user_info.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/compositor/compositing_recorder.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/range/range.h" -#include "ui/gfx/render_text.h" -#include "ui/gfx/text_elider.h" -#include "ui/gfx/text_utils.h" -#include "ui/views/border.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/link.h" -#include "ui/views/controls/link_listener.h" -#include "ui/views/layout/box_layout.h" - -namespace ash { -namespace tray { - -namespace { - -const int kUserDetailsVerticalPadding = 5; - -// The invisible word joiner character, used as a marker to indicate the start -// and end of the user's display name in the public account user card's text. -const base::char16 kDisplayNameMark[] = {0x2060, 0}; - -views::View* CreateUserAvatarView(LoginStatus login_status, int user_index) { - RoundedImageView* image_view = new RoundedImageView(kTrayItemSize / 2); - if (login_status == LoginStatus::GUEST) { - gfx::ImageSkia icon = - gfx::CreateVectorIcon(kSystemMenuGuestIcon, kMenuIconColor); - image_view->SetImage(icon, icon.size()); - } else { - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - image_view->SetImage(delegate->GetUserInfo(user_index)->GetImage(), - gfx::Size(kTrayItemSize, kTrayItemSize)); - } - - image_view->SetBorder(views::CreateEmptyBorder(gfx::Insets( - (kTrayPopupItemMinStartWidth - image_view->GetPreferredSize().width()) / - 2))); - return image_view; -} - -// The user details shown in public account mode. This is essentially a label -// but with custom painting code as the text is styled with multiple colors and -// contains a link. -class PublicAccountUserDetails : public views::View, - public views::LinkListener { - public: - PublicAccountUserDetails(int max_width); - ~PublicAccountUserDetails() override; - - private: - // Overridden from views::View. - void Layout() override; - gfx::Size GetPreferredSize() const override; - void OnPaint(gfx::Canvas* canvas) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - - // Overridden from views::LinkListener. - void LinkClicked(views::Link* source, int event_flags) override; - - // Calculate a preferred size that ensures the label text and the following - // link do not wrap over more than three lines in total for aesthetic reasons - // if possible. - void CalculatePreferredSize(); - - base::string16 text_; - views::Link* learn_more_; - gfx::Size preferred_size_; - std::vector<std::unique_ptr<gfx::RenderText>> lines_; - - DISALLOW_COPY_AND_ASSIGN(PublicAccountUserDetails); -}; - -PublicAccountUserDetails::PublicAccountUserDetails(int max_width) - : learn_more_(NULL) { - const int inner_padding = - kTrayPopupPaddingHorizontal - kTrayPopupPaddingBetweenItems; - const bool rtl = base::i18n::IsRTL(); - SetBorder(views::CreateEmptyBorder( - kUserDetailsVerticalPadding, rtl ? 0 : inner_padding, - kUserDetailsVerticalPadding, rtl ? inner_padding : 0)); - - // Retrieve the user's display name and wrap it with markers. - // Note that since this is a public account it always has to be the primary - // user. - base::string16 display_name = WmShell::Get() - ->GetSessionStateDelegate() - ->GetUserInfo(0) - ->GetDisplayName(); - base::RemoveChars(display_name, kDisplayNameMark, &display_name); - display_name = kDisplayNameMark[0] + display_name + kDisplayNameMark[0]; - // Retrieve the domain managing the device and wrap it with markers. - base::string16 domain = base::UTF8ToUTF16( - WmShell::Get()->system_tray_delegate()->GetEnterpriseDomain()); - base::RemoveChars(domain, kDisplayNameMark, &domain); - base::i18n::WrapStringWithLTRFormatting(&domain); - // Retrieve the label text, inserting the display name and domain. - text_ = l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_PUBLIC_LABEL, - display_name, domain); - - learn_more_ = new views::Link(l10n_util::GetStringUTF16(IDS_ASH_LEARN_MORE)); - learn_more_->SetUnderline(false); - learn_more_->set_listener(this); - AddChildView(learn_more_); - - CalculatePreferredSize(); -} - -PublicAccountUserDetails::~PublicAccountUserDetails() {} - -void PublicAccountUserDetails::Layout() { - lines_.clear(); - const gfx::Rect contents_area = GetContentsBounds(); - if (contents_area.IsEmpty()) - return; - - // Word-wrap the label text. - const gfx::FontList font_list; - std::vector<base::string16> lines; - gfx::ElideRectangleText(text_, font_list, contents_area.width(), - contents_area.height(), gfx::ELIDE_LONG_WORDS, - &lines); - // Loop through the lines, creating a renderer for each. - gfx::Point position = contents_area.origin(); - gfx::Range display_name(gfx::Range::InvalidRange()); - for (auto it = lines.begin(); it != lines.end(); ++it) { - auto line = base::WrapUnique(gfx::RenderText::CreateInstance()); - line->SetDirectionalityMode(gfx::DIRECTIONALITY_FROM_UI); - line->SetText(*it); - const gfx::Size size(contents_area.width(), line->GetStringSize().height()); - line->SetDisplayRect(gfx::Rect(position, size)); - position.set_y(position.y() + size.height()); - - // Set the default text color for the line. - line->SetColor(kPublicAccountUserCardTextColor); - - // If a range of the line contains the user's display name, apply a custom - // text color to it. - if (display_name.is_empty()) - display_name.set_start(it->find(kDisplayNameMark)); - if (!display_name.is_empty()) { - display_name.set_end( - it->find(kDisplayNameMark, display_name.start() + 1)); - gfx::Range line_range(0, it->size()); - line->ApplyColor(kPublicAccountUserCardNameColor, - display_name.Intersect(line_range)); - // Update the range for the next line. - if (display_name.end() >= line_range.end()) - display_name.set_start(0); - else - display_name = gfx::Range::InvalidRange(); - } - - lines_.push_back(std::move(line)); - } - - // Position the link after the label text, separated by a space. If it does - // not fit onto the last line of the text, wrap the link onto its own line. - const gfx::Size last_line_size = lines_.back()->GetStringSize(); - const int space_width = - gfx::GetStringWidth(base::ASCIIToUTF16(" "), font_list); - const gfx::Size link_size = learn_more_->GetPreferredSize(); - if (contents_area.width() - last_line_size.width() >= - space_width + link_size.width()) { - position.set_x(position.x() + last_line_size.width() + space_width); - position.set_y(position.y() - last_line_size.height()); - } - position.set_y(position.y() - learn_more_->GetInsets().top()); - gfx::Rect learn_more_bounds(position, link_size); - learn_more_bounds.Intersect(contents_area); - if (base::i18n::IsRTL()) { - const gfx::Insets insets = GetInsets(); - learn_more_bounds.Offset(insets.right() - insets.left(), 0); - } - learn_more_->SetBoundsRect(learn_more_bounds); -} - -gfx::Size PublicAccountUserDetails::GetPreferredSize() const { - return preferred_size_; -} - -void PublicAccountUserDetails::OnPaint(gfx::Canvas* canvas) { - for (const auto& line : lines_) - line->Draw(canvas); - - views::View::OnPaint(canvas); -} - -void PublicAccountUserDetails::GetAccessibleNodeData( - ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_STATIC_TEXT; - node_data->SetName(text_); -} - -void PublicAccountUserDetails::LinkClicked(views::Link* source, - int event_flags) { - DCHECK_EQ(source, learn_more_); - WmShell::Get()->system_tray_controller()->ShowPublicAccountInfo(); -} - -void PublicAccountUserDetails::CalculatePreferredSize() { - const gfx::FontList font_list; - const gfx::Size link_size = learn_more_->GetPreferredSize(); - const int space_width = - gfx::GetStringWidth(base::ASCIIToUTF16(" "), font_list); - const gfx::Insets insets = GetInsets(); - int min_width = link_size.width(); - int max_width = - gfx::GetStringWidth(text_, font_list) + space_width + link_size.width(); - - // Do a binary search for the minimum width that ensures no more than three - // lines are needed. The lower bound is the minimum of the current bubble - // width and the width of the link (as no wrapping is permitted inside the - // link). The upper bound is the maximum of the largest allowed bubble width - // and the sum of the label text and link widths when put on a single line. - std::vector<base::string16> lines; - while (min_width < max_width) { - lines.clear(); - const int width = (min_width + max_width) / 2; - const bool too_narrow = - gfx::ElideRectangleText(text_, font_list, width, INT_MAX, - gfx::TRUNCATE_LONG_WORDS, &lines) != 0; - int line_count = lines.size(); - if (!too_narrow && line_count == 3 && - width - gfx::GetStringWidth(lines.back(), font_list) <= - space_width + link_size.width()) - ++line_count; - if (too_narrow || line_count > 3) - min_width = width + 1; - else - max_width = width; - } - - // Calculate the corresponding height and set the preferred size. - lines.clear(); - gfx::ElideRectangleText(text_, font_list, min_width, INT_MAX, - gfx::TRUNCATE_LONG_WORDS, &lines); - int line_count = lines.size(); - if (min_width - gfx::GetStringWidth(lines.back(), font_list) <= - space_width + link_size.width()) { - ++line_count; - } - const int line_height = font_list.GetHeight(); - const int link_extra_height = std::max( - link_size.height() - learn_more_->GetInsets().top() - line_height, 0); - preferred_size_ = - gfx::Size(min_width + insets.width(), - line_count * line_height + link_extra_height + insets.height()); -} - -} // namespace - -UserCardView::UserCardView(LoginStatus login_status, - int max_width, - int user_index) - : user_index_(user_index), - user_name_(nullptr), - media_capture_label_(nullptr), - media_capture_icon_(nullptr) { - auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, - kTrayPopupLabelHorizontalPadding); - SetLayoutManager(layout); - layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); - layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - // For active users, the left inset is provided by ActiveUserBorder, which - // is necessary to make sure the ripple does not cover that part of the row. - // For inactive users, we set the inset here and this causes the ripple to - // extend all the way to the edges of the menu. - if (!is_active_user()) - SetBorder(views::CreateEmptyBorder(0, kMenuExtraMarginFromLeftEdge, 0, 0)); - - WmShell::Get()->media_controller()->AddObserver(this); - - if (login_status == LoginStatus::PUBLIC) - AddPublicModeUserContent(max_width); - else - AddUserContent(layout, login_status); -} - -UserCardView::~UserCardView() { - WmShell::Get()->media_controller()->RemoveObserver(this); -} - -void UserCardView::PaintChildren(const ui::PaintContext& context) { - if (!is_active_user()) { - ui::CompositingRecorder alpha(context, 0xFF / 2, true); - View::PaintChildren(context); - } else { - View::PaintChildren(context); - } -} - -void UserCardView::GetAccessibleNodeData(ui::AXNodeData* node_data) { - node_data->role = ui::AX_ROLE_STATIC_TEXT; - std::vector<base::string16> labels; - - // Construct the name by concatenating descendants' names. - std::list<views::View*> descendants; - descendants.push_back(this); - while (!descendants.empty()) { - auto* view = descendants.front(); - descendants.pop_front(); - if (view != this) { - ui::AXNodeData descendant_data; - view->GetAccessibleNodeData(&descendant_data); - base::string16 label = - descendant_data.GetString16Attribute(ui::AX_ATTR_NAME); - // If we find a non-empty name, use that and don't descend further into - // the tree. - if (!label.empty()) { - labels.push_back(label); - continue; - } - } - - // This view didn't have its own name, so look over its children. - for (int i = view->child_count() - 1; i >= 0; --i) - descendants.push_front(view->child_at(i)); - } - node_data->SetName(base::JoinString(labels, base::ASCIIToUTF16(" "))); -} - -void UserCardView::OnMediaCaptureChanged( - const std::vector<mojom::MediaCaptureState>& capture_states) { - if (is_active_user()) - return; - - mojom::MediaCaptureState state = capture_states[user_index_]; - int res_id = 0; - switch (state) { - case mojom::MediaCaptureState::AUDIO_VIDEO: - res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO_VIDEO; - break; - case mojom::MediaCaptureState::AUDIO: - res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_AUDIO; - break; - case mojom::MediaCaptureState::VIDEO: - res_id = IDS_ASH_STATUS_TRAY_MEDIA_RECORDING_VIDEO; - break; - case mojom::MediaCaptureState::NONE: - break; - } - if (res_id) - media_capture_label_->SetText(l10n_util::GetStringUTF16(res_id)); - media_capture_label_->SetVisible(!!res_id); - media_capture_icon_->SetVisible(!!res_id); - user_name_->SetVisible(!res_id); - Layout(); -} - -void UserCardView::AddPublicModeUserContent(int max_width) { - views::View* avatar = CreateUserAvatarView(LoginStatus::PUBLIC, 0); - AddChildView(avatar); - int details_max_width = max_width - avatar->GetPreferredSize().width() - - kTrayPopupPaddingBetweenItems; - AddChildView(new PublicAccountUserDetails(details_max_width)); -} - -void UserCardView::AddUserContent(views::BoxLayout* layout, - LoginStatus login_status) { - AddChildView(CreateUserAvatarView(login_status, user_index_)); - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - base::string16 user_name_string = - login_status == LoginStatus::GUEST - ? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_GUEST_LABEL) - : delegate->GetUserInfo(user_index_)->GetDisplayName(); - user_name_ = new views::Label(user_name_string); - user_name_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - TrayPopupItemStyle user_name_style( - TrayPopupItemStyle::FontStyle::DEFAULT_VIEW_LABEL); - user_name_style.SetupLabel(user_name_); - - TrayPopupItemStyle user_email_style(TrayPopupItemStyle::FontStyle::CAPTION); - // Only the active user's email label is lightened (for the inactive user, the - // label starts as black and the entire row is 54% opacity). - if (is_active_user()) - user_email_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); - auto* user_email = new views::Label(); - base::string16 user_email_string; - if (login_status != LoginStatus::GUEST) { - user_email_string = - WmShell::Get()->system_tray_delegate()->IsUserSupervised() - ? l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SUPERVISED_LABEL) - : base::UTF8ToUTF16( - delegate->GetUserInfo(user_index_)->GetDisplayEmail()); - } - user_email->SetText(user_email_string); - user_email->SetHorizontalAlignment(gfx::ALIGN_LEFT); - user_email_style.SetupLabel(user_email); - user_email->SetVisible(!user_email_string.empty()); - user_email->set_collapse_when_hidden(true); - - views::View* stack_of_labels = new views::View; - AddChildView(stack_of_labels); - layout->SetFlexForView(stack_of_labels, 1); - stack_of_labels->SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); - stack_of_labels->AddChildView(user_name_); - stack_of_labels->AddChildView(user_email); - // The name and email have different font sizes. This border is designed - // to make both views take up equal space so the whitespace between them - // is centered on the vertical midpoint. - int user_email_bottom_pad = user_name_->GetPreferredSize().height() - - user_email->GetPreferredSize().height(); - user_email->SetBorder( - views::CreateEmptyBorder(0, 0, user_email_bottom_pad, 0)); - - // Only inactive users need media capture indicators. - if (!is_active_user()) { - media_capture_label_ = new views::Label(); - media_capture_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - media_capture_label_->SetBorder( - views::CreateEmptyBorder(0, 0, user_email_bottom_pad, 0)); - user_email_style.SetupLabel(media_capture_label_); - stack_of_labels->AddChildView(media_capture_label_); - - media_capture_icon_ = new views::ImageView; - media_capture_icon_->SetImage( - gfx::CreateVectorIcon(kSystemTrayRecordingIcon, gfx::kGoogleRed700)); - const int media_capture_width = kTrayPopupItemMinEndWidth; - media_capture_icon_->SetBorder(views::CreateEmptyBorder( - gfx::Insets(0, (media_capture_width - - media_capture_icon_->GetPreferredSize().width()) / - 2))); - - media_capture_icon_->set_id(VIEW_ID_USER_VIEW_MEDIA_INDICATOR); - AddChildView(media_capture_icon_); - - WmShell::Get()->media_controller()->RequestCaptureState(); - } -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/user/user_card_view.h b/ash/system/user/user_card_view.h deleted file mode 100644 index 14a26e4..0000000 --- a/ash/system/user/user_card_view.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_USER_CARD_VIEW_H_ -#define ASH_SYSTEM_USER_USER_CARD_VIEW_H_ - -#include "ash/common/media_controller.h" -#include "base/macros.h" -#include "ui/views/view.h" - -namespace views { -class BoxLayout; -class ImageView; -class Label; -} - -namespace ash { - -enum class LoginStatus; - -namespace tray { - -// The view displaying information about the user, such as user's avatar, email -// address, name, and more. View has no borders. -class UserCardView : public views::View, public MediaCaptureObserver { - public: - // |max_width| takes effect only if |login_status| is LOGGED_IN_PUBLIC. - UserCardView(LoginStatus login_status, int max_width, int user_index); - ~UserCardView() override; - - // View: - void PaintChildren(const ui::PaintContext& context) override; - void GetAccessibleNodeData(ui::AXNodeData* node_data) override; - - // MediaCaptureObserver: - void OnMediaCaptureChanged( - const std::vector<mojom::MediaCaptureState>& capture_states) override; - - private: - // Creates the content for the public mode. - void AddPublicModeUserContent(int max_width); - - void AddUserContent(views::BoxLayout* layout, LoginStatus login_status); - - bool is_active_user() const { return !user_index_; } - - int user_index_; - - views::Label* user_name_; - views::Label* media_capture_label_; - views::ImageView* media_capture_icon_; - - DISALLOW_COPY_AND_ASSIGN(UserCardView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_USER_USER_CARD_VIEW_H_
diff --git a/ash/system/user/user_observer.h b/ash/system/user/user_observer.h deleted file mode 100644 index 64c2b9d..0000000 --- a/ash/system/user/user_observer.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_USER_OBSERVER_H_ -#define ASH_SYSTEM_USER_USER_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -class ASH_EXPORT UserObserver { - public: - virtual ~UserObserver() {} - - // A user got updated / changed. - virtual void OnUserUpdate() = 0; - - // A user was added to the existing session. - virtual void OnUserAddedToSession() = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_USER_USER_OBSERVER_H_
diff --git a/ash/system/user/user_view.cc b/ash/system/user/user_view.cc deleted file mode 100644 index ccddef0..0000000 --- a/ash/system/user/user_view.cc +++ /dev/null
@@ -1,400 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/user/user_view.h" - -#include <algorithm> -#include <utility> - -#include "ash/common/multi_profile_uma.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/root_window_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_controller.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_popup_item_style.h" -#include "ash/system/tray/tray_popup_utils.h" -#include "ash/system/user/button_from_view.h" -#include "ash/system/user/login_status.h" -#include "ash/system/user/rounded_image_view.h" -#include "ash/system/user/user_card_view.h" -#include "base/memory/ptr_util.h" -#include "components/signin/core/account_id/account_id.h" -#include "components/user_manager/user_info.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/separator.h" -#include "ui/views/layout/fill_layout.h" -#include "ui/views/painter.h" - -namespace ash { -namespace tray { - -namespace { - -// Switch to a user with the given |user_index|. -void SwitchUser(UserIndex user_index) { - // Do not switch users when the log screen is presented. - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - if (delegate->IsUserSessionBlocked()) - return; - - DCHECK(user_index > 0); - MultiProfileUMA::RecordSwitchActiveUser( - MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY); - delegate->SwitchActiveUser(delegate->GetUserInfo(user_index)->GetAccountId()); -} - -bool IsMultiProfileSupportedAndUserActive() { - return WmShell::Get()->delegate()->IsMultiProfilesEnabled() && - !WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked(); -} - -// Creates the view shown in the user switcher popup ("AddUserMenuOption"). -views::View* CreateAddUserView(AddUserSessionPolicy policy, - views::ButtonListener* listener) { - auto* view = new views::View; - const int icon_padding = (kMenuButtonSize - kMenuIconSize) / 2; - auto* layout = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, - kTrayPopupLabelHorizontalPadding + icon_padding); - layout->set_minimum_cross_axis_size(kTrayPopupItemMinHeight); - view->SetLayoutManager(layout); - view->set_background( - views::Background::CreateSolidBackground(kBackgroundColor)); - - int message_id = 0; - switch (policy) { - case AddUserSessionPolicy::ALLOWED: { - message_id = IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT; - - auto* icon = new views::ImageView(); - icon->SetImage( - gfx::CreateVectorIcon(kSystemMenuNewUserIcon, kMenuIconColor)); - view->AddChildView(icon); - break; - } - case AddUserSessionPolicy::ERROR_NOT_ALLOWED_PRIMARY_USER: - message_id = IDS_ASH_STATUS_TRAY_MESSAGE_NOT_ALLOWED_PRIMARY_USER; - break; - case AddUserSessionPolicy::ERROR_MAXIMUM_USERS_REACHED: - message_id = IDS_ASH_STATUS_TRAY_MESSAGE_CANNOT_ADD_USER; - break; - case AddUserSessionPolicy::ERROR_NO_ELIGIBLE_USERS: - message_id = IDS_ASH_STATUS_TRAY_MESSAGE_OUT_OF_USERS; - break; - } - - auto* command_label = new views::Label(l10n_util::GetStringUTF16(message_id)); - command_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); - command_label->SetMultiLine(true); - - TrayPopupItemStyle label_style( - TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL); - int vertical_padding = kMenuSeparatorVerticalPadding; - if (policy != AddUserSessionPolicy::ALLOWED) { - label_style.set_font_style(TrayPopupItemStyle::FontStyle::CAPTION); - label_style.set_color_style(TrayPopupItemStyle::ColorStyle::INACTIVE); - vertical_padding += kMenuSeparatorVerticalPadding; - } - label_style.SetupLabel(command_label); - view->AddChildView(command_label); - view->SetBorder(views::CreateEmptyBorder(vertical_padding, icon_padding, - vertical_padding, - kTrayPopupLabelHorizontalPadding)); - if (policy == AddUserSessionPolicy::ALLOWED) { - auto* button = - new ButtonFromView(view, listener, TrayPopupInkDropStyle::INSET_BOUNDS); - button->SetAccessibleName( - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SIGN_IN_ANOTHER_ACCOUNT)); - return button; - } - - return view; -} - -class UserViewMouseWatcherHost : public views::MouseWatcherHost { - public: - explicit UserViewMouseWatcherHost(const gfx::Rect& screen_area) - : screen_area_(screen_area) {} - ~UserViewMouseWatcherHost() override {} - - // Implementation of MouseWatcherHost. - bool Contains(const gfx::Point& screen_point, - views::MouseWatcherHost::MouseEventType type) override { - return screen_area_.Contains(screen_point); - } - - private: - gfx::Rect screen_area_; - - DISALLOW_COPY_AND_ASSIGN(UserViewMouseWatcherHost); -}; - -// A view that acts as the contents of the widget that appears when clicking -// the active user. If the mouse exits this view or an otherwise unhandled -// click is detected, it will invoke a closure passed at construction time. -class AddUserWidgetContents : public views::View { - public: - explicit AddUserWidgetContents(const base::Closure& close_widget) - : close_widget_(close_widget) { - // Don't want to receive a mouse exit event when the cursor enters a child. - set_notify_enter_exit_on_child(true); - } - - ~AddUserWidgetContents() override {} - - bool OnMousePressed(const ui::MouseEvent& event) override { return true; } - void OnMouseReleased(const ui::MouseEvent& event) override { - close_widget_.Run(); - } - void OnMouseExited(const ui::MouseEvent& event) override { - close_widget_.Run(); - } - void OnGestureEvent(ui::GestureEvent* event) override { close_widget_.Run(); } - - private: - base::Closure close_widget_; - - DISALLOW_COPY_AND_ASSIGN(AddUserWidgetContents); -}; - -// This border reserves 4dp above and 8dp below and paints a horizontal -// separator 3dp below the host view. -class ActiveUserBorder : public views::Border { - public: - ActiveUserBorder() {} - ~ActiveUserBorder() override {} - - // views::Border: - void Paint(const views::View& view, gfx::Canvas* canvas) override { - canvas->FillRect( - gfx::Rect( - 0, view.height() - kMenuSeparatorVerticalPadding - kSeparatorWidth, - view.width(), kSeparatorWidth), - kMenuSeparatorColor); - } - - gfx::Insets GetInsets() const override { - return gfx::Insets(kMenuSeparatorVerticalPadding, - kMenuExtraMarginFromLeftEdge, - kMenuSeparatorVerticalPadding * 2, 0); - } - - gfx::Size GetMinimumSize() const override { return gfx::Size(); } - - private: - DISALLOW_COPY_AND_ASSIGN(ActiveUserBorder); -}; - -} // namespace - -UserView::UserView(SystemTrayItem* owner, LoginStatus login, UserIndex index) - : user_index_(index), - user_card_view_(nullptr), - owner_(owner), - is_user_card_button_(false), - logout_button_(nullptr), - add_user_enabled_(true), - focus_manager_(nullptr) { - CHECK_NE(LoginStatus::NOT_LOGGED_IN, login); - // The logout button must be added before the user card so that the user card - // can correctly calculate the remaining available width. - // Note that only the current multiprofile user gets a button. - if (IsActiveUser()) - AddLogoutButton(login); - AddUserCard(login); - - auto* layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - SetLayoutManager(layout); - layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER); - layout->SetFlexForView(user_card_view_, 1); - - if (IsActiveUser()) - SetBorder(base::MakeUnique<ActiveUserBorder>()); -} - -UserView::~UserView() { - RemoveAddUserMenuOption(); -} - -TrayUser::TestState UserView::GetStateForTest() const { - if (add_menu_option_) - return add_user_enabled_ ? TrayUser::ACTIVE : TrayUser::ACTIVE_BUT_DISABLED; - - if (!is_user_card_button_) - return TrayUser::SHOWN; - - return static_cast<ButtonFromView*>(user_card_view_)->is_hovered_for_test() - ? TrayUser::HOVERED - : TrayUser::SHOWN; -} - -gfx::Rect UserView::GetBoundsInScreenOfUserButtonForTest() { - DCHECK(user_card_view_); - return user_card_view_->GetBoundsInScreen(); -} - -bool UserView::IsActiveUser() const { - return user_index_ == 0; -} - -int UserView::GetHeightForWidth(int width) const { - return GetPreferredSize().height(); -} - -void UserView::ButtonPressed(views::Button* sender, const ui::Event& event) { - if (sender == logout_button_) { - WmShell::Get()->RecordUserMetricsAction(UMA_STATUS_AREA_SIGN_OUT); - RemoveAddUserMenuOption(); - WmShell::Get()->system_tray_controller()->SignOut(); - } else if (sender == user_card_view_ && - IsMultiProfileSupportedAndUserActive()) { - if (IsActiveUser()) { - ToggleAddUserMenuOption(); - } else { - RemoveAddUserMenuOption(); - SwitchUser(user_index_); - // Since the user list is about to change the system menu should get - // closed. - owner_->system_tray()->CloseSystemBubble(); - } - } else if (add_menu_option_ && - sender->GetWidget() == add_menu_option_.get()) { - RemoveAddUserMenuOption(); - // Let the user add another account to the session. - MultiProfileUMA::RecordSigninUser(MultiProfileUMA::SIGNIN_USER_BY_TRAY); - WmShell::Get()->system_tray_delegate()->ShowUserLogin(); - owner_->system_tray()->CloseSystemBubble(); - } else { - NOTREACHED(); - } -} - -void UserView::OnWillChangeFocus(View* focused_before, View* focused_now) { - if (focused_now) - RemoveAddUserMenuOption(); -} - -void UserView::OnDidChangeFocus(View* focused_before, View* focused_now) { - // Nothing to do here. -} - -void UserView::AddLogoutButton(LoginStatus login) { - AddChildView(TrayPopupUtils::CreateVerticalSeparator()); - logout_button_ = TrayPopupUtils::CreateTrayPopupBorderlessButton( - this, user::GetLocalizedSignOutStringForStatus(login, true)); - AddChildView(logout_button_); -} - -void UserView::AddUserCard(LoginStatus login) { - user_card_view_ = new UserCardView(login, -1, user_index_); - // The entry is clickable when no system modal dialog is open and the multi - // profile option is active. - bool clickable = !WmShell::Get()->IsSystemModalWindowOpen() && - IsMultiProfileSupportedAndUserActive(); - if (clickable) { - views::View* contents_view = user_card_view_; - auto* button = - new ButtonFromView(contents_view, this, - IsActiveUser() ? TrayPopupInkDropStyle::INSET_BOUNDS - : TrayPopupInkDropStyle::FILL_BOUNDS); - user_card_view_ = button; - is_user_card_button_ = true; - } - AddChildViewAt(user_card_view_, 0); -} - -void UserView::ToggleAddUserMenuOption() { - if (add_menu_option_) { - RemoveAddUserMenuOption(); - return; - } - - // Note: We do not need to install a global event handler to delete this - // item since it will destroyed automatically before the menu / user menu item - // gets destroyed.. - add_menu_option_.reset(new views::Widget); - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_TOOLTIP; - params.keep_on_top = true; - params.accept_events = true; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.name = "AddUserMenuOption"; - WmWindow::Get(GetWidget()->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - add_menu_option_.get(), kShellWindowId_DragImageAndTooltipContainer, - ¶ms); - add_menu_option_->Init(params); - - const SessionStateDelegate* delegate = - WmShell::Get()->GetSessionStateDelegate(); - const AddUserSessionPolicy add_user_policy = - delegate->GetAddUserSessionPolicy(); - add_user_enabled_ = add_user_policy == AddUserSessionPolicy::ALLOWED; - - // Position the widget on top of the user card view (which is still in the - // system menu). The top half of the widget will be transparent to allow - // the active user to show through. - gfx::Rect bounds = user_card_view_->GetBoundsInScreen(); - bounds.set_width(bounds.width() + kSeparatorWidth); - int row_height = bounds.height(); - - views::View* container = new AddUserWidgetContents( - base::Bind(&UserView::RemoveAddUserMenuOption, base::Unretained(this))); - container->SetBorder(views::CreatePaddedBorder( - views::CreateSolidSidedBorder(0, 0, 0, kSeparatorWidth, kBackgroundColor), - gfx::Insets(row_height, 0, 0, 0))); - views::View* add_user_padding = new views::View(); - add_user_padding->SetBorder(views::CreateSolidSidedBorder( - kMenuSeparatorVerticalPadding, 0, 0, 0, kBackgroundColor)); - views::View* add_user_view = CreateAddUserView(add_user_policy, this); - add_user_padding->AddChildView(add_user_view); - add_user_padding->SetLayoutManager(new views::FillLayout()); - container->AddChildView(add_user_padding); - container->SetLayoutManager(new views::FillLayout()); - add_menu_option_->SetContentsView(container); - - bounds.set_height(container->GetPreferredSize().height()); - add_menu_option_->SetBounds(bounds); - - // Show the content. - add_menu_option_->SetAlwaysOnTop(true); - add_menu_option_->Show(); - - // Install a listener to focus changes so that we can remove the card when - // the focus gets changed. When called through the destruction of the bubble, - // the FocusManager cannot be determined anymore and we remember it here. - focus_manager_ = user_card_view_->GetFocusManager(); - focus_manager_->AddFocusChangeListener(this); -} - -void UserView::RemoveAddUserMenuOption() { - if (!add_menu_option_) - return; - focus_manager_->RemoveFocusChangeListener(this); - focus_manager_ = nullptr; - if (user_card_view_->GetFocusManager()) - user_card_view_->GetFocusManager()->ClearFocus(); - add_menu_option_.reset(); -} - -} // namespace tray -} // namespace ash
diff --git a/ash/system/user/user_view.h b/ash/system/user/user_view.h deleted file mode 100644 index 6bd903d..0000000 --- a/ash/system/user/user_view.h +++ /dev/null
@@ -1,96 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_USER_USER_VIEW_H_ -#define ASH_SYSTEM_USER_USER_VIEW_H_ - -#include <memory> - -#include "ash/public/cpp/session_types.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/user/tray_user.h" -#include "base/macros.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/focus/focus_manager.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/view.h" - -namespace gfx { -class Rect; -} - -namespace views { -class FocusManager; -} - -namespace ash { - -enum class LoginStatus; -class SystemTrayItem; - -namespace tray { - -// The view of a user item in system tray bubble. -class UserView : public views::View, - public views::ButtonListener, - public views::FocusChangeListener { - public: - UserView(SystemTrayItem* owner, LoginStatus login, UserIndex index); - ~UserView() override; - - TrayUser::TestState GetStateForTest() const; - gfx::Rect GetBoundsInScreenOfUserButtonForTest(); - - views::View* user_card_view_for_test() const { return user_card_view_; } - - private: - // Retruns true if |this| view is for the currently active user, i.e. top row. - bool IsActiveUser() const; - - // Overridden from views::View. - int GetHeightForWidth(int width) const override; - - // Overridden from views::ButtonListener. - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // Overridden from views::FocusChangeListener: - void OnWillChangeFocus(View* focused_before, View* focused_now) override; - void OnDidChangeFocus(View* focused_before, View* focused_now) override; - - void AddLogoutButton(LoginStatus login); - void AddUserCard(LoginStatus login); - - // Create the menu option to add another user. If |disabled| is set the user - // cannot actively click on the item. - void ToggleAddUserMenuOption(); - - // Removes the add user menu option. - void RemoveAddUserMenuOption(); - - const UserIndex user_index_; - views::View* user_card_view_; - - // This is the owner system tray item of this view. - SystemTrayItem* owner_; - - // True if |user_card_view_| is a |ButtonFromView| - otherwise it is only - // a |UserCardView|. - bool is_user_card_button_; - - views::View* logout_button_; - std::unique_ptr<views::Widget> add_menu_option_; - - // False when the add user panel is visible but not activatable. - bool add_user_enabled_; - - // The focus manager which we use to detect focus changes. - views::FocusManager* focus_manager_; - - DISALLOW_COPY_AND_ASSIGN(UserView); -}; - -} // namespace tray -} // namespace ash - -#endif // ASH_SYSTEM_USER_USER_VIEW_H_
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_observer.h b/ash/system/virtual_keyboard/virtual_keyboard_observer.h deleted file mode 100644 index f44ce06..0000000 --- a/ash/system/virtual_keyboard/virtual_keyboard_observer.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_OBSERVER_H_ -#define ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -class ASH_EXPORT VirtualKeyboardObserver { - public: - virtual ~VirtualKeyboardObserver() {} - - // Notifies when the keyboard is suppressed. - virtual void OnKeyboardSuppressionChanged(bool suppressed) = 0; -}; - -} // namespace ash - -#endif // ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_OBSERVER_H_
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc deleted file mode 100644 index 19e60ec..0000000 --- a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/virtual_keyboard/virtual_keyboard_tray.h" - -#include <algorithm> - -#include "ash/common/keyboard/keyboard_ui.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/tray_constants.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/display/display.h" -#include "ui/events/event.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/views/controls/image_view.h" - -namespace ash { - -VirtualKeyboardTray::VirtualKeyboardTray(WmShelf* wm_shelf) - : TrayBackgroundView(wm_shelf), - icon_(new views::ImageView), - wm_shelf_(wm_shelf) { - SetInkDropMode(InkDropMode::ON); - SetContentsBackground(false); - - icon_->SetImage(gfx::CreateVectorIcon(kShelfKeyboardIcon, kShelfIconColor)); - SetIconBorderForShelfAlignment(); - tray_container()->AddChildView(icon_); - - // The Shell may not exist in some unit tests. - if (WmShell::HasInstance()) - WmShell::Get()->keyboard_ui()->AddObserver(this); - // Try observing keyboard controller, in case it is already constructed. - ObserveKeyboardController(); -} - -VirtualKeyboardTray::~VirtualKeyboardTray() { - // Try unobserving keyboard controller, in case it still exists. - UnobserveKeyboardController(); - // The Shell may not exist in some unit tests. - if (WmShell::HasInstance()) - WmShell::Get()->keyboard_ui()->RemoveObserver(this); -} - -void VirtualKeyboardTray::SetShelfAlignment(ShelfAlignment alignment) { - if (alignment == shelf_alignment()) - return; - - TrayBackgroundView::SetShelfAlignment(alignment); - SetIconBorderForShelfAlignment(); -} - -base::string16 VirtualKeyboardTray::GetAccessibleNameForTray() { - return l10n_util::GetStringUTF16( - IDS_ASH_VIRTUAL_KEYBOARD_TRAY_ACCESSIBLE_NAME); -} - -void VirtualKeyboardTray::HideBubbleWithView( - const views::TrayBubbleView* bubble_view) {} - -void VirtualKeyboardTray::ClickedOutsideBubble() {} - -bool VirtualKeyboardTray::PerformAction(const ui::Event& event) { - const int64_t display_id = - wm_shelf_->GetWindow()->GetDisplayNearestWindow().id(); - WmShell::Get()->keyboard_ui()->ShowInDisplay(display_id); - // Normally, active status is set when virtual keyboard is shown/hidden, - // however, showing virtual keyboard happens asynchronously and, especially - // the first time, takes some time. We need to set active status here to - // prevent bad things happening if user clicked the button before keyboard is - // shown. - SetIsActive(true); - return true; -} - -void VirtualKeyboardTray::OnKeyboardEnabledStateChanged(bool new_enabled) { - SetVisible(new_enabled); - if (new_enabled) { - // Observe keyboard controller to detect when the virtual keyboard is - // shown/hidden. - ObserveKeyboardController(); - } else { - // Try unobserving keyboard controller, in case it is not yet destroyed. - UnobserveKeyboardController(); - } -} - -void VirtualKeyboardTray::OnKeyboardBoundsChanging( - const gfx::Rect& new_bounds) { - SetIsActive(!new_bounds.IsEmpty()); -} - -void VirtualKeyboardTray::OnKeyboardClosed() {} - -void VirtualKeyboardTray::SetIconBorderForShelfAlignment() { - const gfx::ImageSkia& image = icon_->GetImage(); - const int vertical_padding = (kTrayItemSize - image.height()) / 2; - const int horizontal_padding = (kTrayItemSize - image.width()) / 2; - icon_->SetBorder(views::CreateEmptyBorder( - gfx::Insets(vertical_padding, horizontal_padding))); -} - -void VirtualKeyboardTray::ObserveKeyboardController() { - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) - keyboard_controller->AddObserver(this); -} - -void VirtualKeyboardTray::UnobserveKeyboardController() { - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) - keyboard_controller->RemoveObserver(this); -} - -} // namespace ash
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray.h b/ash/system/virtual_keyboard/virtual_keyboard_tray.h deleted file mode 100644 index 1572e3d..0000000 --- a/ash/system/virtual_keyboard/virtual_keyboard_tray.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_ -#define ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_ - -#include "ash/common/keyboard/keyboard_ui_observer.h" -#include "ash/system/tray/tray_background_view.h" -#include "base/macros.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace views { -class ImageView; -} - -namespace ash { - -// TODO(sky): make this visible on non-chromeos platforms. -class VirtualKeyboardTray : public TrayBackgroundView, - public KeyboardUIObserver, - public keyboard::KeyboardControllerObserver { - public: - explicit VirtualKeyboardTray(WmShelf* wm_shelf); - ~VirtualKeyboardTray() override; - - // TrayBackgroundView: - void SetShelfAlignment(ShelfAlignment alignment) override; - base::string16 GetAccessibleNameForTray() override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void ClickedOutsideBubble() override; - bool PerformAction(const ui::Event& event) override; - - // KeyboardUIObserver: - void OnKeyboardEnabledStateChanged(bool new_enabled) override; - - // keyboard::KeyboardControllerObserver: - void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; - void OnKeyboardClosed() override; - - private: - // Creates a new border for the icon. The padding is determined based on the - // alignment of the shelf. - void SetIconBorderForShelfAlignment(); - - void ObserveKeyboardController(); - void UnobserveKeyboardController(); - - // Weak pointer, will be parented by TrayContainer for its lifetime. - views::ImageView* icon_; - - WmShelf* wm_shelf_; - - DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_VIRTUAL_KEYBOARD_VIRTUAL_KEYBOARD_TRAY_H_
diff --git a/ash/system/web_notification/ash_popup_alignment_delegate.cc b/ash/system/web_notification/ash_popup_alignment_delegate.cc deleted file mode 100644 index 0d33b7bc..0000000 --- a/ash/system/web_notification/ash_popup_alignment_delegate.cc +++ /dev/null
@@ -1,168 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/web_notification/ash_popup_alignment_delegate.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "base/i18n/rtl.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/message_center/message_center_style.h" -#include "ui/message_center/views/message_popup_collection.h" -#include "ui/wm/core/shadow_types.h" - -namespace ash { - -namespace { - -const int kToastMarginX = 7; - -// If there should be no margin for the first item, this value needs to be -// substracted to flush the message to the shelf (the width of the border + -// shadow). -const int kNoToastMarginBorderAndShadowOffset = 2; - -} // namespace - -AshPopupAlignmentDelegate::AshPopupAlignmentDelegate(WmShelf* shelf) - : screen_(NULL), shelf_(shelf), tray_bubble_height_(0) { - shelf_->AddObserver(this); -} - -AshPopupAlignmentDelegate::~AshPopupAlignmentDelegate() { - if (screen_) - screen_->RemoveObserver(this); - WmShell::Get()->RemoveShellObserver(this); - shelf_->RemoveObserver(this); -} - -void AshPopupAlignmentDelegate::StartObserving( - display::Screen* screen, - const display::Display& display) { - screen_ = screen; - work_area_ = display.work_area(); - screen->AddObserver(this); - WmShell::Get()->AddShellObserver(this); - if (tray_bubble_height_ > 0) - UpdateWorkArea(); -} - -void AshPopupAlignmentDelegate::SetTrayBubbleHeight(int height) { - tray_bubble_height_ = height; - - // If the shelf is shown during auto-hide state, the distance from the edge - // should be reduced by the height of shelf's shown height. - if (shelf_->GetVisibilityState() == SHELF_AUTO_HIDE && - shelf_->GetAutoHideState() == SHELF_AUTO_HIDE_SHOWN) { - tray_bubble_height_ -= GetShelfConstant(SHELF_SIZE) - - GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE); - } - - if (tray_bubble_height_ > 0) - tray_bubble_height_ += message_center::kMarginBetweenItems; - else - tray_bubble_height_ = 0; - - DoUpdateIfPossible(); -} - -int AshPopupAlignmentDelegate::GetToastOriginX( - const gfx::Rect& toast_bounds) const { - // In Ash, RTL UI language mirrors the whole ash layout, so the toast - // widgets should be at the bottom-left instead of bottom right. - if (base::i18n::IsRTL()) - return work_area_.x() + kToastMarginX; - - if (IsFromLeft()) - return work_area_.x() + kToastMarginX; - return work_area_.right() - kToastMarginX - toast_bounds.width(); -} - -int AshPopupAlignmentDelegate::GetBaseLine() const { - return work_area_.bottom() - kNoToastMarginBorderAndShadowOffset - - tray_bubble_height_; -} - -gfx::Rect AshPopupAlignmentDelegate::GetWorkArea() const { - gfx::Rect work_area_without_tray_bubble = work_area_; - work_area_without_tray_bubble.set_height( - work_area_without_tray_bubble.height() - tray_bubble_height_); - return work_area_without_tray_bubble; -} - -bool AshPopupAlignmentDelegate::IsTopDown() const { - return false; -} - -bool AshPopupAlignmentDelegate::IsFromLeft() const { - return GetAlignment() == SHELF_ALIGNMENT_LEFT; -} - -void AshPopupAlignmentDelegate::RecomputeAlignment( - const display::Display& display) { - // Nothing needs to be done. -} - -void AshPopupAlignmentDelegate::ConfigureWidgetInitParamsForContainer( - views::Widget* widget, - views::Widget::InitParams* init_params) { - init_params->shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP; - init_params->shadow_elevation = ::wm::ShadowElevation::MEDIUM; - // On ash, popups go in the status container. - shelf_->GetWindow() - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - widget, kShellWindowId_StatusContainer, init_params); -} - -ShelfAlignment AshPopupAlignmentDelegate::GetAlignment() const { - return shelf_->GetAlignment(); -} - -display::Display AshPopupAlignmentDelegate::GetCurrentDisplay() const { - return shelf_->GetWindow()->GetDisplayNearestWindow(); -} - -void AshPopupAlignmentDelegate::UpdateWorkArea() { - work_area_ = shelf_->GetUserWorkAreaBounds(); - DoUpdateIfPossible(); -} - -/////////////////////////////////////////////////////////////////////////////// -// WmShelfObserver: - -void AshPopupAlignmentDelegate::WillChangeVisibilityState( - ShelfVisibilityState new_state) { - UpdateWorkArea(); -} - -void AshPopupAlignmentDelegate::OnAutoHideStateChanged( - ShelfAutoHideState new_state) { - UpdateWorkArea(); -} - -/////////////////////////////////////////////////////////////////////////////// -// display::DisplayObserver: - -void AshPopupAlignmentDelegate::OnDisplayAdded( - const display::Display& new_display) {} - -void AshPopupAlignmentDelegate::OnDisplayRemoved( - const display::Display& old_display) {} - -void AshPopupAlignmentDelegate::OnDisplayMetricsChanged( - const display::Display& display, - uint32_t metrics) { - if (GetCurrentDisplay().id() == display.id()) - UpdateWorkArea(); -} - -} // namespace ash
diff --git a/ash/system/web_notification/ash_popup_alignment_delegate.h b/ash/system/web_notification/ash_popup_alignment_delegate.h deleted file mode 100644 index d8e41b4..0000000 --- a/ash/system/web_notification/ash_popup_alignment_delegate.h +++ /dev/null
@@ -1,94 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ -#define ASH_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ - -#include <stdint.h> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/wm_shelf_observer.h" -#include "base/macros.h" -#include "ui/display/display_observer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/message_center/views/popup_alignment_delegate.h" - -namespace display { -class Screen; -} - -namespace ash { - -class AshPopupAlignmentDelegateTest; -class WebNotificationTrayTest; -class WmShelf; - -// The PopupAlignmentDelegate subclass for Ash. It needs to handle alignment of -// the shelf and its autohide state. -class ASH_EXPORT AshPopupAlignmentDelegate - : public message_center::PopupAlignmentDelegate, - public WmShelfObserver, - public ShellObserver, - public display::DisplayObserver { - public: - explicit AshPopupAlignmentDelegate(WmShelf* shelf); - ~AshPopupAlignmentDelegate() override; - - // Start observing the system. - void StartObserving(display::Screen* screen, const display::Display& display); - - // Sets the current height of the system tray bubble (or legacy notification - // bubble) so that web notification toasts can avoid it. - void SetTrayBubbleHeight(int height); - - // Returns the current tray bubble height or 0 if there is no bubble. - int tray_bubble_height_for_test() const { return tray_bubble_height_; } - - // Overridden from message_center::PopupAlignmentDelegate: - int GetToastOriginX(const gfx::Rect& toast_bounds) const override; - int GetBaseLine() const override; - gfx::Rect GetWorkArea() const override; - bool IsTopDown() const override; - bool IsFromLeft() const override; - void RecomputeAlignment(const display::Display& display) override; - void ConfigureWidgetInitParamsForContainer( - views::Widget* widget, - views::Widget::InitParams* init_params) override; - - private: - friend class AshPopupAlignmentDelegateTest; - friend class WebNotificationTrayTest; - - // Get the current alignment of the shelf. - ShelfAlignment GetAlignment() const; - - // Utility function to get the display which should be care about. - display::Display GetCurrentDisplay() const; - - // Compute the new work area. - void UpdateWorkArea(); - - // WmShelfObserver: - void WillChangeVisibilityState(ShelfVisibilityState new_state) override; - void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; - - // Overridden from display::DisplayObserver: - void OnDisplayAdded(const display::Display& new_display) override; - void OnDisplayRemoved(const display::Display& old_display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t metrics) override; - - display::Screen* screen_; - gfx::Rect work_area_; - WmShelf* shelf_; - int tray_bubble_height_; - - DISALLOW_COPY_AND_ASSIGN(AshPopupAlignmentDelegate); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_
diff --git a/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc b/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc index 56ff6e9..f7728b2 100644 --- a/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc +++ b/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/web_notification/ash_popup_alignment_delegate.h" +#include "ash/common/system/web_notification/ash_popup_alignment_delegate.h" #include <utility> #include <vector> +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/command_line.h"
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc deleted file mode 100644 index 8e6c79df..0000000 --- a/ash/system/web_notification/web_notification_tray.cc +++ /dev/null
@@ -1,662 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/system/web_notification/web_notification_tray.h" - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/system/tray/tray_bubble_wrapper.h" -#include "ash/system/tray/tray_constants.h" -#include "ash/system/tray/tray_utils.h" -#include "ash/system/web_notification/ash_popup_alignment_delegate.h" -#include "base/auto_reset.h" -#include "base/i18n/number_formatting.h" -#include "base/i18n/rtl.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread_task_runner_handle.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/message_center/message_center_style.h" -#include "ui/message_center/message_center_tray_delegate.h" -#include "ui/message_center/views/message_bubble_base.h" -#include "ui/message_center/views/message_center_bubble.h" -#include "ui/message_center/views/message_popup_collection.h" -#include "ui/strings/grit/ui_strings.h" -#include "ui/views/bubble/tray_bubble_view.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/label.h" -#include "ui/views/controls/menu/menu_runner.h" -#include "ui/views/layout/fill_layout.h" - -namespace message_center { - -MessageCenterTrayDelegate* CreateMessageCenterTray() { - // On non-CrOS, the Tray will not be hosted in ash::Shell. - NOTREACHED(); - return nullptr; -} - -} // namespace message_center - -namespace ash { -namespace { - -// Menu commands -constexpr int kToggleQuietMode = 0; -constexpr int kEnableQuietModeDay = 2; - -constexpr int kMaximumSmallIconCount = 3; - -constexpr gfx::Size kTrayItemInnerIconSize(16, 16); -constexpr gfx::Size kTrayItemInnerBellIconSizeNonMd(18, 18); -constexpr gfx::Size kTrayItemOuterSize(26, 26); -constexpr int kTrayMainAxisInset = 3; -constexpr int kTrayCrossAxisInset = 0; - -constexpr int kTrayItemAnimationDurationMS = 200; - -constexpr size_t kMaximumNotificationNumber = 99; - -// Flag to disable animation. Only for testing. -bool disable_animations_for_test = false; -} - -namespace { - -const SkColor kWebNotificationColorNoUnread = - SkColorSetARGB(128, 255, 255, 255); -const SkColor kWebNotificationColorWithUnread = SK_ColorWHITE; -const int kNoUnreadIconSize = 18; - -} // namespace - -// Class to initialize and manage the WebNotificationBubble and -// TrayBubbleWrapper instances for a bubble. -class WebNotificationBubbleWrapper { - public: - // Takes ownership of |bubble| and creates |bubble_wrapper_|. - WebNotificationBubbleWrapper(WebNotificationTray* tray, - TrayBackgroundView* anchor_tray, - message_center::MessageBubbleBase* bubble) { - bubble_.reset(bubble); - views::TrayBubbleView::AnchorAlignment anchor_alignment = - tray->GetAnchorAlignment(); - views::TrayBubbleView::InitParams init_params = - bubble->GetInitParams(anchor_alignment); - views::TrayBubbleView* bubble_view = views::TrayBubbleView::Create( - anchor_tray->GetBubbleAnchor(), tray, &init_params); - bubble_view->set_anchor_view_insets(anchor_tray->GetBubbleAnchorInsets()); - bubble_wrapper_.reset(new TrayBubbleWrapper(tray, bubble_view)); - bubble->InitializeContents(bubble_view); - } - - message_center::MessageBubbleBase* bubble() const { return bubble_.get(); } - - // Convenience accessors. - views::TrayBubbleView* bubble_view() const { return bubble_->bubble_view(); } - - private: - std::unique_ptr<message_center::MessageBubbleBase> bubble_; - std::unique_ptr<TrayBubbleWrapper> bubble_wrapper_; - - DISALLOW_COPY_AND_ASSIGN(WebNotificationBubbleWrapper); -}; - -class WebNotificationItem : public views::View, public gfx::AnimationDelegate { - public: - WebNotificationItem(gfx::AnimationContainer* container, - WebNotificationTray* tray) - : tray_(tray) { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - views::View::SetVisible(false); - set_owned_by_client(); - - SetLayoutManager(new views::FillLayout); - - animation_.reset(new gfx::SlideAnimation(this)); - animation_->SetContainer(container); - animation_->SetSlideDuration(kTrayItemAnimationDurationMS); - animation_->SetTweenType(gfx::Tween::LINEAR); - } - - void SetVisible(bool set_visible) override { - if (!GetWidget() || disable_animations_for_test) { - views::View::SetVisible(set_visible); - return; - } - - if (!set_visible) { - animation_->Hide(); - AnimationProgressed(animation_.get()); - } else { - animation_->Show(); - AnimationProgressed(animation_.get()); - views::View::SetVisible(true); - } - } - - void HideAndDelete() { - SetVisible(false); - - if (!visible() && !animation_->is_animating()) { - if (parent()) - parent()->RemoveChildView(this); - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); - } else { - delete_after_animation_ = true; - } - } - - protected: - // Overridden from views::View: - gfx::Size GetPreferredSize() const override { - if (!animation_.get() || !animation_->is_animating()) - return kTrayItemOuterSize; - - // Animate the width (or height) when this item shows (or hides) so that - // the icons on the left are shifted with the animation. - // Note that TrayItemView does the same thing. - gfx::Size size = kTrayItemOuterSize; - if (IsHorizontalLayout()) { - size.set_width(std::max( - 1, gfx::ToRoundedInt(size.width() * animation_->GetCurrentValue()))); - } else { - size.set_height(std::max( - 1, gfx::ToRoundedInt(size.height() * animation_->GetCurrentValue()))); - } - return size; - } - - int GetHeightForWidth(int width) const override { - return GetPreferredSize().height(); - } - - bool IsHorizontalLayout() const { - return IsHorizontalAlignment(tray_->shelf_alignment()); - } - - private: - // gfx::AnimationDelegate: - void AnimationProgressed(const gfx::Animation* animation) override { - gfx::Transform transform; - if (IsHorizontalLayout()) { - transform.Translate(0, animation->CurrentValueBetween( - static_cast<double>(height()) / 2., 0.)); - } else { - transform.Translate( - animation->CurrentValueBetween(static_cast<double>(width() / 2.), 0.), - 0); - } - transform.Scale(animation->GetCurrentValue(), animation->GetCurrentValue()); - layer()->SetTransform(transform); - PreferredSizeChanged(); - } - void AnimationEnded(const gfx::Animation* animation) override { - if (animation->GetCurrentValue() < 0.1) - views::View::SetVisible(false); - - if (delete_after_animation_) { - if (parent()) - parent()->RemoveChildView(this); - base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this); - } - } - void AnimationCanceled(const gfx::Animation* animation) override { - AnimationEnded(animation); - } - - std::unique_ptr<gfx::SlideAnimation> animation_; - bool delete_after_animation_ = false; - WebNotificationTray* tray_; - - DISALLOW_COPY_AND_ASSIGN(WebNotificationItem); -}; - -class WebNotificationImage : public WebNotificationItem { - public: - WebNotificationImage(const gfx::ImageSkia& image, - const gfx::Size& size, - gfx::AnimationContainer* container, - WebNotificationTray* tray) - : WebNotificationItem(container, tray) { - view_ = new views::ImageView(); - view_->SetImage(image); - view_->SetImageSize(size); - AddChildView(view_); - } - - private: - views::ImageView* view_; - - DISALLOW_COPY_AND_ASSIGN(WebNotificationImage); -}; - -class WebNotificationLabel : public WebNotificationItem { - public: - WebNotificationLabel(gfx::AnimationContainer* container, - WebNotificationTray* tray) - : WebNotificationItem(container, tray) { - view_ = new views::Label(); - SetupLabelForTray(view_); - AddChildView(view_); - } - - void SetNotificationCount(bool small_icons_exist, size_t notification_count) { - notification_count = std::min(notification_count, - kMaximumNotificationNumber); // cap with 99 - - // TODO(yoshiki): Use a string for "99" and "+99". - - base::string16 str = base::FormatNumber(notification_count); - if (small_icons_exist) { - if (!base::i18n::IsRTL()) - str = base::ASCIIToUTF16("+") + str; - else - str = str + base::ASCIIToUTF16("+"); - } - - view_->SetText(str); - view_->SetEnabledColor(kWebNotificationColorWithUnread); - SchedulePaint(); - } - - private: - views::Label* view_; - - DISALLOW_COPY_AND_ASSIGN(WebNotificationLabel); -}; - -WebNotificationTray::WebNotificationTray(WmShelf* shelf, - WmWindow* status_area_window, - SystemTray* system_tray) - : TrayBackgroundView(shelf), - status_area_window_(status_area_window), - system_tray_(system_tray), - show_message_center_on_unlock_(false), - should_update_tray_content_(false), - should_block_shelf_auto_hide_(false) { - DCHECK(shelf); - DCHECK(status_area_window_); - DCHECK(system_tray_); - - if (MaterialDesignController::IsShelfMaterial()) { - SetInkDropMode(InkDropMode::ON); - SetContentsBackground(false); - gfx::ImageSkia bell_image = - CreateVectorIcon(kShelfNotificationsIcon, kShelfIconColor); - const gfx::Size bell_icon_size = kTrayItemInnerIconSize; - bell_icon_.reset(new WebNotificationImage( - bell_image, bell_icon_size, animation_container_.get(), this)); - } else { - SetContentsBackground(true); - gfx::ImageSkia bell_image = - CreateVectorIcon(gfx::VectorIconId::NOTIFICATIONS, kNoUnreadIconSize, - kWebNotificationColorNoUnread); - const gfx::Size bell_icon_size = kTrayItemInnerBellIconSizeNonMd; - bell_icon_.reset(new WebNotificationImage( - bell_image, bell_icon_size, animation_container_.get(), this)); - } - tray_container()->AddChildView(bell_icon_.get()); - - counter_.reset(new WebNotificationLabel(animation_container_.get(), this)); - tray_container()->AddChildView(counter_.get()); - - message_center_tray_.reset(new message_center::MessageCenterTray( - this, message_center::MessageCenter::Get())); - popup_alignment_delegate_.reset(new AshPopupAlignmentDelegate(shelf)); - popup_collection_.reset(new message_center::MessagePopupCollection( - message_center(), message_center_tray_.get(), - popup_alignment_delegate_.get())); - const display::Display& display = - status_area_window_->GetDisplayNearestWindow(); - popup_alignment_delegate_->StartObserving(display::Screen::GetScreen(), - display); - OnMessageCenterTrayChanged(); - - tray_container()->SetMargin(kTrayMainAxisInset, kTrayCrossAxisInset); -} - -WebNotificationTray::~WebNotificationTray() { - // Release any child views that might have back pointers before ~View(). - message_center_bubble_.reset(); - popup_alignment_delegate_.reset(); - popup_collection_.reset(); -} - -// static -void WebNotificationTray::DisableAnimationsForTest(bool disable) { - disable_animations_for_test = disable; -} - -// Public methods. - -bool WebNotificationTray::ShowMessageCenterInternal(bool show_settings) { - if (!ShouldShowMessageCenter()) - return false; - - should_block_shelf_auto_hide_ = true; - message_center::MessageCenterBubble* message_center_bubble = - new message_center::MessageCenterBubble(message_center(), - message_center_tray_.get()); - - // In the horizontal case, message center starts from the top of the shelf. - // In the vertical case, it starts from the bottom of WebNotificationTray. - const int max_height = IsHorizontalAlignment(shelf_alignment()) - ? shelf()->GetIdealBounds().y() - : GetBoundsInScreen().bottom(); - message_center_bubble->SetMaxHeight(max_height); - - if (show_settings) - message_center_bubble->SetSettingsVisible(); - - // For vertical shelf alignments, anchor to the WebNotificationTray, but for - // horizontal (i.e. bottom) shelves, anchor to the system tray. - TrayBackgroundView* anchor_tray = this; - if (IsHorizontalAlignment(shelf_alignment())) { - anchor_tray = WmShelf::ForWindow(status_area_window_) - ->GetStatusAreaWidget() - ->system_tray(); - } - - message_center_bubble_.reset(new WebNotificationBubbleWrapper( - this, anchor_tray, message_center_bubble)); - - shelf()->UpdateAutoHideState(); - SetIsActive(true); - return true; -} - -bool WebNotificationTray::ShowMessageCenter() { - return ShowMessageCenterInternal(false /* show_settings */); -} - -void WebNotificationTray::HideMessageCenter() { - if (!message_center_bubble()) - return; - SetIsActive(false); - message_center_bubble_.reset(); - should_block_shelf_auto_hide_ = false; - show_message_center_on_unlock_ = false; - shelf()->UpdateAutoHideState(); -} - -void WebNotificationTray::SetTrayBubbleHeight(int height) { - popup_alignment_delegate_->SetTrayBubbleHeight(height); -} - -int WebNotificationTray::tray_bubble_height_for_test() const { - return popup_alignment_delegate_->tray_bubble_height_for_test(); -} - -bool WebNotificationTray::ShowPopups() { - if (message_center_bubble()) - return false; - - popup_collection_->DoUpdateIfPossible(); - return true; -} - -void WebNotificationTray::HidePopups() { - DCHECK(popup_collection_.get()); - popup_collection_->MarkAllPopupsShown(); -} - -// Private methods. - -bool WebNotificationTray::ShouldShowMessageCenter() { - return WmShell::Get()->system_tray_delegate()->ShouldShowNotificationTray(); -} - -bool WebNotificationTray::ShouldBlockShelfAutoHide() const { - return should_block_shelf_auto_hide_; -} - -bool WebNotificationTray::IsMessageCenterBubbleVisible() const { - return (message_center_bubble() && - message_center_bubble()->bubble()->IsVisible()); -} - -void WebNotificationTray::ShowMessageCenterBubble() { - if (!IsMessageCenterBubbleVisible()) - message_center_tray_->ShowMessageCenterBubble(); -} - -void WebNotificationTray::UpdateAfterLoginStatusChange( - LoginStatus login_status) { - message_center()->SetLockedState(login_status == LoginStatus::LOCKED); - OnMessageCenterTrayChanged(); -} - -void WebNotificationTray::SetShelfAlignment(ShelfAlignment alignment) { - if (alignment == shelf_alignment()) - return; - TrayBackgroundView::SetShelfAlignment(alignment); - // Destroy any existing bubble so that it will be rebuilt correctly. - message_center_tray_->HideMessageCenterBubble(); - message_center_tray_->HidePopupBubble(); -} - -void WebNotificationTray::AnchorUpdated() { - if (message_center_bubble()) { - message_center_bubble()->bubble_view()->UpdateBubble(); - UpdateBubbleViewArrow(message_center_bubble()->bubble_view()); - } -} - -base::string16 WebNotificationTray::GetAccessibleNameForTray() { - return l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_ACCESSIBLE_NAME); -} - -void WebNotificationTray::HideBubbleWithView( - const views::TrayBubbleView* bubble_view) { - if (message_center_bubble() && - bubble_view == message_center_bubble()->bubble_view()) { - message_center_tray_->HideMessageCenterBubble(); - } else if (popup_collection_.get()) { - message_center_tray_->HidePopupBubble(); - } -} - -bool WebNotificationTray::PerformAction(const ui::Event& event) { - if (message_center_bubble()) - message_center_tray_->HideMessageCenterBubble(); - else - message_center_tray_->ShowMessageCenterBubble(); - return true; -} - -void WebNotificationTray::BubbleViewDestroyed() { - if (message_center_bubble()) - message_center_bubble()->bubble()->BubbleViewDestroyed(); -} - -void WebNotificationTray::OnMouseEnteredView() {} - -void WebNotificationTray::OnMouseExitedView() {} - -base::string16 WebNotificationTray::GetAccessibleNameForBubble() { - return GetAccessibleNameForTray(); -} - -void WebNotificationTray::OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const { - // Place the bubble in the same root window as |anchor_widget|. - WmWindow::Get(anchor_widget->GetNativeWindow()) - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - bubble_widget, kShellWindowId_SettingBubbleContainer, params); -} - -void WebNotificationTray::HideBubble(const views::TrayBubbleView* bubble_view) { - HideBubbleWithView(bubble_view); -} - -bool WebNotificationTray::ShowNotifierSettings() { - if (message_center_bubble()) { - static_cast<message_center::MessageCenterBubble*>( - message_center_bubble()->bubble()) - ->SetSettingsVisible(); - return true; - } - return ShowMessageCenterInternal(true /* show_settings */); -} - -bool WebNotificationTray::IsContextMenuEnabled() const { - return IsLoggedIn(); -} - -message_center::MessageCenterTray* WebNotificationTray::GetMessageCenterTray() { - return message_center_tray_.get(); -} - -bool WebNotificationTray::IsCommandIdChecked(int command_id) const { - if (command_id != kToggleQuietMode) - return false; - return message_center()->IsQuietMode(); -} - -bool WebNotificationTray::IsCommandIdEnabled(int command_id) const { - return true; -} - -void WebNotificationTray::ExecuteCommand(int command_id, int event_flags) { - if (command_id == kToggleQuietMode) { - bool in_quiet_mode = message_center()->IsQuietMode(); - message_center()->SetQuietMode(!in_quiet_mode); - return; - } - base::TimeDelta expires_in = command_id == kEnableQuietModeDay - ? base::TimeDelta::FromDays(1) - : base::TimeDelta::FromHours(1); - message_center()->EnterQuietModeWithExpire(expires_in); -} - -void WebNotificationTray::OnMessageCenterTrayChanged() { - // Do not update the tray contents directly. Multiple change events can happen - // consecutively, and calling Update in the middle of those events will show - // intermediate unread counts for a moment. - should_update_tray_content_ = true; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&WebNotificationTray::UpdateTrayContent, AsWeakPtr())); -} - -void WebNotificationTray::UpdateTrayContent() { - if (!should_update_tray_content_) - return; - should_update_tray_content_ = false; - - std::unordered_set<std::string> notification_ids; - for (auto pair : visible_small_icons_) - notification_ids.insert(pair.first); - - // Add small icons (up to kMaximumSmallIconCount = 3). - message_center::MessageCenter* message_center = - message_center_tray_->message_center(); - size_t visible_small_icon_count = 0; - for (const auto* notification : message_center->GetVisibleNotifications()) { - gfx::Image image = notification->small_image(); - if (image.IsEmpty()) - continue; - - if (visible_small_icon_count >= kMaximumSmallIconCount) - break; - visible_small_icon_count++; - - notification_ids.erase(notification->id()); - if (visible_small_icons_.count(notification->id()) != 0) - continue; - - auto* item = - new WebNotificationImage(image.AsImageSkia(), kTrayItemInnerIconSize, - animation_container_.get(), this); - visible_small_icons_.insert(std::make_pair(notification->id(), item)); - - tray_container()->AddChildViewAt(item, 0); - item->SetVisible(true); - } - - // Remove unnecessary icons. - for (const std::string& id : notification_ids) { - WebNotificationImage* item = visible_small_icons_[id]; - visible_small_icons_.erase(id); - item->HideAndDelete(); - } - - // Show or hide the bell icon. - size_t visible_notification_count = message_center->NotificationCount(); - bell_icon_->SetVisible(visible_notification_count == 0); - - // Show or hide the counter. - size_t hidden_icon_count = - visible_notification_count - visible_small_icon_count; - if (hidden_icon_count != 0) { - counter_->SetVisible(true); - counter_->SetNotificationCount( - (visible_small_icon_count != 0), // small_icons_exist - hidden_icon_count); - } else { - counter_->SetVisible(false); - } - - SetVisible(IsLoggedIn() && ShouldShowMessageCenter()); - PreferredSizeChanged(); - Layout(); - SchedulePaint(); - if (IsLoggedIn()) - system_tray_->SetNextFocusableView(this); -} - -void WebNotificationTray::ClickedOutsideBubble() { - // Only hide the message center - if (!message_center_bubble()) - return; - - message_center_tray_->HideMessageCenterBubble(); -} - -message_center::MessageCenter* WebNotificationTray::message_center() const { - return message_center_tray_->message_center(); -} - -bool WebNotificationTray::IsLoggedIn() const { - WmShell* shell = WmShell::Get(); - return shell->system_tray_delegate()->GetUserLoginStatus() != - LoginStatus::NOT_LOGGED_IN && - !shell->GetSessionStateDelegate()->IsInSecondaryLoginScreen(); -} - -// Methods for testing - -bool WebNotificationTray::IsPopupVisible() const { - return message_center_tray_->popups_visible(); -} - -message_center::MessageCenterBubble* -WebNotificationTray::GetMessageCenterBubbleForTest() { - if (!message_center_bubble()) - return nullptr; - return static_cast<message_center::MessageCenterBubble*>( - message_center_bubble()->bubble()); -} - -} // namespace ash
diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h deleted file mode 100644 index da07447..0000000 --- a/ash/system/web_notification/web_notification_tray.h +++ /dev/null
@@ -1,190 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_ -#define ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/login_status.h" -#include "ash/system/tray/tray_background_view.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "ui/base/models/simple_menu_model.h" -#include "ui/gfx/animation/animation_container.h" -#include "ui/message_center/message_center_tray.h" -#include "ui/message_center/message_center_tray_delegate.h" -#include "ui/views/bubble/tray_bubble_view.h" - -// Status area tray for showing browser and app notifications. This hosts -// a MessageCenter class which manages the notification list. This class -// contains the Ash specific tray implementation. -// -// Note: These are not related to system notifications (i.e NotificationView -// generated by SystemTrayItem). Visibility of one notification type or other -// is controlled by StatusAreaWidget. - -namespace message_center { -class MessageCenter; -class MessageCenterBubble; -class MessagePopupCollection; -} - -namespace ash { -class AshPopupAlignmentDelegate; -class SystemTray; -class WebNotificationBubbleWrapper; -class WebNotificationImage; -class WebNotificationLabel; -class WmWindow; - -class ASH_EXPORT WebNotificationTray - : public TrayBackgroundView, - public views::TrayBubbleView::Delegate, - public message_center::MessageCenterTrayDelegate, - public base::SupportsWeakPtr<WebNotificationTray>, - public ui::SimpleMenuModel::Delegate { - public: - WebNotificationTray(WmShelf* shelf, - WmWindow* status_area_window, - SystemTray* system_tray); - ~WebNotificationTray() override; - - static void DisableAnimationsForTest(bool disable); - - // Sets the height of the system tray bubble (or legacy notification bubble) - // from the edge of the work area so that the web notification popups don't - // overlap with the tray. Pass 0 if no bubble is shown. - void SetTrayBubbleHeight(int height); - - // Returns the current tray bubble height or 0 if there is no bubble. - int tray_bubble_height_for_test() const; - - // Returns true if it should block the auto hide behavior of the shelf. - bool ShouldBlockShelfAutoHide() const; - - // Returns true if the message center bubble is visible. - bool IsMessageCenterBubbleVisible() const; - - // Shows the message center bubble. - void ShowMessageCenterBubble(); - - // Called when the login status is changed. - void UpdateAfterLoginStatusChange(LoginStatus login_status); - - // Overridden from TrayBackgroundView. - void SetShelfAlignment(ShelfAlignment alignment) override; - void AnchorUpdated() override; - base::string16 GetAccessibleNameForTray() override; - void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override; - void ClickedOutsideBubble() override; - - // Overridden from ActionableView. - bool PerformAction(const ui::Event& event) override; - - // Overridden from views::TrayBubbleView::Delegate. - void BubbleViewDestroyed() override; - void OnMouseEnteredView() override; - void OnMouseExitedView() override; - base::string16 GetAccessibleNameForBubble() override; - void OnBeforeBubbleWidgetInit( - views::Widget* anchor_widget, - views::Widget* bubble_widget, - views::Widget::InitParams* params) const override; - void HideBubble(const views::TrayBubbleView* bubble_view) override; - - // Overridden from MessageCenterTrayDelegate. - void OnMessageCenterTrayChanged() override; - bool ShowMessageCenter() override; - void HideMessageCenter() override; - bool ShowPopups() override; - void HidePopups() override; - bool ShowNotifierSettings() override; - bool IsContextMenuEnabled() const override; - message_center::MessageCenterTray* GetMessageCenterTray() override; - - // Overridden from ui::SimpleMenuModel::Delegate. - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - void ExecuteCommand(int command_id, int event_flags) override; - - message_center::MessageCenter* message_center() const; - - private: - friend class WebNotificationTrayTest; - - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotifications); - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotificationPopupBubble); - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, - ManyMessageCenterNotifications); - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, ManyPopupNotifications); - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupShownOnBothDisplays); - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupAndSystemTray); - FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupAndAutoHideShelf); - - void UpdateTrayContent(); - - // The actual process to show the message center. Set |show_settings| to true - // if the message center should be initialized with the settings visible. - // Returns true if the center is successfully created. - bool ShowMessageCenterInternal(bool show_settings); - - // Queries login status and the status area widget to determine visibility of - // the message center. - bool ShouldShowMessageCenter(); - - // Returns true if it should show the quiet mode menu. - bool ShouldShowQuietModeMenu(const ui::Event& event); - - // Shows the quiet mode menu. - void ShowQuietModeMenu(const ui::Event& event); - - // Creates the menu model for quiet mode and returns it. - ui::MenuModel* CreateQuietModeMenu(); - - WebNotificationBubbleWrapper* message_center_bubble() const { - return message_center_bubble_.get(); - } - - // Returns true if any user is logged in and the system is not at the screen - // for adding a secondary user. - bool IsLoggedIn() const; - - // Testing accessors. - bool IsPopupVisible() const; - message_center::MessageCenterBubble* GetMessageCenterBubbleForTest(); - - WmWindow* status_area_window_; - SystemTray* system_tray_; - std::unique_ptr<message_center::MessageCenterTray> message_center_tray_; - std::unique_ptr<WebNotificationBubbleWrapper> message_center_bubble_; - std::unique_ptr<message_center::MessagePopupCollection> popup_collection_; - std::unique_ptr<WebNotificationImage> bell_icon_; - std::unique_ptr<WebNotificationLabel> counter_; - - scoped_refptr<gfx::AnimationContainer> animation_container_ = - new gfx::AnimationContainer(); - - std::unordered_map<std::string, WebNotificationImage*> visible_small_icons_; - - bool show_message_center_on_unlock_; - - bool should_update_tray_content_; - - // True when the shelf auto hide behavior has to be blocked. Previously - // this was done by checking |message_center_bubble_| but actually - // the check can be called when creating this object, so it would cause - // flickers of the shelf from hidden to shown. See: crbug.com/181213 - bool should_block_shelf_auto_hide_; - - std::unique_ptr<AshPopupAlignmentDelegate> popup_alignment_delegate_; - - DISALLOW_COPY_AND_ASSIGN(WebNotificationTray); -}; - -} // namespace ash - -#endif // ASH_SYSTEM_WEB_NOTIFICATION_WEB_NOTIFICATION_TRAY_H_
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc index 4a00585..5b00cc1 100644 --- a/ash/system/web_notification/web_notification_tray_unittest.cc +++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -2,26 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/system/web_notification/web_notification_tray.h" +#include "ash/common/system/web_notification/web_notification_tray.h" #include <utility> #include <vector> +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_item.h" +#include "ash/common/system/web_notification/ash_popup_alignment_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/screen_layout_observer.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_item.h" -#include "ash/system/web_notification/ash_popup_alignment_delegate.h" +#include "ash/system/chromeos/screen_layout_observer.h" #include "ash/test/ash_test_base.h" #include "ash/test/status_area_widget_test_helper.h" -#include "ash/test/test_system_tray_delegate.h" -#include "ash/wm/window_state.h" #include "base/memory/ptr_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h"
diff --git a/ash/test/BUILD.gn b/ash/test/BUILD.gn index 02c7e16..96d7d5d 100644 --- a/ash/test/BUILD.gn +++ b/ash/test/BUILD.gn
@@ -67,23 +67,23 @@ testonly = true visibility = [ ":*" ] sources = [ - "ash_test.cc", - "ash_test.h", - "ash_test_impl.h", - "test_palette_delegate.cc", - "test_palette_delegate.h", - "test_session_state_delegate.cc", - "test_session_state_delegate.h", - "test_shelf_delegate.cc", - "test_shelf_delegate.h", - "test_shelf_item_delegate.cc", - "test_shelf_item_delegate.h", - "test_system_tray_delegate.cc", - "test_system_tray_delegate.h", - "wm_shell_test_api.cc", - "wm_shell_test_api.h", - "workspace_event_handler_test_helper.cc", - "workspace_event_handler_test_helper.h", + "../common/test/ash_test.cc", + "../common/test/ash_test.h", + "../common/test/ash_test_impl.h", + "../common/test/test_palette_delegate.cc", + "../common/test/test_palette_delegate.h", + "../common/test/test_session_state_delegate.cc", + "../common/test/test_session_state_delegate.h", + "../common/test/test_shelf_delegate.cc", + "../common/test/test_shelf_delegate.h", + "../common/test/test_shelf_item_delegate.cc", + "../common/test/test_shelf_item_delegate.h", + "../common/test/test_system_tray_delegate.cc", + "../common/test/test_system_tray_delegate.h", + "../common/test/wm_shell_test_api.cc", + "../common/test/wm_shell_test_api.h", + "../common/test/workspace_event_handler_test_helper.cc", + "../common/test/workspace_event_handler_test_helper.h", # TODO(jamescook): Move these files into ash/test. "../laser/laser_pointer_controller_test_api.cc",
diff --git a/ash/test/ash_test.cc b/ash/test/ash_test.cc deleted file mode 100644 index f3d7072..0000000 --- a/ash/test/ash_test.cc +++ /dev/null
@@ -1,143 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/ash_test.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/system/status_area_widget.h" -#include "ash/test/ash_test_impl.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/test/test_system_tray_delegate.h" -#include "base/memory/ptr_util.h" -#include "base/run_loop.h" -#include "ui/compositor/layer_type.h" -#include "ui/display/display.h" - -namespace ash { - -WindowOwner::WindowOwner(WmWindow* window) : window_(window) {} - -WindowOwner::~WindowOwner() { - window_->Destroy(); -} - -AshTest::AshTest() : test_impl_(AshTestImpl::Create()) {} - -AshTest::~AshTest() {} - -// static -WmShelf* AshTest::GetPrimaryShelf() { - return WmShell::Get() - ->GetPrimaryRootWindow() - ->GetRootWindowController() - ->GetShelf(); -} - -// static -SystemTray* AshTest::GetPrimarySystemTray() { - return GetPrimaryShelf()->GetStatusAreaWidget()->system_tray(); -} - -// static -test::TestSystemTrayDelegate* AshTest::GetSystemTrayDelegate() { - return static_cast<test::TestSystemTrayDelegate*>( - WmShell::Get()->system_tray_delegate()); -} - -void AshTest::UpdateDisplay(const std::string& display_spec) { - return test_impl_->UpdateDisplay(display_spec); -} - -std::unique_ptr<WindowOwner> AshTest::CreateTestWindow(const gfx::Rect& bounds, - ui::wm::WindowType type, - int shell_window_id) { - return test_impl_->CreateTestWindow(bounds, type, shell_window_id); -} - -std::unique_ptr<WindowOwner> AshTest::CreateToplevelTestWindow( - const gfx::Rect& bounds_in_screen, - int shell_window_id) { - return test_impl_->CreateToplevelTestWindow(bounds_in_screen, - shell_window_id); -} - -std::unique_ptr<WindowOwner> AshTest::CreateChildWindow(WmWindow* parent, - const gfx::Rect& bounds, - int shell_window_id) { - std::unique_ptr<WindowOwner> window_owner = - base::MakeUnique<WindowOwner>(WmShell::Get()->NewWindow( - ui::wm::WINDOW_TYPE_NORMAL, ui::LAYER_NOT_DRAWN)); - window_owner->window()->SetBounds(bounds); - window_owner->window()->SetShellWindowId(shell_window_id); - parent->AddChild(window_owner->window()); - window_owner->window()->Show(); - return window_owner; -} - -// static -std::unique_ptr<views::Widget> AshTest::CreateTestWidget( - const gfx::Rect& bounds, - views::WidgetDelegate* delegate, - int container_id) { - std::unique_ptr<views::Widget> widget(new views::Widget); - views::Widget::InitParams params; - params.delegate = delegate; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = bounds; - WmShell::Get() - ->GetPrimaryRootWindow() - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer(widget.get(), container_id, - ¶ms); - widget->Init(params); - widget->Show(); - return widget; -} - -display::Display AshTest::GetSecondaryDisplay() { - return test_impl_->GetSecondaryDisplay(); -} - -bool AshTest::SetSecondaryDisplayPlacement( - display::DisplayPlacement::Position position, - int offset) { - if (WmShell::Get()->IsRunningInMash()) { - NOTIMPLEMENTED(); - return false; - } - return test_impl_->SetSecondaryDisplayPlacement(position, offset); -} - -void AshTest::ConfigureWidgetInitParamsForDisplay( - WmWindow* window, - views::Widget::InitParams* init_params) { - test_impl_->ConfigureWidgetInitParamsForDisplay(window, init_params); -} - -void AshTest::ParentWindowInPrimaryRootWindow(WmWindow* window) { - window->SetParentUsingContext(WmShell::Get()->GetPrimaryRootWindow(), - gfx::Rect()); -} - -void AshTest::AddTransientChild(WmWindow* parent, WmWindow* window) { - test_impl_->AddTransientChild(parent, window); -} - -void AshTest::RunAllPendingInMessageLoop() { - base::RunLoop run_loop; - run_loop.RunUntilIdle(); -} - -void AshTest::SetUp() { - test_impl_->SetUp(); -} - -void AshTest::TearDown() { - test_impl_->TearDown(); -} - -} // namespace ash
diff --git a/ash/test/ash_test.h b/ash/test/ash_test.h deleted file mode 100644 index 0eccb70d..0000000 --- a/ash/test/ash_test.h +++ /dev/null
@@ -1,149 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_ASH_TEST_H_ -#define ASH_TEST_ASH_TEST_H_ - -#include <memory> -#include <string> - -#include "ash/public/cpp/shell_window_ids.h" -#include "base/macros.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/display/display_layout.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/public/window_types.h" - -namespace display { -class Display; -} - -namespace views { -class WidgetDelegate; -} - -namespace ash { - -class AshTestImpl; -class SystemTray; -class WmShelf; -class WmWindow; - -namespace test { -class TestSystemTrayDelegate; -} - -// Wraps a WmWindow calling WmWindow::Destroy() from the destructor. WmWindow is -// owned by the corresponding window implementation. The only way to delete -// WmWindow is to call WmWindow::Destroy(), which deletes the corresponding -// window, then the WmWindow. This class calls WmWindow::Destroy() from its -// destructor. -class WindowOwner { - public: - explicit WindowOwner(WmWindow* window); - ~WindowOwner(); - - WmWindow* window() { return window_; } - - private: - WmWindow* window_; - - DISALLOW_COPY_AND_ASSIGN(WindowOwner); -}; - -// Base class for ash tests. This class calls through to AshTestImpl for the -// real implementation. This class exists so that tests can be written to -// ash/common and run in both mus and aura. -// -// The implementation of AshTestImpl that is used depends upon gn targets. To -// use the aura backend depend on "//ash/test:ash_with_aura_test_support." The -// mus backend is not provided as a separate link target. -class AshTest : public testing::Test { - public: - AshTest(); - ~AshTest() override; - - // Returns the WmShelf for the primary display. - static WmShelf* GetPrimaryShelf(); - - // Returns the system tray on the primary display. - static SystemTray* GetPrimarySystemTray(); - - static test::TestSystemTrayDelegate* GetSystemTrayDelegate(); - - // Update the display configuration as given in |display_spec|. - // See test::DisplayManagerTestApi::UpdateDisplay for more details. - void UpdateDisplay(const std::string& display_spec); - - // Creates a visible window in the appropriate container. If - // |bounds_in_screen| is empty the window is added to the primary root - // window, otherwise the window is added to the display matching - // |bounds_in_screen|. |shell_window_id| is the shell window id to give to - // the new window. - std::unique_ptr<WindowOwner> CreateTestWindow( - const gfx::Rect& bounds_in_screen = gfx::Rect(), - ui::wm::WindowType type = ui::wm::WINDOW_TYPE_NORMAL, - int shell_window_id = kShellWindowId_Invalid); - - // Creates a visible top-level window. For aura a top-level window is a Window - // that has a delegate, see aura::Window::GetToplevelWindow() for more - // details. - std::unique_ptr<WindowOwner> CreateToplevelTestWindow( - const gfx::Rect& bounds_in_screen = gfx::Rect(), - int shell_window_id = kShellWindowId_Invalid); - - // Creates a visible window parented to |parent| with the specified bounds and - // id. - std::unique_ptr<WindowOwner> CreateChildWindow( - WmWindow* parent, - const gfx::Rect& bounds = gfx::Rect(), - int shell_window_id = kShellWindowId_Invalid); - - // Creates and shows a widget. See ash/public/cpp/shell_window_ids.h for - // values for |container_id|. - static std::unique_ptr<views::Widget> CreateTestWidget( - const gfx::Rect& bounds, - views::WidgetDelegate* delegate = nullptr, - int container_id = kShellWindowId_DefaultContainer); - - // Returns the Display for the secondary display. It's assumed there are two - // displays. - display::Display GetSecondaryDisplay(); - - // Sets the placement of the secondary display. Returns true if the secondary - // display can be moved, false otherwise. The false return value is temporary - // until mus fully supports this. - bool SetSecondaryDisplayPlacement( - display::DisplayPlacement::Position position, - int offset); - - // Configures |init_params| so that the widget will be created on the same - // display as |window|. - void ConfigureWidgetInitParamsForDisplay( - WmWindow* window, - views::Widget::InitParams* init_params); - - // Adds |window| to the appropriate container in the primary root window. - void ParentWindowInPrimaryRootWindow(WmWindow* window); - - // Adds |window| as as a transient child of |parent|. - void AddTransientChild(WmWindow* parent, WmWindow* window); - - void RunAllPendingInMessageLoop(); - - protected: - // testing::Test: - void SetUp() override; - void TearDown() override; - - private: - std::unique_ptr<AshTestImpl> test_impl_; - - DISALLOW_COPY_AND_ASSIGN(AshTest); -}; - -} // namespace ash - -#endif // ASH_TEST_ASH_TEST_H_
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index 32fc673..3da727a 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc
@@ -7,6 +7,9 @@ #include <string> #include <vector> +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm/window_positioner.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/extended_mouse_warp_controller.h" @@ -19,10 +22,7 @@ #include "ash/shell/toplevel_window.h" #include "ash/test/ash_test_environment.h" #include "ash/test/ash_test_helper.h" -#include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" -#include "ash/test/test_system_tray_delegate.h" -#include "ash/wm/window_positioner.h" #include "base/command_line.h" #include "services/ui/public/interfaces/window_manager_constants.mojom.h" #include "ui/aura/client/aura_constants.h"
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 1ed61fa..7421eec7 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -5,6 +5,9 @@ #include "ash/test/ash_test_helper.h" #include "ash/accelerators/accelerator_controller_delegate_aura.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/test/wm_shell_test_api.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/mus/screen_mus.h" @@ -12,15 +15,12 @@ #include "ash/mus/window_manager_application.h" #include "ash/shell.h" #include "ash/shell_init_params.h" -#include "ash/system/screen_layout_observer.h" +#include "ash/system/chromeos/screen_layout_observer.h" #include "ash/test/ash_test_environment.h" #include "ash/test/ash_test_views_delegate.h" #include "ash/test/shell_test_api.h" #include "ash/test/test_screenshot_delegate.h" -#include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" -#include "ash/test/test_system_tray_delegate.h" -#include "ash/test/wm_shell_test_api.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string_split.h"
diff --git a/ash/test/ash_test_impl.h b/ash/test/ash_test_impl.h deleted file mode 100644 index f1ba7f7..0000000 --- a/ash/test/ash_test_impl.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_ASH_TEST_IMPL_H_ -#define ASH_TEST_ASH_TEST_IMPL_H_ - -#include <memory> -#include <string> - -#include "ui/display/display_layout.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/public/window_types.h" - -namespace display { -class Display; -} - -namespace gfx { -class Rect; -} - -namespace ash { - -class WindowOwner; -class WmWindow; - -// Provides the real implementation of AshTest, see it for details. -class AshTestImpl { - public: - virtual ~AshTestImpl() {} - - // Factory function for creating AshTestImpl. Implemention that is used - // depends upon build dependencies. - static std::unique_ptr<AshTestImpl> Create(); - - // These functions mirror that of AshTest, see it for details. - virtual void SetUp() = 0; - virtual void TearDown() = 0; - virtual void UpdateDisplay(const std::string& display_spec) = 0; - virtual std::unique_ptr<WindowOwner> CreateTestWindow( - const gfx::Rect& bounds_in_screen, - ui::wm::WindowType type, - int shell_window_id) = 0; - virtual std::unique_ptr<WindowOwner> CreateToplevelTestWindow( - const gfx::Rect& bounds_in_screen, - int shell_window_id) = 0; - virtual display::Display GetSecondaryDisplay() = 0; - virtual bool SetSecondaryDisplayPlacement( - display::DisplayPlacement::Position position, - int offset) = 0; - virtual void ConfigureWidgetInitParamsForDisplay( - WmWindow* window, - views::Widget::InitParams* init_params) = 0; - virtual void AddTransientChild(WmWindow* parent, WmWindow* window) = 0; -}; - -} // namespace ash - -#endif // ASH_TEST_ASH_TEST_IMPL_H_
diff --git a/ash/test/ash_test_impl_aura.cc b/ash/test/ash_test_impl_aura.cc index 4508c531..ec4fa78 100644 --- a/ash/test/ash_test_impl_aura.cc +++ b/ash/test/ash_test_impl_aura.cc
@@ -4,10 +4,10 @@ #include "ash/test/ash_test_impl_aura.h" +#include "ash/common/test/ash_test.h" #include "ash/common/wm_window.h" #include "ash/screen_util.h" #include "ash/shell.h" -#include "ash/test/ash_test.h" #include "ash/test/ash_test_base.h" #include "base/memory/ptr_util.h" #include "ui/aura/test/test_window_delegate.h"
diff --git a/ash/test/ash_test_impl_aura.h b/ash/test/ash_test_impl_aura.h index c723749..54a9c99 100644 --- a/ash/test/ash_test_impl_aura.h +++ b/ash/test/ash_test_impl_aura.h
@@ -5,7 +5,7 @@ #ifndef ASH_MUS_TEST_ASH_TEST_IMPL_AURA_H_ #define ASH_MUS_TEST_ASH_TEST_IMPL_AURA_H_ -#include "ash/test/ash_test_impl.h" +#include "ash/common/test/ash_test_impl.h" namespace ash { namespace test {
diff --git a/ash/test/overflow_bubble_view_test_api.cc b/ash/test/overflow_bubble_view_test_api.cc index aa61675..cabf43a3 100644 --- a/ash/test/overflow_bubble_view_test_api.cc +++ b/ash/test/overflow_bubble_view_test_api.cc
@@ -4,7 +4,7 @@ #include "ash/test/overflow_bubble_view_test_api.h" -#include "ash/shelf/overflow_bubble_view.h" +#include "ash/common/shelf/overflow_bubble_view.h" namespace ash { namespace test {
diff --git a/ash/test/shelf_button_pressed_metric_tracker_test_api.h b/ash/test/shelf_button_pressed_metric_tracker_test_api.h index 874365b..24ac55bb 100644 --- a/ash/test/shelf_button_pressed_metric_tracker_test_api.h +++ b/ash/test/shelf_button_pressed_metric_tracker_test_api.h
@@ -5,7 +5,7 @@ #ifndef ASH_TEST_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_ #define ASH_TEST_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_ -#include "ash/shelf/shelf_button_pressed_metric_tracker.h" +#include "ash/common/shelf/shelf_button_pressed_metric_tracker.h" #include <memory>
diff --git a/ash/test/shelf_view_test_api.cc b/ash/test/shelf_view_test_api.cc index 9bf2d8c7..6231c154 100644 --- a/ash/test/shelf_view_test_api.cc +++ b/ash/test/shelf_view_test_api.cc
@@ -4,11 +4,11 @@ #include "ash/test/shelf_view_test_api.h" -#include "ash/shelf/overflow_button.h" -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_view.h" +#include "ash/common/shelf/overflow_button.h" +#include "ash/common/shelf/shelf_button.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_view.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "ui/views/animation/bounds_animator.h"
diff --git a/ash/test/shelf_view_test_api.h b/ash/test/shelf_view_test_api.h index 5fd84b9..be7185b57 100644 --- a/ash/test/shelf_view_test_api.h +++ b/ash/test/shelf_view_test_api.h
@@ -5,7 +5,7 @@ #ifndef ASH_TEST_SHELF_VIEW_TEST_API_H_ #define ASH_TEST_SHELF_VIEW_TEST_API_H_ -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_types.h" #include "base/macros.h" namespace gfx {
diff --git a/ash/test/status_area_widget_test_helper.cc b/ash/test/status_area_widget_test_helper.cc index cb76a06..c630646 100644 --- a/ash/test/status_area_widget_test_helper.cc +++ b/ash/test/status_area_widget_test_helper.cc
@@ -4,11 +4,11 @@ #include "ash/test/status_area_widget_test_helper.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray_delegate.h" namespace ash {
diff --git a/ash/test/test_palette_delegate.cc b/ash/test/test_palette_delegate.cc deleted file mode 100644 index 49881d3..0000000 --- a/ash/test/test_palette_delegate.cc +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/test_palette_delegate.h" - -namespace ash { - -TestPaletteDelegate::TestPaletteDelegate() {} - -TestPaletteDelegate::~TestPaletteDelegate() {} - -std::unique_ptr<PaletteDelegate::EnableListenerSubscription> -TestPaletteDelegate::AddPaletteEnableListener( - const EnableListener& on_state_changed) { - return nullptr; -} - -void TestPaletteDelegate::CreateNote() { - ++create_note_count_; -} - -bool TestPaletteDelegate::HasNoteApp() { - ++has_note_app_count_; - return has_note_app_; -} - -bool TestPaletteDelegate::ShouldAutoOpenPalette() { - return should_auto_open_palette_; -} - -bool TestPaletteDelegate::ShouldShowPalette() { - return should_show_palette_; -} - -void TestPaletteDelegate::TakeScreenshot() { - ++take_screenshot_count_; -} - -void TestPaletteDelegate::TakePartialScreenshot(const base::Closure& done) { - ++take_partial_screenshot_count_; - partial_screenshot_done_ = done; -} - -void TestPaletteDelegate::CancelPartialScreenshot() {} - -} // namespace ash
diff --git a/ash/test/test_palette_delegate.h b/ash/test/test_palette_delegate.h deleted file mode 100644 index e70e09d..0000000 --- a/ash/test/test_palette_delegate.h +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_TEST_PALETTE_DELEGATE_H_ -#define ASH_TEST_TEST_PALETTE_DELEGATE_H_ - -#include "ash/common/palette_delegate.h" -#include "base/macros.h" - -namespace ash { - -// A simple test double for a PaletteDelegate. -class TestPaletteDelegate : public PaletteDelegate { - public: - TestPaletteDelegate(); - ~TestPaletteDelegate() override; - - int create_note_count() const { return create_note_count_; } - - int has_note_app_count() const { return has_note_app_count_; } - - int take_screenshot_count() const { return take_screenshot_count_; } - - int take_partial_screenshot_count() const { - return take_partial_screenshot_count_; - } - - base::Closure partial_screenshot_done() const { - return partial_screenshot_done_; - } - - void set_has_note_app(bool has_note_app) { has_note_app_ = has_note_app; } - - void set_should_auto_open_palette(bool should_auto_open_palette) { - should_auto_open_palette_ = should_auto_open_palette; - } - - void set_should_show_palette(bool should_show_palette) { - should_show_palette_ = should_show_palette; - } - - private: - // PaletteDelegate: - std::unique_ptr<EnableListenerSubscription> AddPaletteEnableListener( - const EnableListener& on_state_changed) override; - void CreateNote() override; - bool HasNoteApp() override; - bool ShouldAutoOpenPalette() override; - bool ShouldShowPalette() override; - void TakeScreenshot() override; - void TakePartialScreenshot(const base::Closure& done) override; - void CancelPartialScreenshot() override; - - int create_note_count_ = 0; - int has_note_app_count_ = 0; - int take_screenshot_count_ = 0; - int take_partial_screenshot_count_ = 0; - base::Closure partial_screenshot_done_; - bool has_note_app_ = false; - bool should_auto_open_palette_ = false; - bool should_show_palette_ = false; - - DISALLOW_COPY_AND_ASSIGN(TestPaletteDelegate); -}; - -} // namespace ash - -#endif // ASH_TEST_TEST_PALETTE_DELEGATE_H_
diff --git a/ash/test/test_session_state_delegate.cc b/ash/test/test_session_state_delegate.cc deleted file mode 100644 index 00834bd..0000000 --- a/ash/test/test_session_state_delegate.cc +++ /dev/null
@@ -1,253 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/test_session_state_delegate.h" - -#include <algorithm> -#include <string> - -#include "ash/common/login_status.h" -#include "ash/common/wm_shell.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string16.h" -#include "base/strings/utf_string_conversions.h" -#include "components/signin/core/account_id/account_id.h" -#include "components/user_manager/user_info.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace ash { -namespace test { - -namespace { - -// Returns the "canonicalized" email from a given |email| address. -std::string GetUserIdFromEmail(const std::string& email) { - std::string user_id = email; - std::transform(user_id.begin(), user_id.end(), user_id.begin(), ::tolower); - return user_id; -} - -// Returns Account ID from a given |email| address. -AccountId GetAccountIdFromEmail(const std::string& email) { - return AccountId::FromUserEmail(GetUserIdFromEmail(email)); -} - -} // namespace - -class MockUserInfo : public user_manager::UserInfo { - public: - explicit MockUserInfo(const std::string& display_email) - : display_email_(display_email), - account_id_(GetAccountIdFromEmail(display_email)) {} - ~MockUserInfo() override {} - - void SetUserImage(const gfx::ImageSkia& user_image) { - user_image_ = user_image; - } - - base::string16 GetDisplayName() const override { - return base::UTF8ToUTF16("Über tray Über tray Über tray Über tray"); - } - - base::string16 GetGivenName() const override { - return base::UTF8ToUTF16("Über Über Über Über"); - } - - std::string GetDisplayEmail() const override { return display_email_; } - - const AccountId& GetAccountId() const override { return account_id_; } - - const gfx::ImageSkia& GetImage() const override { return user_image_; } - - // A test user image. - gfx::ImageSkia user_image_; - - std::string display_email_; - const AccountId account_id_; - - DISALLOW_COPY_AND_ASSIGN(MockUserInfo); -}; - -// A test version of user_manager::UserManager which can be used for testing on -// non-ChromeOS builds. -class TestSessionStateDelegate::TestUserManager { - public: - TestUserManager() : session_started_(false) {} - - void SessionStarted() { session_started_ = true; } - - bool IsSessionStarted() const { return session_started_; } - - private: - // True if SessionStarted() has been called. - bool session_started_; - DISALLOW_COPY_AND_ASSIGN(TestUserManager); -}; - -TestSessionStateDelegate::TestSessionStateDelegate() - : can_lock_screen_(true), - should_lock_screen_automatically_(false), - screen_locked_(false), - user_adding_screen_running_(false), - logged_in_users_(1), - active_user_index_(0), - user_manager_(new TestUserManager()), - session_state_(session_manager::SessionState::LOGIN_PRIMARY) { - // This is intended to be capitalized. - user_list_.push_back(base::MakeUnique<MockUserInfo>("First@tray")); - // This is intended to be capitalized. - user_list_.push_back(base::MakeUnique<MockUserInfo>("Second@tray")); - user_list_.push_back(base::MakeUnique<MockUserInfo>("third@tray")); - user_list_.push_back(base::MakeUnique<MockUserInfo>("someone@tray")); -} - -TestSessionStateDelegate::~TestSessionStateDelegate() {} - -void TestSessionStateDelegate::AddUser(const AccountId& account_id) { - user_list_.push_back( - base::MakeUnique<MockUserInfo>(account_id.GetUserEmail())); -} - -const user_manager::UserInfo* TestSessionStateDelegate::GetActiveUserInfo() - const { - return user_list_[active_user_index_].get(); -} - -int TestSessionStateDelegate::GetMaximumNumberOfLoggedInUsers() const { - return 3; -} - -int TestSessionStateDelegate::NumberOfLoggedInUsers() const { - // TODO(skuhne): Add better test framework to test multiple profiles. - return IsActiveUserSessionStarted() ? logged_in_users_ : 0; -} - -bool TestSessionStateDelegate::IsActiveUserSessionStarted() const { - return user_manager_->IsSessionStarted() && - session_state_ == session_manager::SessionState::ACTIVE; -} - -bool TestSessionStateDelegate::CanLockScreen() const { - return IsActiveUserSessionStarted() && can_lock_screen_; -} - -bool TestSessionStateDelegate::IsScreenLocked() const { - return screen_locked_; -} - -bool TestSessionStateDelegate::ShouldLockScreenAutomatically() const { - return should_lock_screen_automatically_; -} - -void TestSessionStateDelegate::LockScreen() { - if (CanLockScreen()) - screen_locked_ = true; -} - -void TestSessionStateDelegate::UnlockScreen() { - screen_locked_ = false; -} - -bool TestSessionStateDelegate::IsUserSessionBlocked() const { - return !IsActiveUserSessionStarted() || IsScreenLocked() || - user_adding_screen_running_ || - session_state_ != session_manager::SessionState::ACTIVE; -} - -session_manager::SessionState TestSessionStateDelegate::GetSessionState() - const { - return session_state_; -} - -void TestSessionStateDelegate::SetHasActiveUser(bool has_active_user) { - session_state_ = has_active_user - ? session_manager::SessionState::ACTIVE - : session_manager::SessionState::LOGIN_PRIMARY; -} - -void TestSessionStateDelegate::SetActiveUserSessionStarted( - bool active_user_session_started) { - if (active_user_session_started) { - user_manager_->SessionStarted(); - session_state_ = session_manager::SessionState::ACTIVE; - WmShell::Get()->CreateShelfView(); - WmShell::Get()->UpdateAfterLoginStatusChange(LoginStatus::USER); - } else { - session_state_ = session_manager::SessionState::LOGIN_PRIMARY; - user_manager_.reset(new TestUserManager()); - } -} - -// static -void TestSessionStateDelegate::SetCanLockScreen(bool can_lock_screen) { - CHECK(WmShell::HasInstance()); - static_cast<ash::test::TestSessionStateDelegate*>( - WmShell::Get()->GetSessionStateDelegate()) - ->can_lock_screen_ = can_lock_screen; -} - -void TestSessionStateDelegate::SetShouldLockScreenAutomatically( - bool should_lock) { - should_lock_screen_automatically_ = should_lock; -} - -void TestSessionStateDelegate::SetUserAddingScreenRunning( - bool user_adding_screen_running) { - user_adding_screen_running_ = user_adding_screen_running; - if (user_adding_screen_running_) - session_state_ = session_manager::SessionState::LOGIN_SECONDARY; - else - session_state_ = session_manager::SessionState::ACTIVE; -} - -void TestSessionStateDelegate::SetUserImage(const gfx::ImageSkia& user_image) { - user_list_[active_user_index_]->SetUserImage(user_image); -} - -const user_manager::UserInfo* TestSessionStateDelegate::GetUserInfo( - UserIndex index) const { - int max = static_cast<int>(user_list_.size()); - return user_list_[index < max ? index : max - 1].get(); -} - -bool TestSessionStateDelegate::ShouldShowAvatar(WmWindow* window) const { - return !GetActiveUserInfo()->GetImage().isNull(); -} - -gfx::ImageSkia TestSessionStateDelegate::GetAvatarImageForWindow( - WmWindow* window) const { - return gfx::ImageSkia(); -} - -void TestSessionStateDelegate::SwitchActiveUser(const AccountId& account_id) { - // Make sure this is a user id and not an email address. - EXPECT_EQ(account_id.GetUserEmail(), - GetUserIdFromEmail(account_id.GetUserEmail())); - active_user_index_ = 0; - for (auto iter = user_list_.begin(); iter != user_list_.end(); ++iter) { - if ((*iter)->GetAccountId() == account_id) { - active_user_index_ = iter - user_list_.begin(); - return; - } - } - NOTREACHED() << "Unknown user:" << account_id.GetUserEmail(); -} - -void TestSessionStateDelegate::CycleActiveUser(CycleUserDirection direction) { - SwitchActiveUser(AccountId::FromUserEmail("someone@tray")); -} - -bool TestSessionStateDelegate::IsMultiProfileAllowedByPrimaryUserPolicy() - const { - return true; -} - -void TestSessionStateDelegate::AddSessionStateObserver( - SessionStateObserver* observer) {} - -void TestSessionStateDelegate::RemoveSessionStateObserver( - SessionStateObserver* observer) {} - -} // namespace test -} // namespace ash
diff --git a/ash/test/test_session_state_delegate.h b/ash/test/test_session_state_delegate.h deleted file mode 100644 index 35fe677..0000000 --- a/ash/test/test_session_state_delegate.h +++ /dev/null
@@ -1,122 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_TEST_SESSION_STATE_DELEGATE_H_ -#define ASH_TEST_TEST_SESSION_STATE_DELEGATE_H_ - -#include <memory> -#include <vector> - -#include "ash/common/session/session_state_delegate.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "ui/gfx/image/image_skia.h" - -class AccountId; - -namespace ash { -namespace test { - -class MockUserInfo; - -class TestSessionStateDelegate : public SessionStateDelegate { - public: - TestSessionStateDelegate(); - ~TestSessionStateDelegate() override; - - void set_logged_in_users(int users) { logged_in_users_ = users; } - void set_session_state(session_manager::SessionState session_state) { - session_state_ = session_state; - } - void AddUser(const AccountId& account_id); - const user_manager::UserInfo* GetActiveUserInfo() const; - - // SessionStateDelegate: - int GetMaximumNumberOfLoggedInUsers() const override; - int NumberOfLoggedInUsers() const override; - bool IsActiveUserSessionStarted() const override; - bool CanLockScreen() const override; - bool IsScreenLocked() const override; - bool ShouldLockScreenAutomatically() const override; - void LockScreen() override; - void UnlockScreen() override; - bool IsUserSessionBlocked() const override; - session_manager::SessionState GetSessionState() const override; - const user_manager::UserInfo* GetUserInfo( - ash::UserIndex index) const override; - bool ShouldShowAvatar(WmWindow* window) const override; - gfx::ImageSkia GetAvatarImageForWindow(WmWindow* window) const override; - void SwitchActiveUser(const AccountId& account_id) override; - void CycleActiveUser(CycleUserDirection direction) override; - bool IsMultiProfileAllowedByPrimaryUserPolicy() const override; - void AddSessionStateObserver(ash::SessionStateObserver* observer) override; - void RemoveSessionStateObserver(ash::SessionStateObserver* observer) override; - - // TODO(oshima): Use state machine instead of using boolean variables. - - // Updates the internal state that indicates whether a session is in progress - // and there is an active user. If |has_active_user| is |false|, - // |active_user_session_started_| is reset to |false| as well (see below for - // the difference between these two flags). - void SetHasActiveUser(bool has_active_user); - - // Updates the internal state that indicates whether the session has been - // fully started for the active user. If |active_user_session_started| is - // |true|, |has_active_user_| is set to |true| as well (see below for the - // difference between these two flags). - void SetActiveUserSessionStarted(bool active_user_session_started); - - // Updates the internal state that indicates whether the screen can be locked. - // Locking will only actually be allowed when this value is |true| and there - // is an active user. - static void SetCanLockScreen(bool can_lock_screen); - - // Updates |should_lock_screen_automatically_|. - void SetShouldLockScreenAutomatically(bool should_lock); - - // Updates the internal state that indicates whether user adding screen is - // running now. - void SetUserAddingScreenRunning(bool user_adding_screen_running); - - // Setting non NULL image enables avatar icon. - void SetUserImage(const gfx::ImageSkia& user_image); - - private: - class TestUserManager; - - // Whether the screen can be locked. Locking will only actually be allowed - // when this is |true| and there is an active user. - bool can_lock_screen_; - - // Return value for ShouldLockScreenAutomatically(). - bool should_lock_screen_automatically_; - - // Whether the screen is currently locked. - bool screen_locked_; - - // Whether user addding screen is running now. - bool user_adding_screen_running_; - - // The number of users logged in. - int logged_in_users_; - - // The index for the activated user. - int active_user_index_; - - std::vector<std::unique_ptr<MockUserInfo>> user_list_; - - // The user manager to be used instead of the system instance. - std::unique_ptr<TestUserManager> user_manager_; - - // The current state of the login screen. |session_state_| becomes active - // before the profile and browser UI are available. - session_manager::SessionState session_state_; - - DISALLOW_COPY_AND_ASSIGN(TestSessionStateDelegate); -}; - -} // namespace test -} // namespace ash - -#endif // ASH_TEST_TEST_SESSION_STATE_DELEGATE_H_
diff --git a/ash/test/test_shelf_delegate.cc b/ash/test/test_shelf_delegate.cc deleted file mode 100644 index 1fbdd16e..0000000 --- a/ash/test/test_shelf_delegate.cc +++ /dev/null
@@ -1,162 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/test_shelf_delegate.h" - -#include <utility> - -#include "ash/common/shell_observer.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/test/test_shelf_item_delegate.h" -#include "ash/wm/window_properties.h" -#include "base/memory/ptr_util.h" -#include "ui/aura/window.h" - -namespace ash { -namespace test { - -TestShelfDelegate* TestShelfDelegate::instance_ = nullptr; - -// A ShellObserver that sets the shelf alignment and auto hide behavior when the -// shelf is created, to simulate ChromeLauncherController's behavior. -class ShelfInitializer : public ShellObserver { - public: - ShelfInitializer() { WmShell::Get()->AddShellObserver(this); } - ~ShelfInitializer() override { WmShell::Get()->RemoveShellObserver(this); } - - // ShellObserver: - void OnShelfCreatedForRootWindow(WmWindow* root_window) override { - WmShelf* shelf = root_window->GetRootWindowController()->GetShelf(); - // Do not override the custom initialization performed by some unit tests. - if (shelf->alignment() == SHELF_ALIGNMENT_BOTTOM_LOCKED && - shelf->auto_hide_behavior() == SHELF_AUTO_HIDE_ALWAYS_HIDDEN) { - shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM); - shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); - shelf->UpdateVisibilityState(); - } - } - - private: - DISALLOW_COPY_AND_ASSIGN(ShelfInitializer); -}; - -TestShelfDelegate::TestShelfDelegate() - : shelf_initializer_(base::MakeUnique<ShelfInitializer>()) { - CHECK(!instance_); - instance_ = this; -} - -TestShelfDelegate::~TestShelfDelegate() { - instance_ = nullptr; -} - -void TestShelfDelegate::AddShelfItem(WmWindow* window) { - AddShelfItem(window, STATUS_CLOSED); -} - -void TestShelfDelegate::AddShelfItem(WmWindow* window, - const std::string& app_id) { - AddShelfItem(window, STATUS_CLOSED); - ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey); - AddShelfIDToAppIDMapping(shelf_id, app_id); -} - -void TestShelfDelegate::AddShelfItem(WmWindow* window, ShelfItemStatus status) { - ShelfItem item; - if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL) - item.type = TYPE_APP_PANEL; - else - item.type = TYPE_APP; - ShelfModel* model = WmShell::Get()->shelf_model(); - ShelfID id = model->next_id(); - item.status = status; - model->Add(item); - window->aura_window()->AddObserver(this); - - model->SetShelfItemDelegate(id, - base::MakeUnique<TestShelfItemDelegate>(window)); - window->aura_window()->SetProperty(kShelfIDKey, id); -} - -void TestShelfDelegate::RemoveShelfItemForWindow(WmWindow* window) { - ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey); - if (shelf_id == 0) - return; - ShelfModel* model = WmShell::Get()->shelf_model(); - int index = model->ItemIndexByID(shelf_id); - DCHECK_NE(-1, index); - model->RemoveItemAt(index); - window->aura_window()->RemoveObserver(this); - if (HasShelfIDToAppIDMapping(shelf_id)) { - const std::string& app_id = GetAppIDForShelfID(shelf_id); - if (IsAppPinned(app_id)) - UnpinAppWithID(app_id); - if (HasShelfIDToAppIDMapping(shelf_id)) - RemoveShelfIDToAppIDMapping(shelf_id); - } -} - -void TestShelfDelegate::OnWindowDestroying(aura::Window* window) { - RemoveShelfItemForWindow(WmWindow::Get(window)); -} - -void TestShelfDelegate::OnWindowHierarchyChanging( - const HierarchyChangeParams& params) { - // The window may be legitimately reparented while staying open if it moves - // to another display or container. If the window does not have a new parent - // then remove the shelf item. - if (!params.new_parent) - RemoveShelfItemForWindow(WmWindow::Get(params.target)); -} - -ShelfID TestShelfDelegate::GetShelfIDForAppID(const std::string& app_id) { - for (auto const& iter : shelf_id_to_app_id_map_) { - if (iter.second == app_id) - return iter.first; - } - return 0; -} - -ShelfID TestShelfDelegate::GetShelfIDForAppIDAndLaunchID( - const std::string& app_id, - const std::string& launch_id) { - return GetShelfIDForAppID(app_id); -} - -bool TestShelfDelegate::HasShelfIDToAppIDMapping(ShelfID id) const { - return shelf_id_to_app_id_map_.find(id) != shelf_id_to_app_id_map_.end(); -} - -const std::string& TestShelfDelegate::GetAppIDForShelfID(ShelfID id) { - DCHECK_GT(shelf_id_to_app_id_map_.count(id), 0u); - return shelf_id_to_app_id_map_[id]; -} - -void TestShelfDelegate::PinAppWithID(const std::string& app_id) { - pinned_apps_.insert(app_id); -} - -bool TestShelfDelegate::IsAppPinned(const std::string& app_id) { - return pinned_apps_.find(app_id) != pinned_apps_.end(); -} - -void TestShelfDelegate::UnpinAppWithID(const std::string& app_id) { - pinned_apps_.erase(app_id); -} - -void TestShelfDelegate::AddShelfIDToAppIDMapping(ShelfID shelf_id, - const std::string& app_id) { - shelf_id_to_app_id_map_[shelf_id] = app_id; -} - -void TestShelfDelegate::RemoveShelfIDToAppIDMapping(ShelfID shelf_id) { - shelf_id_to_app_id_map_.erase(shelf_id); -} - -} // namespace test -} // namespace ash
diff --git a/ash/test/test_shelf_delegate.h b/ash/test/test_shelf_delegate.h deleted file mode 100644 index d9e14ca..0000000 --- a/ash/test/test_shelf_delegate.h +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_TEST_SHELF_DELEGATE_H_ -#define ASH_TEST_TEST_SHELF_DELEGATE_H_ - -#include <map> -#include <set> -#include <string> - -#include "ash/shelf/shelf_delegate.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" - -namespace ash { - -class WmWindow; - -namespace test { - -class ShelfInitializer; - -// Test implementation of ShelfDelegate. -// Tests may create icons for windows by calling AddShelfItem(). -class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver { - public: - TestShelfDelegate(); - ~TestShelfDelegate() override; - - // Adds a ShelfItem for the given |window|. The ShelfItem's status will be - // STATUS_CLOSED. - void AddShelfItem(WmWindow* window); - - // Adds a ShelfItem for the given |window| and adds a mapping from the added - // ShelfItem's ShelfID to the given |app_id|. The ShelfItem's status will be - // STATUS_CLOSED. - void AddShelfItem(WmWindow* window, const std::string& app_id); - - // Adds a ShelfItem for the given |window| with the specified |status|. - void AddShelfItem(WmWindow* window, ShelfItemStatus status); - - // Removes the ShelfItem for the specified |window| and unpins it if it was - // pinned. The |window|'s ShelfID to app id mapping will be removed if it - // exists. - void RemoveShelfItemForWindow(WmWindow* window); - - static TestShelfDelegate* instance() { return instance_; } - - // WindowObserver implementation - void OnWindowDestroying(aura::Window* window) override; - void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override; - - // ShelfDelegate implementation. - ShelfID GetShelfIDForAppID(const std::string& app_id) override; - ShelfID GetShelfIDForAppIDAndLaunchID(const std::string& app_id, - const std::string& launch_id) override; - bool HasShelfIDToAppIDMapping(ShelfID id) const override; - const std::string& GetAppIDForShelfID(ShelfID id) override; - void PinAppWithID(const std::string& app_id) override; - bool IsAppPinned(const std::string& app_id) override; - void UnpinAppWithID(const std::string& app_id) override; - - private: - // Adds a mapping from a ShelfID to an app id. - void AddShelfIDToAppIDMapping(ShelfID shelf_id, const std::string& app_id); - - // Removes the mapping from a ShelfID to an app id. - void RemoveShelfIDToAppIDMapping(ShelfID shelf_id); - - static TestShelfDelegate* instance_; - - std::unique_ptr<ShelfInitializer> shelf_initializer_; - - std::set<std::string> pinned_apps_; - - // Tracks the ShelfID to app id mappings. - std::map<ShelfID, std::string> shelf_id_to_app_id_map_; - - DISALLOW_COPY_AND_ASSIGN(TestShelfDelegate); -}; - -} // namespace test -} // namespace ash - -#endif // ASH_TEST_TEST_SHELF_DELEGATE_H_
diff --git a/ash/test/test_shelf_item_delegate.cc b/ash/test/test_shelf_item_delegate.cc deleted file mode 100644 index d70d384..0000000 --- a/ash/test/test_shelf_item_delegate.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/test_shelf_item_delegate.h" - -#include "ash/common/wm_window.h" -#include "ash/wm/window_util.h" - -namespace ash { -namespace test { - -TestShelfItemDelegate::TestShelfItemDelegate(WmWindow* window) - : window_(window) {} - -TestShelfItemDelegate::~TestShelfItemDelegate() {} - -ShelfAction TestShelfItemDelegate::ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) { - if (window_) { - if (window_->GetType() == ui::wm::WINDOW_TYPE_PANEL) - wm::MoveWindowToDisplay(window_->aura_window(), display_id); - window_->Show(); - window_->Activate(); - return SHELF_ACTION_WINDOW_ACTIVATED; - } - return SHELF_ACTION_NONE; -} - -ShelfAppMenuItemList TestShelfItemDelegate::GetAppMenuItems(int event_flags) { - // Return an empty item list to avoid showing an application menu. - return ShelfAppMenuItemList(); -} - -void TestShelfItemDelegate::ExecuteCommand(uint32_t command_id, - int event_flags) { - // This delegate does not support showing an application menu. - NOTIMPLEMENTED(); -} - -void TestShelfItemDelegate::Close() {} - -} // namespace test -} // namespace ash
diff --git a/ash/test/test_shelf_item_delegate.h b/ash/test/test_shelf_item_delegate.h deleted file mode 100644 index 24360e4..0000000 --- a/ash/test/test_shelf_item_delegate.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_TEST_SHELF_ITEM_DELEGATE_H_ -#define ASH_TEST_TEST_SHELF_ITEM_DELEGATE_H_ - -#include "ash/shelf/shelf_item_delegate.h" -#include "base/macros.h" - -namespace ash { - -class WmWindow; - -namespace test { - -// Test implementation of ShelfItemDelegate. -class TestShelfItemDelegate : public ShelfItemDelegate { - public: - explicit TestShelfItemDelegate(WmWindow* window); - ~TestShelfItemDelegate() override; - - // ShelfItemDelegate: - ShelfAction ItemSelected(ui::EventType event_type, - int event_flags, - int64_t display_id, - ShelfLaunchSource source) override; - ShelfAppMenuItemList GetAppMenuItems(int event_flags) override; - void ExecuteCommand(uint32_t command_id, int event_flags) override; - void Close() override; - - private: - WmWindow* window_; - - DISALLOW_COPY_AND_ASSIGN(TestShelfItemDelegate); -}; - -} // namespace test -} // namespace ash - -#endif // ASH_TEST_TEST_SHELF_ITEM_DELEGATE_H_
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc index d1e753f..d18c022d 100644 --- a/ash/test/test_shell_delegate.cc +++ b/ash/test/test_shell_delegate.cc
@@ -10,15 +10,15 @@ #include "ash/common/gpu_support_stub.h" #include "ash/common/palette_delegate.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/system/tray/system_tray_notifier.h" #include "ash/test/test_keyboard_ui.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/test/test_system_tray_delegate.h" #include "ash/test/test_wallpaper_delegate.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "base/logging.h" #include "base/memory/ptr_util.h"
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h index 5d8bea3..fe30c3c 100644 --- a/ash/test/test_shell_delegate.h +++ b/ash/test/test_shell_delegate.h
@@ -9,7 +9,7 @@ #include <string> #include "ash/common/shell_delegate.h" -#include "ash/test/test_session_state_delegate.h" +#include "ash/common/test/test_session_state_delegate.h" #include "base/macros.h" namespace keyboard {
diff --git a/ash/test/test_system_tray_delegate.cc b/ash/test/test_system_tray_delegate.cc deleted file mode 100644 index 524058b0e..0000000 --- a/ash/test/test_system_tray_delegate.cc +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/test_system_tray_delegate.h" - -#include <string> - -#include "ash/common/login_status.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "base/time/time.h" - -namespace ash { -namespace test { - -namespace { - -LoginStatus g_initial_status = LoginStatus::USER; - -} // namespace - -TestSystemTrayDelegate::TestSystemTrayDelegate() - : login_status_(g_initial_status), session_length_limit_set_(false) {} - -TestSystemTrayDelegate::~TestSystemTrayDelegate() {} - -void TestSystemTrayDelegate::SetLoginStatus(LoginStatus login_status) { - login_status_ = login_status; - WmShell::Get()->UpdateAfterLoginStatusChange(login_status); -} - -void TestSystemTrayDelegate::SetSessionLengthLimitForTest( - const base::TimeDelta& new_limit) { - session_length_limit_ = new_limit; - session_length_limit_set_ = true; -} - -void TestSystemTrayDelegate::ClearSessionLengthLimit() { - session_length_limit_set_ = false; -} - -void TestSystemTrayDelegate::SetCurrentIME(const IMEInfo& info) { - current_ime_ = info; -} - -void TestSystemTrayDelegate::SetAvailableIMEList(const IMEInfoList& list) { - ime_list_ = list; -} - -LoginStatus TestSystemTrayDelegate::GetUserLoginStatus() const { - // Initial login status has been changed for testing. - if (g_initial_status != LoginStatus::USER && - g_initial_status == login_status_) { - return login_status_; - } - - // At new user image screen manager->IsUserLoggedIn() would return true - // but there's no browser session available yet so use SessionStarted(). - SessionStateDelegate* delegate = WmShell::Get()->GetSessionStateDelegate(); - - if (!delegate->IsActiveUserSessionStarted()) - return LoginStatus::NOT_LOGGED_IN; - if (delegate->IsScreenLocked()) - return LoginStatus::LOCKED; - return login_status_; -} - -bool TestSystemTrayDelegate::IsUserSupervised() const { - return login_status_ == LoginStatus::SUPERVISED; -} - -bool TestSystemTrayDelegate::GetSessionStartTime( - base::TimeTicks* session_start_time) { - // Just returns TimeTicks::Now(), so the remaining time is always the - // specified limit. This is useful for testing. - if (session_length_limit_set_) - *session_start_time = base::TimeTicks::Now(); - return session_length_limit_set_; -} - -bool TestSystemTrayDelegate::GetSessionLengthLimit( - base::TimeDelta* session_length_limit) { - if (session_length_limit_set_) - *session_length_limit = session_length_limit_; - return session_length_limit_set_; -} - -void TestSystemTrayDelegate::GetCurrentIME(IMEInfo* info) { - *info = current_ime_; -} - -void TestSystemTrayDelegate::GetAvailableIMEList(IMEInfoList* list) { - *list = ime_list_; -} - -//////////////////////////////////////////////////////////////////////////////// - -ScopedInitialLoginStatus::ScopedInitialLoginStatus(LoginStatus new_status) - : old_status_(g_initial_status) { - g_initial_status = new_status; -} - -ScopedInitialLoginStatus::~ScopedInitialLoginStatus() { - g_initial_status = old_status_; -} - -} // namespace test -} // namespace ash
diff --git a/ash/test/test_system_tray_delegate.h b/ash/test/test_system_tray_delegate.h deleted file mode 100644 index 8dc944f..0000000 --- a/ash/test/test_system_tray_delegate.h +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_ -#define ASH_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_ - -#include "ash/system/tray/default_system_tray_delegate.h" -#include "ash/system/tray/ime_info.h" -#include "base/macros.h" -#include "base/time/time.h" - -namespace ash { -namespace test { - -class TestSystemTrayDelegate : public DefaultSystemTrayDelegate { - public: - TestSystemTrayDelegate(); - ~TestSystemTrayDelegate() override; - - // Changes the current login status in the test. This also invokes - // UpdateAfterLoginStatusChange(). Usually this is called in the test code to - // set up a login status. This will fit to most of the test cases, but this - // cannot be set during the initialization. To test the initialization, - // consider using SetInitialLoginStatus() instead. - void SetLoginStatus(LoginStatus login_status); - - // Updates the session length limit so that the limit will come from now in - // |new_limit|. - void SetSessionLengthLimitForTest(const base::TimeDelta& new_limit); - - // Clears the session length limit. - void ClearSessionLengthLimit(); - - // Sets the IME info. - void SetCurrentIME(const IMEInfo& info); - - // Sets the list of available IMEs. - void SetAvailableIMEList(const IMEInfoList& list); - - // Overridden from SystemTrayDelegate: - LoginStatus GetUserLoginStatus() const override; - bool IsUserSupervised() const override; - bool GetSessionStartTime(base::TimeTicks* session_start_time) override; - bool GetSessionLengthLimit(base::TimeDelta* session_length_limit) override; - void GetCurrentIME(IMEInfo* info) override; - void GetAvailableIMEList(IMEInfoList* list) override; - - private: - LoginStatus login_status_; - base::TimeDelta session_length_limit_; - bool session_length_limit_set_; - IMEInfo current_ime_; - IMEInfoList ime_list_; - - DISALLOW_COPY_AND_ASSIGN(TestSystemTrayDelegate); -}; - -// Changes the initial login status before TestSystemTrayDelegate is created. -// Allows testing the case when chrome is restarted right after login (such as -// when a flag is set). -class ScopedInitialLoginStatus { - public: - explicit ScopedInitialLoginStatus(LoginStatus status); - ~ScopedInitialLoginStatus(); - - private: - LoginStatus old_status_; - - DISALLOW_COPY_AND_ASSIGN(ScopedInitialLoginStatus); -}; - -} // namespace test -} // namespace ash - -#endif // ASH_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_
diff --git a/ash/test/test_system_tray_item.h b/ash/test/test_system_tray_item.h index 9ddaeb4..5ef1f58 100644 --- a/ash/test/test_system_tray_item.h +++ b/ash/test/test_system_tray_item.h
@@ -5,7 +5,7 @@ #ifndef ASH_COMMON_SYSTEM_TRAY_TEST_TEST_SYSTEM_TRAY_ITEM_H_ #define ASH_COMMON_SYSTEM_TRAY_TEST_TEST_SYSTEM_TRAY_ITEM_H_ -#include "ash/system/tray/system_tray_item.h" +#include "ash/common/system/tray/system_tray_item.h" namespace ash { namespace test {
diff --git a/ash/test/tray_cast_test_api.cc b/ash/test/tray_cast_test_api.cc index af9146c8..a105bf3 100644 --- a/ash/test/tray_cast_test_api.cc +++ b/ash/test/tray_cast_test_api.cc
@@ -4,9 +4,9 @@ #include "ash/test/tray_cast_test_api.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ui/views/view.h" namespace ash {
diff --git a/ash/test/tray_cast_test_api.h b/ash/test/tray_cast_test_api.h index 7726f017..24fc207 100644 --- a/ash/test/tray_cast_test_api.h +++ b/ash/test/tray_cast_test_api.h
@@ -8,7 +8,7 @@ #include <string> #include "ash/ash_export.h" -#include "ash/system/cast/tray_cast.h" +#include "ash/common/system/chromeos/cast/tray_cast.h" #include "base/macros.h" namespace ash {
diff --git a/ash/test/ui_controls_factory_ash.cc b/ash/test/ui_controls_factory_ash.cc index 090059ec..d0606357 100644 --- a/ash/test/ui_controls_factory_ash.cc +++ b/ash/test/ui_controls_factory_ash.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" #include "ash/shell.h" -#include "ash/wm/root_window_finder.h" #include "ash/wm/window_properties.h" #include "ui/aura/client/capture_client.h" #include "ui/aura/client/screen_position_client.h"
diff --git a/ash/test/wm_shell_test_api.cc b/ash/test/wm_shell_test_api.cc deleted file mode 100644 index 35f4b1e..0000000 --- a/ash/test/wm_shell_test_api.cc +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/wm_shell_test_api.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/public/interfaces/new_window.mojom.h" -#include "ash/system/tray/system_tray_delegate.h" - -namespace ash { - -WmShellTestApi::WmShellTestApi() {} - -WmShellTestApi::~WmShellTestApi() {} - -void WmShellTestApi::SetSystemTrayDelegate( - std::unique_ptr<SystemTrayDelegate> delegate) { - WmShell::Get()->SetSystemTrayDelegate(std::move(delegate)); -} - -} // namespace ash
diff --git a/ash/test/wm_shell_test_api.h b/ash/test/wm_shell_test_api.h deleted file mode 100644 index d4be5cf..0000000 --- a/ash/test/wm_shell_test_api.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_WM_SHELL_TEST_API_H_ -#define ASH_TEST_WM_SHELL_TEST_API_H_ - -#include <memory> - -#include "base/macros.h" - -namespace ash { - -class SystemTrayDelegate; - -// Test API to access the internal state of the singleton WmShell. -class WmShellTestApi { - public: - WmShellTestApi(); - ~WmShellTestApi(); - - void SetSystemTrayDelegate(std::unique_ptr<SystemTrayDelegate> delegate); - - private: - DISALLOW_COPY_AND_ASSIGN(WmShellTestApi); -}; - -} // namespace ash - -#endif // ASH_TEST_WM_SHELL_TEST_API_H_
diff --git a/ash/test/workspace_event_handler_test_helper.cc b/ash/test/workspace_event_handler_test_helper.cc deleted file mode 100644 index fe7b1d9..0000000 --- a/ash/test/workspace_event_handler_test_helper.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/test/workspace_event_handler_test_helper.h" - -namespace ash { - -WorkspaceEventHandlerTestHelper::WorkspaceEventHandlerTestHelper( - WorkspaceEventHandler* handler) - : handler_(handler) {} - -WorkspaceEventHandlerTestHelper::~WorkspaceEventHandlerTestHelper() {} - -} // namespace ash
diff --git a/ash/test/workspace_event_handler_test_helper.h b/ash/test/workspace_event_handler_test_helper.h deleted file mode 100644 index 0360328..0000000 --- a/ash/test/workspace_event_handler_test_helper.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_ -#define ASH_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_ - -#include "ash/wm/workspace/workspace_event_handler.h" - -#include "base/macros.h" - -namespace ash { - -class WorkspaceEventHandlerTestHelper { - public: - explicit WorkspaceEventHandlerTestHelper(WorkspaceEventHandler* handler); - ~WorkspaceEventHandlerTestHelper(); - - MultiWindowResizeController* resize_controller() { - return &(handler_->multi_window_resize_controller_); - } - - private: - WorkspaceEventHandler* handler_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceEventHandlerTestHelper); -}; - -} // namespace ash - -#endif // ASH_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
diff --git a/ash/touch/touch_uma.h b/ash/touch/touch_uma.h index 805f059..480cb3de 100644 --- a/ash/touch/touch_uma.h +++ b/ash/touch/touch_uma.h
@@ -6,7 +6,7 @@ #define ASH_TOUCH_TOUCH_OBSERVER_UMA_H_ #include "ash/ash_export.h" -#include "ash/metrics/gesture_action_type.h" +#include "ash/common/metrics/gesture_action_type.h" #include "base/macros.h" #include "base/memory/singleton.h"
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc index d19ad09..b483df6e5 100644 --- a/ash/virtual_keyboard_controller.cc +++ b/ash/virtual_keyboard_controller.cc
@@ -7,12 +7,12 @@ #include <vector> #include "ash/common/keyboard/keyboard_ui.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/command_line.h" #include "base/strings/string_util.h" #include "ui/display/display.h"
diff --git a/ash/virtual_keyboard_controller_unittest.cc b/ash/virtual_keyboard_controller_unittest.cc index 7cf0a9fe..facd574 100644 --- a/ash/virtual_keyboard_controller_unittest.cc +++ b/ash/virtual_keyboard_controller_unittest.cc
@@ -7,13 +7,13 @@ #include <utility> #include <vector> +#include "ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/virtual_keyboard/virtual_keyboard_observer.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" #include "base/command_line.h" #include "ui/events/devices/device_data_manager.h" #include "ui/events/devices/device_hotplug_event_observer.h"
diff --git a/ash/wm/always_on_top_controller.cc b/ash/wm/always_on_top_controller.cc deleted file mode 100644 index 90ee7a1..0000000 --- a/ash/wm/always_on_top_controller.cc +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/always_on_top_controller.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/workspace/workspace_layout_manager.h" -#include "base/memory/ptr_util.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/window.h" - -namespace ash { - -AlwaysOnTopController::AlwaysOnTopController(WmWindow* viewport) - : always_on_top_container_(viewport) { - DCHECK_NE(kShellWindowId_DefaultContainer, viewport->GetShellWindowId()); - always_on_top_container_->SetLayoutManager( - base::MakeUnique<WorkspaceLayoutManager>(viewport)); - // Container should be empty. - DCHECK(always_on_top_container_->GetChildren().empty()); - always_on_top_container_->aura_window()->AddObserver(this); -} - -AlwaysOnTopController::~AlwaysOnTopController() { - if (always_on_top_container_) - always_on_top_container_->aura_window()->RemoveObserver(this); -} - -WmWindow* AlwaysOnTopController::GetContainer(WmWindow* window) const { - DCHECK(always_on_top_container_); - if (window->aura_window()->GetProperty(aura::client::kAlwaysOnTopKey)) - return always_on_top_container_; - return always_on_top_container_->GetRootWindow()->GetChildByShellWindowId( - kShellWindowId_DefaultContainer); -} - -// TODO(rsadam@): Refactor so that this cast is unneeded. -WorkspaceLayoutManager* AlwaysOnTopController::GetLayoutManager() const { - return static_cast<WorkspaceLayoutManager*>( - always_on_top_container_->GetLayoutManager()); -} - -void AlwaysOnTopController::SetLayoutManagerForTest( - std::unique_ptr<WorkspaceLayoutManager> layout_manager) { - always_on_top_container_->SetLayoutManager(std::move(layout_manager)); -} - -void AlwaysOnTopController::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - if (WmWindow::Get(params.old_parent) == always_on_top_container_) - params.target->RemoveObserver(this); - else if (WmWindow::Get(params.new_parent) == always_on_top_container_) - params.target->AddObserver(this); -} - -void AlwaysOnTopController::OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) { - if (WmWindow::Get(window) != always_on_top_container_ && - key == aura::client::kAlwaysOnTopKey) { - DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL || - window->type() == ui::wm::WINDOW_TYPE_POPUP); - WmWindow* container = GetContainer(WmWindow::Get(window)); - if (WmWindow::Get(window->parent()) != container) - container->AddChild(WmWindow::Get(window)); - } -} - -void AlwaysOnTopController::OnWindowDestroying(aura::Window* window) { - if (WmWindow::Get(window) == always_on_top_container_) { - always_on_top_container_->aura_window()->RemoveObserver(this); - always_on_top_container_ = nullptr; - } -} - -} // namespace ash
diff --git a/ash/wm/always_on_top_controller.h b/ash/wm/always_on_top_controller.h deleted file mode 100644 index 4f33eeee..0000000 --- a/ash/wm/always_on_top_controller.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_ALWAYS_ON_TOP_CONTROLLER_H_ -#define ASH_WM_ALWAYS_ON_TOP_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" - -namespace ash { - -class WmWindow; -class WorkspaceLayoutManager; - -// AlwaysOnTopController puts window into proper containers based on its -// 'AlwaysOnTop' property. That is, putting a window into the worskpace -// container if its "AlwaysOnTop" property is false. Otherwise, put it in -// |always_on_top_container_|. -class ASH_EXPORT AlwaysOnTopController : public aura::WindowObserver { - public: - explicit AlwaysOnTopController(WmWindow* viewport); - ~AlwaysOnTopController() override; - - // Gets container for given |window| based on its "AlwaysOnTop" property. - WmWindow* GetContainer(WmWindow* window) const; - - WorkspaceLayoutManager* GetLayoutManager() const; - - void SetLayoutManagerForTest( - std::unique_ptr<WorkspaceLayoutManager> layout_manager); - - private: - // Overridden from aura::WindowObserver: - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; - void OnWindowDestroying(aura::Window* window) override; - - WmWindow* always_on_top_container_; - - DISALLOW_COPY_AND_ASSIGN(AlwaysOnTopController); -}; - -} // namepsace ash - -#endif // ASH_WM_ALWAYS_ON_TOP_CONTROLLER_H_
diff --git a/ash/wm/always_on_top_controller_unittest.cc b/ash/wm/always_on_top_controller_unittest.cc index 70131d69..54dad32 100644 --- a/ash/wm/always_on_top_controller_unittest.cc +++ b/ash/wm/always_on_top_controller_unittest.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/always_on_top_controller.h" +#include "ash/common/wm/always_on_top_controller.h" +#include "ash/common/wm/workspace/workspace_layout_manager.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/workspace/workspace_layout_manager.h" #include "base/command_line.h" #include "base/memory/ptr_util.h" #include "ui/keyboard/keyboard_controller.h"
diff --git a/ash/wm/ash_focus_rules.cc b/ash/wm/ash_focus_rules.cc index 2d4616a..26adb0b8 100644 --- a/ash/wm/ash_focus_rules.cc +++ b/ash/wm/ash_focus_rules.cc
@@ -4,14 +4,14 @@ #include "ash/wm/ash_focus_rules.h" +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/focus_rules.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/container_finder.h" -#include "ash/wm/focus_rules.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/window.h"
diff --git a/ash/wm/ash_focus_rules_unittest.cc b/ash/wm/ash_focus_rules_unittest.cc index 2ea7da9..faabf2d7 100644 --- a/ash/wm/ash_focus_rules_unittest.cc +++ b/ash/wm/ash_focus_rules_unittest.cc
@@ -3,15 +3,15 @@ // found in the LICENSE file. #include "ash/common/session/session_state_delegate.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" -#include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
diff --git a/ash/wm/container_finder.cc b/ash/wm/container_finder.cc deleted file mode 100644 index 0efd32d..0000000 --- a/ash/wm/container_finder.cc +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/container_finder.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/root_window_controller.h" -#include "ash/wm/always_on_top_controller.h" -#include "ash/wm/root_window_finder.h" -#include "ash/wm/window_state.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { -namespace wm { -namespace { - -WmWindow* FindContainerRoot(WmShell* shell, const gfx::Rect& bounds) { - if (bounds == gfx::Rect()) - return shell->GetRootWindowForNewWindows(); - return GetRootWindowMatching(bounds); -} - -bool HasTransientParentWindow(const WmWindow* window) { - return window->GetTransientParent() && - window->GetTransientParent()->GetType() != ui::wm::WINDOW_TYPE_UNKNOWN; -} - -WmWindow* GetSystemModalContainer(WmWindow* root, WmWindow* window) { - DCHECK(window->IsSystemModal()); - - // If screen lock is not active and user session is active, - // all modal windows are placed into the normal modal container. - // In case of missing transient parent (it could happen for alerts from - // background pages) assume that the window belongs to user session. - if (!window->GetShell()->GetSessionStateDelegate()->IsUserSessionBlocked() || - !window->GetTransientParent()) { - return root->GetChildByShellWindowId(kShellWindowId_SystemModalContainer); - } - - // Otherwise those that originate from LockScreen container and above are - // placed in the screen lock modal container. - int window_container_id = - window->GetTransientParent()->GetParent()->GetShellWindowId(); - if (window_container_id < kShellWindowId_LockScreenContainer) - return root->GetChildByShellWindowId(kShellWindowId_SystemModalContainer); - return root->GetChildByShellWindowId(kShellWindowId_LockSystemModalContainer); -} - -WmWindow* GetContainerFromAlwaysOnTopController(WmWindow* root, - WmWindow* window) { - return root->GetRootWindowController() - ->always_on_top_controller() - ->GetContainer(window); -} - -} // namespace - -WmWindow* GetContainerForWindow(WmWindow* window) { - WmWindow* parent = window->GetParent(); - // The first parent with an explicit shell window ID is the container. - while (parent && parent->GetShellWindowId() == kShellWindowId_Invalid) - parent = parent->GetParent(); - return parent; -} - -WmWindow* GetDefaultParent(WmWindow* context, - WmWindow* window, - const gfx::Rect& bounds) { - WmWindow* target_root = nullptr; - WmWindow* transient_parent = window->GetTransientParent(); - if (transient_parent) { - // Transient window should use the same root as its transient parent. - target_root = transient_parent->GetRootWindow(); - } else { - target_root = FindContainerRoot(context->GetShell(), bounds); - } - - switch (window->GetType()) { - case ui::wm::WINDOW_TYPE_NORMAL: - case ui::wm::WINDOW_TYPE_POPUP: - if (window->IsSystemModal()) - return GetSystemModalContainer(target_root, window); - if (HasTransientParentWindow(window)) - return GetContainerForWindow(window->GetTransientParent()); - return GetContainerFromAlwaysOnTopController(target_root, window); - case ui::wm::WINDOW_TYPE_CONTROL: - return target_root->GetChildByShellWindowId( - kShellWindowId_UnparentedControlContainer); - case ui::wm::WINDOW_TYPE_PANEL: - if (window->aura_window()->GetProperty(kPanelAttachedKey)) - return target_root->GetChildByShellWindowId( - kShellWindowId_PanelContainer); - return GetContainerFromAlwaysOnTopController(target_root, window); - case ui::wm::WINDOW_TYPE_MENU: - return target_root->GetChildByShellWindowId(kShellWindowId_MenuContainer); - case ui::wm::WINDOW_TYPE_TOOLTIP: - return target_root->GetChildByShellWindowId( - kShellWindowId_DragImageAndTooltipContainer); - default: - NOTREACHED() << "Window " << window->GetShellWindowId() - << " has unhandled type " << window->GetType(); - break; - } - return nullptr; -} - -std::vector<WmWindow*> GetContainersFromAllRootWindows( - int container_id, - WmWindow* priority_root) { - std::vector<WmWindow*> containers; - for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { - WmWindow* container = root->GetChildByShellWindowId(container_id); - if (!container) - continue; - - if (priority_root && priority_root->Contains(container)) - containers.insert(containers.begin(), container); - else - containers.push_back(container); - } - return containers; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/container_finder.h b/ash/wm/container_finder.h deleted file mode 100644 index 7f90806..0000000 --- a/ash/wm/container_finder.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_CONTAINER_FINDER_H_ -#define ASH_WM_CONTAINER_FINDER_H_ - -#include <vector> - -#include "ash/ash_export.h" - -namespace gfx { -class Rect; -} - -namespace ash { - -class WmWindow; - -namespace wm { - -// Returns the first ancestor of |window| that has a known container ID. -ASH_EXPORT WmWindow* GetContainerForWindow(WmWindow* window); - -// Returns the parent to add |window| to in |context|. This is generally -// used when a window is moved from one root to another. In this case |context| -// is the new root to add |window| to. -ASH_EXPORT WmWindow* GetDefaultParent(WmWindow* context, - WmWindow* window, - const gfx::Rect& bounds); - -// Returns the list of containers that match |container_id| in all root windows. -// If |priority_root| is non-null, the container in |priority_root| is placed at -// the front of the list. -ASH_EXPORT std::vector<WmWindow*> GetContainersFromAllRootWindows( - int container_id, - WmWindow* priority_root = nullptr); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_CONTAINER_FINDER_H_
diff --git a/ash/wm/container_finder_unittest.cc b/ash/wm/container_finder_unittest.cc deleted file mode 100644 index 7692c82..0000000 --- a/ash/wm/container_finder_unittest.cc +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/container_finder.h" - -#include <memory> - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/test/ash_test.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -using ContainerFinderTest = AshTest; - -TEST_F(ContainerFinderTest, GetContainerForWindow) { - // Create a normal widget in the default container. - std::unique_ptr<views::Widget> widget = - CreateTestWidget(gfx::Rect(1, 2, 3, 4)); - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - - // The window itself is not a container. - EXPECT_EQ(kShellWindowId_Invalid, window->GetShellWindowId()); - - // Container lookup finds the default container. - WmWindow* container = wm::GetContainerForWindow(window); - ASSERT_TRUE(container); - EXPECT_EQ(kShellWindowId_DefaultContainer, container->GetShellWindowId()); -} - -} // namespace ash
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc deleted file mode 100644 index 404786e..0000000 --- a/ash/wm/default_state.cc +++ /dev/null
@@ -1,823 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/default_state.h" - -#include "ash/common/ash_switches.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/window_animation_types.h" -#include "ash/wm/window_parenting_utils.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_delegate.h" -#include "ash/wm/window_state_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" - -namespace ash { -namespace wm { -namespace { - -// This specifies how much percent (30%) of a window rect -// must be visible when the window is added to the workspace. -const float kMinimumPercentOnScreenArea = 0.3f; - -// When a window that has restore bounds at least as large as a work area is -// unmaximized, inset the bounds slightly so that they are not exactly the same. -// This makes it easier to resize the window. -const int kMaximizedWindowInset = 10; // DIPs. - -bool IsMinimizedWindowState(const WindowStateType state_type) { - return state_type == WINDOW_STATE_TYPE_MINIMIZED || - state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; -} - -void MoveToDisplayForRestore(WindowState* window_state) { - if (!window_state->HasRestoreBounds()) - return; - const gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); - - // Move only if the restore bounds is outside of - // the display. There is no information about in which - // display it should be restored, so this is best guess. - // TODO(oshima): Restore information should contain the - // work area information like WindowResizer does for the - // last window location. - gfx::Rect display_area = - window_state->window()->GetDisplayNearestWindow().bounds(); - - if (!display_area.Intersects(restore_bounds)) { - const display::Display& display = - display::Screen::GetScreen()->GetDisplayMatching(restore_bounds); - WmShell* shell = window_state->window()->GetShell(); - WmWindow* new_root = shell->GetRootWindowForDisplayId(display.id()); - if (new_root != window_state->window()->GetRootWindow()) { - WmWindow* new_container = new_root->GetChildByShellWindowId( - window_state->window()->GetParent()->GetShellWindowId()); - new_container->AddChild(window_state->window()); - } - } -} - -DockedWindowLayoutManager* GetDockedWindowLayoutManager(WmShell* shell) { - return DockedWindowLayoutManager::Get(shell->GetActiveWindow()); -} - -class ScopedPreferredAlignmentResetter { - public: - ScopedPreferredAlignmentResetter(DockedAlignment dock_alignment, - DockedWindowLayoutManager* dock_layout) - : docked_window_layout_manager_(dock_layout) { - docked_window_layout_manager_->set_preferred_alignment(dock_alignment); - } - ~ScopedPreferredAlignmentResetter() { - docked_window_layout_manager_->set_preferred_alignment( - DOCKED_ALIGNMENT_NONE); - } - - private: - DockedWindowLayoutManager* docked_window_layout_manager_; - - DISALLOW_COPY_AND_ASSIGN(ScopedPreferredAlignmentResetter); -}; - -class ScopedDockedLayoutEventSourceResetter { - public: - ScopedDockedLayoutEventSourceResetter(DockedWindowLayoutManager* dock_layout) - : docked_window_layout_manager_(dock_layout) { - docked_window_layout_manager_->set_event_source( - DOCKED_ACTION_SOURCE_KEYBOARD); - } - ~ScopedDockedLayoutEventSourceResetter() { - docked_window_layout_manager_->set_event_source( - DOCKED_ACTION_SOURCE_UNKNOWN); - } - - private: - DockedWindowLayoutManager* docked_window_layout_manager_; - - DISALLOW_COPY_AND_ASSIGN(ScopedDockedLayoutEventSourceResetter); -}; - -void CycleSnap(WindowState* window_state, WMEventType event) { - DCHECK(!ash::switches::DockedWindowsEnabled()); - - wm::WindowStateType desired_snap_state = - event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT - ? wm::WINDOW_STATE_TYPE_LEFT_SNAPPED - : wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED; - - if (window_state->CanSnap() && - window_state->GetStateType() != desired_snap_state && - window_state->window()->GetType() != ui::wm::WINDOW_TYPE_PANEL) { - const wm::WMEvent event(desired_snap_state == - wm::WINDOW_STATE_TYPE_LEFT_SNAPPED - ? wm::WM_EVENT_SNAP_LEFT - : wm::WM_EVENT_SNAP_RIGHT); - window_state->OnWMEvent(&event); - return; - } - - if (window_state->IsSnapped()) { - window_state->Restore(); - return; - } - window_state->window()->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); -} - -void CycleSnapDock(WindowState* window_state, WMEventType event) { - DCHECK(ash::switches::DockedWindowsEnabled()); - - DockedWindowLayoutManager* dock_layout = - GetDockedWindowLayoutManager(window_state->window()->GetShell()); - wm::WindowStateType desired_snap_state = - event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT - ? wm::WINDOW_STATE_TYPE_LEFT_SNAPPED - : wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED; - DockedAlignment desired_dock_alignment = - event == WM_EVENT_CYCLE_SNAP_DOCK_LEFT ? DOCKED_ALIGNMENT_LEFT - : DOCKED_ALIGNMENT_RIGHT; - DockedAlignment current_dock_alignment = - dock_layout ? dock_layout->CalculateAlignment() : DOCKED_ALIGNMENT_NONE; - - if (!window_state->IsDocked() || - (current_dock_alignment != DOCKED_ALIGNMENT_NONE && - current_dock_alignment != desired_dock_alignment)) { - if (window_state->CanSnap() && - window_state->GetStateType() != desired_snap_state && - window_state->window()->GetType() != ui::wm::WINDOW_TYPE_PANEL) { - const wm::WMEvent event(desired_snap_state == - wm::WINDOW_STATE_TYPE_LEFT_SNAPPED - ? wm::WM_EVENT_SNAP_LEFT - : wm::WM_EVENT_SNAP_RIGHT); - window_state->OnWMEvent(&event); - return; - } - - if (dock_layout && - dock_layout->CanDockWindow(window_state->window(), - desired_dock_alignment)) { - if (window_state->IsDocked()) { - dock_layout->MaybeSetDesiredDockedAlignment(desired_dock_alignment); - return; - } - - ScopedDockedLayoutEventSourceResetter event_source_resetter(dock_layout); - ScopedPreferredAlignmentResetter alignmentResetter(desired_dock_alignment, - dock_layout); - const wm::WMEvent event(wm::WM_EVENT_DOCK); - window_state->OnWMEvent(&event); - return; - } - } - - if (window_state->IsDocked() || window_state->IsSnapped()) { - ScopedDockedLayoutEventSourceResetter event_source_resetter(dock_layout); - window_state->Restore(); - return; - } - window_state->window()->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); -} - -} // namespace - -DefaultState::DefaultState(WindowStateType initial_state_type) - : state_type_(initial_state_type), stored_window_state_(nullptr) {} -DefaultState::~DefaultState() {} - -void DefaultState::OnWMEvent(WindowState* window_state, const WMEvent* event) { - if (ProcessWorkspaceEvents(window_state, event)) - return; - - // Do not change the PINNED window state if this is not unpin event. - if (window_state->IsTrustedPinned() && event->type() != WM_EVENT_NORMAL) - return; - - if (ProcessCompoundEvents(window_state, event)) - return; - - WindowStateType current_state_type = window_state->GetStateType(); - WindowStateType next_state_type = WINDOW_STATE_TYPE_NORMAL; - switch (event->type()) { - case WM_EVENT_NORMAL: - next_state_type = current_state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED - ? WINDOW_STATE_TYPE_DOCKED - : WINDOW_STATE_TYPE_NORMAL; - break; - case WM_EVENT_MAXIMIZE: - next_state_type = WINDOW_STATE_TYPE_MAXIMIZED; - break; - case WM_EVENT_MINIMIZE: - next_state_type = current_state_type == WINDOW_STATE_TYPE_DOCKED - ? WINDOW_STATE_TYPE_DOCKED_MINIMIZED - : WINDOW_STATE_TYPE_MINIMIZED; - break; - case WM_EVENT_FULLSCREEN: - next_state_type = WINDOW_STATE_TYPE_FULLSCREEN; - break; - case WM_EVENT_SNAP_LEFT: - next_state_type = WINDOW_STATE_TYPE_LEFT_SNAPPED; - break; - case WM_EVENT_SNAP_RIGHT: - next_state_type = WINDOW_STATE_TYPE_RIGHT_SNAPPED; - break; - case WM_EVENT_DOCK: - next_state_type = WINDOW_STATE_TYPE_DOCKED; - break; - case WM_EVENT_SET_BOUNDS: - SetBounds(window_state, static_cast<const SetBoundsEvent*>(event)); - return; - case WM_EVENT_SHOW_INACTIVE: - next_state_type = WINDOW_STATE_TYPE_INACTIVE; - break; - case WM_EVENT_PIN: - case WM_EVENT_TRUSTED_PIN: - // If there already is a pinned window, it is not allowed to set it - // to this window. - // TODO(hidehiko): If a system modal window is openening, the pinning - // probably should fail. - if (WmShell::Get()->IsPinned()) { - LOG(ERROR) << "An PIN event will be failed since another window is " - << "already in pinned mode."; - next_state_type = current_state_type; - } else { - next_state_type = event->type() == WM_EVENT_PIN - ? WINDOW_STATE_TYPE_PINNED - : WINDOW_STATE_TYPE_TRUSTED_PINNED; - } - break; - case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: - case WM_EVENT_TOGGLE_MAXIMIZE: - case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: - case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: - case WM_EVENT_TOGGLE_FULLSCREEN: - case WM_EVENT_CYCLE_SNAP_DOCK_LEFT: - case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: - case WM_EVENT_CENTER: - NOTREACHED() << "Compound event should not reach here:" << event; - return; - case WM_EVENT_ADDED_TO_WORKSPACE: - case WM_EVENT_WORKAREA_BOUNDS_CHANGED: - case WM_EVENT_DISPLAY_BOUNDS_CHANGED: - NOTREACHED() << "Workspace event should not reach here:" << event; - return; - } - - if (next_state_type == current_state_type && window_state->IsSnapped()) { - gfx::Rect snapped_bounds = - event->type() == WM_EVENT_SNAP_LEFT - ? GetDefaultLeftSnappedWindowBoundsInParent(window_state->window()) - : GetDefaultRightSnappedWindowBoundsInParent( - window_state->window()); - window_state->SetBoundsDirectAnimated(snapped_bounds); - return; - } - - if (event->type() == WM_EVENT_SNAP_LEFT || - event->type() == WM_EVENT_SNAP_RIGHT) { - window_state->set_bounds_changed_by_user(true); - } - - EnterToNextState(window_state, next_state_type); -} - -WindowStateType DefaultState::GetType() const { - return state_type_; -} - -void DefaultState::AttachState(WindowState* window_state, - WindowState::State* state_in_previous_mode) { - DCHECK_EQ(stored_window_state_, window_state); - - ReenterToCurrentState(window_state, state_in_previous_mode); - - // If the display has changed while in the another mode, - // we need to let windows know the change. - display::Display current_display = - window_state->window()->GetDisplayNearestWindow(); - if (stored_display_state_.bounds() != current_display.bounds()) { - const WMEvent event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); - window_state->OnWMEvent(&event); - } else if (stored_display_state_.work_area() != current_display.work_area()) { - const WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); - window_state->OnWMEvent(&event); - } -} - -void DefaultState::DetachState(WindowState* window_state) { - stored_window_state_ = window_state; - stored_bounds_ = window_state->window()->GetBounds(); - stored_restore_bounds_ = window_state->HasRestoreBounds() - ? window_state->GetRestoreBoundsInParent() - : gfx::Rect(); - // Remember the display state so that in case of the display change - // while in the other mode, we can perform necessary action to - // restore the window state to the proper state for the current - // display. - stored_display_state_ = window_state->window()->GetDisplayNearestWindow(); -} - -// static -bool DefaultState::ProcessCompoundEvents(WindowState* window_state, - const WMEvent* event) { - WmWindow* window = window_state->window(); - - switch (event->type()) { - case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: - if (window_state->IsFullscreen()) { - const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); - window_state->OnWMEvent(&event); - } else if (window_state->IsMaximized()) { - window_state->Restore(); - } else if (window_state->IsNormalOrSnapped()) { - if (window_state->CanMaximize()) - window_state->Maximize(); - } - return true; - case WM_EVENT_TOGGLE_MAXIMIZE: - if (window_state->IsFullscreen()) { - const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN); - window_state->OnWMEvent(&event); - } else if (window_state->IsMaximized()) { - window_state->Restore(); - } else if (window_state->CanMaximize()) { - window_state->Maximize(); - } - return true; - case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: { - gfx::Rect work_area = GetDisplayWorkAreaBoundsInParent(window); - - // Maximize vertically if: - // - The window does not have a max height defined. - // - The window has the normal state type. Snapped windows are excluded - // because they are already maximized vertically and reverting to the - // restored bounds looks weird. - if (window->GetMaximumSize().height() != 0 || - !window_state->IsNormalStateType()) { - return true; - } - if (window_state->HasRestoreBounds() && - (window->GetBounds().height() == work_area.height() && - window->GetBounds().y() == work_area.y())) { - window_state->SetAndClearRestoreBounds(); - } else { - window_state->SaveCurrentBoundsForRestore(); - window->SetBounds(gfx::Rect(window->GetBounds().x(), work_area.y(), - window->GetBounds().width(), - work_area.height())); - } - return true; - } - case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: { - // Maximize horizontally if: - // - The window does not have a max width defined. - // - The window is snapped or has the normal state type. - if (window->GetMaximumSize().width() != 0) - return true; - if (!window_state->IsNormalOrSnapped()) - return true; - gfx::Rect work_area = GetDisplayWorkAreaBoundsInParent(window); - if (window_state->IsNormalStateType() && - window_state->HasRestoreBounds() && - (window->GetBounds().width() == work_area.width() && - window->GetBounds().x() == work_area.x())) { - window_state->SetAndClearRestoreBounds(); - } else { - gfx::Rect new_bounds(work_area.x(), window->GetBounds().y(), - work_area.width(), window->GetBounds().height()); - - gfx::Rect restore_bounds = window->GetBounds(); - if (window_state->IsSnapped()) { - window_state->SetRestoreBoundsInParent(new_bounds); - window_state->Restore(); - - // The restore logic prevents a window from being restored to bounds - // which match the workspace bounds exactly so it is necessary to set - // the bounds again below. - } - - window_state->SetRestoreBoundsInParent(restore_bounds); - window->SetBounds(new_bounds); - } - return true; - } - case WM_EVENT_TOGGLE_FULLSCREEN: - ToggleFullScreen(window_state, window_state->delegate()); - return true; - case WM_EVENT_CYCLE_SNAP_DOCK_LEFT: - case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: - if (ash::switches::DockedWindowsEnabled()) - CycleSnapDock(window_state, event->type()); - else - CycleSnap(window_state, event->type()); - return true; - case WM_EVENT_CENTER: - CenterWindow(window_state); - return true; - case WM_EVENT_NORMAL: - case WM_EVENT_MAXIMIZE: - case WM_EVENT_MINIMIZE: - case WM_EVENT_FULLSCREEN: - case WM_EVENT_PIN: - case WM_EVENT_TRUSTED_PIN: - case WM_EVENT_SNAP_LEFT: - case WM_EVENT_SNAP_RIGHT: - case WM_EVENT_SET_BOUNDS: - case WM_EVENT_SHOW_INACTIVE: - case WM_EVENT_DOCK: - break; - case WM_EVENT_ADDED_TO_WORKSPACE: - case WM_EVENT_WORKAREA_BOUNDS_CHANGED: - case WM_EVENT_DISPLAY_BOUNDS_CHANGED: - NOTREACHED() << "Workspace event should not reach here:" << event; - break; - } - return false; -} - -bool DefaultState::ProcessWorkspaceEvents(WindowState* window_state, - const WMEvent* event) { - switch (event->type()) { - case WM_EVENT_ADDED_TO_WORKSPACE: { - // When a window is dragged and dropped onto a different - // root window, the bounds will be updated after they are added - // to the root window. - // If a window is opened as maximized or fullscreen, its bounds may be - // empty, so update the bounds now before checking empty. - if (window_state->is_dragged() || - SetMaximizedOrFullscreenBounds(window_state)) { - return true; - } - - WmWindow* window = window_state->window(); - gfx::Rect bounds = window->GetBounds(); - - // Don't adjust window bounds if the bounds are empty as this - // happens when a new views::Widget is created. - if (bounds.IsEmpty()) - return true; - - // Only windows of type WINDOW_TYPE_NORMAL or WINDOW_TYPE_PANEL need to be - // adjusted to have minimum visibility, because they are positioned by the - // user and user should always be able to interact with them. Other - // windows are positioned programmatically. - if (!window_state->IsUserPositionable()) - return true; - - // Use entire display instead of workarea because the workarea can - // be further shrunk by the docked area. The logic ensures 30% - // visibility which should be enough to see where the window gets - // moved. - gfx::Rect display_area = GetDisplayBoundsInParent(window); - int min_width = bounds.width() * wm::kMinimumPercentOnScreenArea; - int min_height = bounds.height() * wm::kMinimumPercentOnScreenArea; - wm::AdjustBoundsToEnsureWindowVisibility(display_area, min_width, - min_height, &bounds); - window_state->AdjustSnappedBounds(&bounds); - if (window->GetBounds() != bounds) - window_state->SetBoundsConstrained(bounds); - return true; - } - case WM_EVENT_DISPLAY_BOUNDS_CHANGED: { - if (window_state->is_dragged() || - SetMaximizedOrFullscreenBounds(window_state)) { - return true; - } - gfx::Rect work_area_in_parent = - GetDisplayWorkAreaBoundsInParent(window_state->window()); - gfx::Rect bounds = window_state->window()->GetTargetBounds(); - // When display bounds has changed, make sure the entire window is fully - // visible. - bounds.AdjustToFit(work_area_in_parent); - window_state->AdjustSnappedBounds(&bounds); - if (window_state->window()->GetTargetBounds() != bounds) - window_state->SetBoundsDirectAnimated(bounds); - return true; - } - case WM_EVENT_WORKAREA_BOUNDS_CHANGED: { - // Don't resize the maximized window when the desktop is covered - // by fullscreen window. crbug.com/504299. - bool in_fullscreen = - window_state->window() - ->GetRootWindowController() - ->GetWorkspaceWindowState() == WORKSPACE_WINDOW_STATE_FULL_SCREEN; - if (in_fullscreen && window_state->IsMaximized()) - return true; - - if (window_state->is_dragged() || - SetMaximizedOrFullscreenBounds(window_state)) { - return true; - } - gfx::Rect work_area_in_parent = - GetDisplayWorkAreaBoundsInParent(window_state->window()); - gfx::Rect bounds = window_state->window()->GetTargetBounds(); - if (!window_state->window()->GetTransientParent()) { - wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, - &bounds); - } - window_state->AdjustSnappedBounds(&bounds); - if (window_state->window()->GetTargetBounds() != bounds) - window_state->SetBoundsDirectAnimated(bounds); - return true; - } - case WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: - case WM_EVENT_TOGGLE_MAXIMIZE: - case WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: - case WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: - case WM_EVENT_TOGGLE_FULLSCREEN: - case WM_EVENT_CYCLE_SNAP_DOCK_LEFT: - case WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: - case WM_EVENT_CENTER: - case WM_EVENT_NORMAL: - case WM_EVENT_MAXIMIZE: - case WM_EVENT_MINIMIZE: - case WM_EVENT_FULLSCREEN: - case WM_EVENT_PIN: - case WM_EVENT_TRUSTED_PIN: - case WM_EVENT_SNAP_LEFT: - case WM_EVENT_SNAP_RIGHT: - case WM_EVENT_SET_BOUNDS: - case WM_EVENT_SHOW_INACTIVE: - case WM_EVENT_DOCK: - break; - } - return false; -} - -// static -bool DefaultState::SetMaximizedOrFullscreenBounds(WindowState* window_state) { - DCHECK(!window_state->is_dragged()); - if (window_state->IsMaximized()) { - window_state->SetBoundsDirect( - GetMaximizedWindowBoundsInParent(window_state->window())); - return true; - } - if (window_state->IsFullscreen()) { - window_state->SetBoundsDirect( - GetDisplayBoundsInParent(window_state->window())); - return true; - } - return false; -} - -// static -void DefaultState::SetBounds(WindowState* window_state, - const SetBoundsEvent* event) { - if (window_state->is_dragged()) { - // TODO(oshima|varkha): This may be no longer needed, as the dragging - // happens in docked window container. crbug.com/485612. - window_state->SetBoundsDirect(event->requested_bounds()); - } else if (window_state->IsSnapped()) { - gfx::Rect work_area_in_parent = - GetDisplayWorkAreaBoundsInParent(window_state->window()); - gfx::Rect child_bounds(event->requested_bounds()); - wm::AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds); - window_state->AdjustSnappedBounds(&child_bounds); - window_state->SetBoundsDirect(child_bounds); - } else if (!SetMaximizedOrFullscreenBounds(window_state) || - window_state->allow_set_bounds_in_maximized()) { - window_state->SetBoundsConstrained(event->requested_bounds()); - } -} - -void DefaultState::EnterToNextState(WindowState* window_state, - WindowStateType next_state_type) { - // Do nothing if we're already in the same state. - if (state_type_ == next_state_type) - return; - - WindowStateType previous_state_type = state_type_; - state_type_ = next_state_type; - - window_state->UpdateWindowShowStateFromStateType(); - window_state->NotifyPreStateTypeChange(previous_state_type); - - if (window_state->window()->GetParent()) { - if (!window_state->HasRestoreBounds() && - (previous_state_type == WINDOW_STATE_TYPE_DEFAULT || - previous_state_type == WINDOW_STATE_TYPE_NORMAL) && - !window_state->IsMinimized() && !window_state->IsNormalStateType()) { - window_state->SaveCurrentBoundsForRestore(); - } - - // When restoring from a minimized state, we want to restore to the - // previous bounds. However, we want to maintain the restore bounds. - // (The restore bounds are set if a user maximized the window in one - // axis by double clicking the window border for example). - gfx::Rect restore_bounds_in_screen; - if (previous_state_type == WINDOW_STATE_TYPE_MINIMIZED && - window_state->IsNormalStateType() && window_state->HasRestoreBounds() && - !window_state->unminimize_to_restore_bounds()) { - restore_bounds_in_screen = window_state->GetRestoreBoundsInScreen(); - window_state->SaveCurrentBoundsForRestore(); - } - - if (window_state->IsMaximizedOrFullscreenOrPinned()) - MoveToDisplayForRestore(window_state); - - UpdateBoundsFromState(window_state, previous_state_type); - - // Normal state should have no restore bounds unless it's - // unminimized. - if (!restore_bounds_in_screen.IsEmpty()) - window_state->SetRestoreBoundsInScreen(restore_bounds_in_screen); - else if (window_state->IsNormalStateType()) - window_state->ClearRestoreBounds(); - } - window_state->NotifyPostStateTypeChange(previous_state_type); - - if (next_state_type == WINDOW_STATE_TYPE_PINNED || - previous_state_type == WINDOW_STATE_TYPE_PINNED || - next_state_type == WINDOW_STATE_TYPE_TRUSTED_PINNED || - previous_state_type == WINDOW_STATE_TYPE_TRUSTED_PINNED) { - WmShell::Get()->SetPinnedWindow(window_state->window()); - } -} - -void DefaultState::ReenterToCurrentState( - WindowState* window_state, - WindowState::State* state_in_previous_mode) { - WindowStateType previous_state_type = state_in_previous_mode->GetType(); - - // A state change should not move a window into or out of full screen or - // pinned since these are "special mode" the user wanted to be in and - // should be respected as such. - if (previous_state_type == wm::WINDOW_STATE_TYPE_FULLSCREEN || - previous_state_type == wm::WINDOW_STATE_TYPE_PINNED || - previous_state_type == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { - state_type_ = previous_state_type; - } else if (state_type_ == wm::WINDOW_STATE_TYPE_FULLSCREEN || - state_type_ == wm::WINDOW_STATE_TYPE_PINNED || - state_type_ == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { - state_type_ = previous_state_type; - } - - window_state->UpdateWindowShowStateFromStateType(); - window_state->NotifyPreStateTypeChange(previous_state_type); - - if ((state_type_ == wm::WINDOW_STATE_TYPE_NORMAL || - state_type_ == wm::WINDOW_STATE_TYPE_DEFAULT) && - !stored_bounds_.IsEmpty()) { - // Use the restore mechanism to set the bounds for - // the window in normal state. This also covers unminimize case. - window_state->SetRestoreBoundsInParent(stored_bounds_); - } - - UpdateBoundsFromState(window_state, state_in_previous_mode->GetType()); - - // Then restore the restore bounds to their previous value. - if (!stored_restore_bounds_.IsEmpty()) - window_state->SetRestoreBoundsInParent(stored_restore_bounds_); - else - window_state->ClearRestoreBounds(); - - window_state->NotifyPostStateTypeChange(previous_state_type); -} - -void DefaultState::UpdateBoundsFromState(WindowState* window_state, - WindowStateType previous_state_type) { - WmWindow* window = window_state->window(); - gfx::Rect bounds_in_parent; - switch (state_type_) { - case WINDOW_STATE_TYPE_LEFT_SNAPPED: - case WINDOW_STATE_TYPE_RIGHT_SNAPPED: - bounds_in_parent = - state_type_ == WINDOW_STATE_TYPE_LEFT_SNAPPED - ? GetDefaultLeftSnappedWindowBoundsInParent(window) - : GetDefaultRightSnappedWindowBoundsInParent(window); - break; - case WINDOW_STATE_TYPE_DOCKED: { - // TODO(afakhry): Remove in M58. - DCHECK(ash::switches::DockedWindowsEnabled()); - if (window->GetParent()->GetShellWindowId() != - kShellWindowId_DockedContainer) { - WmWindow* docked_container = - window->GetRootWindow()->GetChildByShellWindowId( - kShellWindowId_DockedContainer); - ReparentChildWithTransientChildren(window, window->GetParent(), - docked_container); - } - // Return early because we don't want to update the bounds of the - // window below; as the bounds are managed by the dock layout. - return; - } - case WINDOW_STATE_TYPE_DEFAULT: - case WINDOW_STATE_TYPE_NORMAL: { - gfx::Rect work_area_in_parent = GetDisplayWorkAreaBoundsInParent(window); - if (window_state->HasRestoreBounds()) { - bounds_in_parent = window_state->GetRestoreBoundsInParent(); - // Check if the |window|'s restored size is bigger than the working area - // This may happen if a window was resized to maximized bounds or if the - // display resolution changed while the window was maximized. - if (previous_state_type == WINDOW_STATE_TYPE_MAXIMIZED && - bounds_in_parent.width() >= work_area_in_parent.width() && - bounds_in_parent.height() >= work_area_in_parent.height()) { - bounds_in_parent = work_area_in_parent; - bounds_in_parent.Inset(kMaximizedWindowInset, kMaximizedWindowInset, - kMaximizedWindowInset, kMaximizedWindowInset); - } - } else { - bounds_in_parent = window->GetBounds(); - } - // Make sure that part of the window is always visible. - if (!window_state->is_dragged()) { - // Avoid doing this while the window is being dragged as its root - // window hasn't been updated yet in the case of dragging to another - // display. crbug.com/666836. - wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_in_parent, - &bounds_in_parent); - } - break; - } - case WINDOW_STATE_TYPE_MAXIMIZED: - bounds_in_parent = GetMaximizedWindowBoundsInParent(window); - break; - - case WINDOW_STATE_TYPE_FULLSCREEN: - case WINDOW_STATE_TYPE_PINNED: - case WINDOW_STATE_TYPE_TRUSTED_PINNED: - bounds_in_parent = GetDisplayBoundsInParent(window); - break; - - case WINDOW_STATE_TYPE_DOCKED_MINIMIZED: - case WINDOW_STATE_TYPE_MINIMIZED: - break; - case WINDOW_STATE_TYPE_INACTIVE: - case WINDOW_STATE_TYPE_END: - case WINDOW_STATE_TYPE_AUTO_POSITIONED: - return; - } - - if (!window_state->IsMinimized()) { - if (IsMinimizedWindowState(previous_state_type) || - window_state->IsFullscreen() || window_state->IsPinned()) { - window_state->SetBoundsDirect(bounds_in_parent); - } else if (window_state->IsMaximized() || - IsMaximizedOrFullscreenOrPinnedWindowStateType( - previous_state_type)) { - window_state->SetBoundsDirectCrossFade(bounds_in_parent); - } else if (window_state->is_dragged()) { - // SetBoundsDirectAnimated does not work when the window gets reparented. - // TODO(oshima): Consider fixing it and reenable the animation. - window_state->SetBoundsDirect(bounds_in_parent); - } else { - window_state->SetBoundsDirectAnimated(bounds_in_parent); - } - } - - if (window_state->IsMinimized()) { - // Save the previous show state so that we can correctly restore it after - // exiting the minimized mode. - window->SetPreMinimizedShowState(ToWindowShowState(previous_state_type)); - window->SetVisibilityAnimationType( - WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); - - // Hide the window. - window->Hide(); - // Activate another window. - if (window_state->IsActive()) - window_state->Deactivate(); - } else if ((window->GetTargetVisibility() || - IsMinimizedWindowState(previous_state_type)) && - !window->GetLayerVisible()) { - // The layer may be hidden if the window was previously minimized. Make - // sure it's visible. - window->Show(); - if (IsMinimizedWindowState(previous_state_type) && - !window_state->IsMaximizedOrFullscreenOrPinned()) { - window_state->set_unminimize_to_restore_bounds(false); - } - } -} - -// static -void DefaultState::CenterWindow(WindowState* window_state) { - if (!window_state->IsNormalOrSnapped()) - return; - WmWindow* window = window_state->window(); - if (window_state->IsSnapped()) { - gfx::Rect center_in_screen = window->GetDisplayNearestWindow().work_area(); - gfx::Size size = window_state->HasRestoreBounds() - ? window_state->GetRestoreBoundsInScreen().size() - : window->GetBounds().size(); - center_in_screen.ClampToCenteredSize(size); - window_state->SetRestoreBoundsInScreen(center_in_screen); - window_state->Restore(); - } else { - gfx::Rect center_in_parent = GetDisplayWorkAreaBoundsInParent(window); - center_in_parent.ClampToCenteredSize(window->GetBounds().size()); - window_state->SetBoundsDirectAnimated(center_in_parent); - } - // Centering window is treated as if a user moved and resized the window. - window_state->set_bounds_changed_by_user(true); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/default_state.h b/ash/wm/default_state.h deleted file mode 100644 index d48da36..0000000 --- a/ash/wm/default_state.h +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DEFAULT_STATE_H_ -#define ASH_WM_DEFAULT_STATE_H_ - -#include "ash/wm/window_state.h" -#include "base/macros.h" -#include "ui/display/display.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { -namespace wm { -class SetBoundsEvent; - -// DefaultState implements Ash behavior without state machine. -class DefaultState : public WindowState::State { - public: - explicit DefaultState(WindowStateType initial_state_type); - ~DefaultState() override; - - // WindowState::State overrides: - void OnWMEvent(WindowState* window_state, const WMEvent* event) override; - WindowStateType GetType() const override; - void AttachState(WindowState* window_state, - WindowState::State* previous_state) override; - void DetachState(WindowState* window_state) override; - - private: - // Process state dependent events, such as TOGGLE_MAXIMIZED, - // TOGGLE_FULLSCREEN. - static bool ProcessCompoundEvents(WindowState* window_state, - const WMEvent* event); - - // Process workspace related events, such as DISPLAY_BOUNDS_CHANGED. - static bool ProcessWorkspaceEvents(WindowState* window_state, - const WMEvent* event); - - // Set the fullscreen/maximized bounds without animation. - static bool SetMaximizedOrFullscreenBounds(wm::WindowState* window_state); - - static void SetBounds(WindowState* window_state, - const SetBoundsEvent* bounds_event); - - static void CenterWindow(WindowState* window_state); - - // Enters next state. This is used when the state moves from one to another - // within the same desktop mode. - void EnterToNextState(wm::WindowState* window_state, - wm::WindowStateType next_state_type); - - // Reenters the current state. This is called when migrating from - // previous desktop mode, and the window's state needs to re-construct the - // state/bounds for this state. - void ReenterToCurrentState(wm::WindowState* window_state, - wm::WindowState::State* state_in_previous_mode); - - // Animates to new window bounds based on the current and previous state type. - void UpdateBoundsFromState(wm::WindowState* window_state, - wm::WindowStateType old_state_type); - - // The current type of the window. - WindowStateType state_type_; - - // The saved window state for the case that the state gets de-/activated. - gfx::Rect stored_bounds_; - gfx::Rect stored_restore_bounds_; - - // The display state in which the mode got started. - display::Display stored_display_state_; - - // The window state only gets remembered for DCHECK reasons. - WindowState* stored_window_state_; - - DISALLOW_COPY_AND_ASSIGN(DefaultState); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_DEFAULT_STATE_H_
diff --git a/ash/wm/default_window_resizer.cc b/ash/wm/default_window_resizer.cc deleted file mode 100644 index 98943add..0000000 --- a/ash/wm/default_window_resizer.cc +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/default_window_resizer.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/window_state.h" - -namespace ash { - -DefaultWindowResizer::~DefaultWindowResizer() { - shell_->UnlockCursor(); -} - -// static -DefaultWindowResizer* DefaultWindowResizer::Create( - wm::WindowState* window_state) { - return new DefaultWindowResizer(window_state); -} - -void DefaultWindowResizer::Drag(const gfx::Point& location, int event_flags) { - gfx::Rect bounds(CalculateBoundsForDrag(location)); - if (bounds != GetTarget()->GetBounds()) { - if (!did_move_or_resize_ && !details().restore_bounds.IsEmpty()) - window_state_->ClearRestoreBounds(); - did_move_or_resize_ = true; - GetTarget()->SetBounds(bounds); - } -} - -void DefaultWindowResizer::CompleteDrag() {} - -void DefaultWindowResizer::RevertDrag() { - if (!did_move_or_resize_) - return; - - GetTarget()->SetBounds(details().initial_bounds_in_parent); - - if (!details().restore_bounds.IsEmpty()) - window_state_->SetRestoreBoundsInScreen(details().restore_bounds); -} - -DefaultWindowResizer::DefaultWindowResizer(wm::WindowState* window_state) - : WindowResizer(window_state), - did_move_or_resize_(false), - shell_(GetTarget()->GetShell()) { - DCHECK(details().is_resizable); - shell_->LockCursor(); -} - -} // namespace aura
diff --git a/ash/wm/default_window_resizer.h b/ash/wm/default_window_resizer.h deleted file mode 100644 index 7919a638..0000000 --- a/ash/wm/default_window_resizer.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DEFAULT_WINDOW_RESIZER_H_ -#define ASH_WM_DEFAULT_WINDOW_RESIZER_H_ - -#include "ash/ash_export.h" -#include "ash/wm/window_resizer.h" -#include "base/macros.h" - -namespace ash { -class WmShell; - -// WindowResizer is used by ToplevelWindowEventFilter to handle dragging, moving -// or resizing a window. All coordinates passed to this are in the parent -// windows coordiantes. -class ASH_EXPORT DefaultWindowResizer : public WindowResizer { - public: - ~DefaultWindowResizer() override; - - // Creates a new DefaultWindowResizer. The caller takes ownership of the - // returned object. - static DefaultWindowResizer* Create(wm::WindowState* window_state); - - // Returns true if the drag will result in changing the window in anyway. - bool is_resizable() const { return details().is_resizable; } - - bool changed_size() const { - return !(details().bounds_change & kBoundsChange_Repositions); - } - - // WindowResizer: - void Drag(const gfx::Point& location, int event_flags) override; - void CompleteDrag() override; - void RevertDrag() override; - - private: - explicit DefaultWindowResizer(wm::WindowState* window_state); - - // Set to true once Drag() is invoked and the bounds of the window change. - bool did_move_or_resize_; - - WmShell* shell_; - - DISALLOW_COPY_AND_ASSIGN(DefaultWindowResizer); -}; - -} // namespace aura - -#endif // ASH_WM_DEFAULT_WINDOW_RESIZER_H_
diff --git a/ash/wm/dock/dock_types.h b/ash/wm/dock/dock_types.h deleted file mode 100644 index 8ca97f1..0000000 --- a/ash/wm/dock/dock_types.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DOCK_DOCK_TYPES_H_ -#define ASH_WM_DOCK_DOCK_TYPES_H_ - -namespace ash { - -// Possible values of which side of the screen the windows are docked at. -// This is used by DockedwindowLayoutManager and DockedWindowResizer to -// implement docking behavior including magnetism while dragging windows into -// or out of the docked windows area. -enum DockedAlignment { - // No docked windows. - DOCKED_ALIGNMENT_NONE, - - // Some windows are already docked on the left side of the screen. - DOCKED_ALIGNMENT_LEFT, - - // Some windows are already docked on the right side of the screen. - DOCKED_ALIGNMENT_RIGHT, -}; - -// User action recorded for use in UMA histograms. -enum DockedAction { - DOCKED_ACTION_NONE, // Regular drag of undocked window. Not recorded. - DOCKED_ACTION_DOCK, // Dragged and docked a window. - DOCKED_ACTION_UNDOCK, // Dragged and undocked a window. - DOCKED_ACTION_RESIZE, // Resized a docked window. - DOCKED_ACTION_REORDER, // Possibly reordered docked windows. - DOCKED_ACTION_EVICT, // A docked window could not stay docked. - DOCKED_ACTION_MAXIMIZE, // Maximized a docked window. - DOCKED_ACTION_MINIMIZE, // Minimized a docked window. - DOCKED_ACTION_RESTORE, // Restored a docked window that was minimized. - DOCKED_ACTION_CLOSE, // Closed a window while it was docked. - DOCKED_ACTION_COUNT, // Maximum value of this enum for histograms use. -}; - -// Event source for the docking user action (when known). -enum DockedActionSource { - DOCKED_ACTION_SOURCE_UNKNOWN, - DOCKED_ACTION_SOURCE_MOUSE, - DOCKED_ACTION_SOURCE_TOUCH, - DOCKED_ACTION_SOURCE_KEYBOARD, - - // Maximum value of this enum for histograms use. - DOCKED_ACTION_SOURCE_COUNT, -}; - -} // namespace ash - -#endif // ASH_WM_DOCK_DOCK_TYPES_H_
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc deleted file mode 100644 index 86ddad13..0000000 --- a/ash/wm/dock/docked_window_layout_manager.cc +++ /dev/null
@@ -1,1336 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/dock/docked_window_layout_manager.h" - -#include "ash/animation/animation_change_type.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_background_animator.h" -#include "ash/shelf/shelf_background_animator_observer.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_observer.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/window_animation_types.h" -#include "ash/wm/window_parenting_utils.h" -#include "ash/wm/window_resizer.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_aura.h" -#include "base/auto_reset.h" -#include "base/metrics/histogram_macros.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/views/background.h" -#include "ui/wm/core/coordinate_conversion.h" -#include "ui/wm/core/window_animations.h" - -namespace ash { - -// Minimum, maximum width of the dock area and a width of the gap -// static -const int DockedWindowLayoutManager::kMaxDockWidth = 360; -// static -const int DockedWindowLayoutManager::kMinDockWidth = 200; -// static -const int DockedWindowLayoutManager::kMinDockGap = 2; -// static -const int DockedWindowLayoutManager::kIdealWidth = 250; -const int kMinimumHeight = 250; -const int kSlideDurationMs = 120; -const int kFadeDurationMs = 60; -const int kMinimizeDurationMs = 720; - -class DockedBackgroundWidget : public views::Widget, - public WmShelfObserver, - public ShelfBackgroundAnimatorObserver { - public: - explicit DockedBackgroundWidget(DockedWindowLayoutManager* manager) - : manager_(manager), - alignment_(DOCKED_ALIGNMENT_NONE), - background_animator_(SHELF_BACKGROUND_DEFAULT, - nullptr, - WmShell::Get()->wallpaper_controller()), - opaque_background_(ui::LAYER_SOLID_COLOR), - visible_background_type_(manager_->shelf()->GetBackgroundType()), - visible_background_change_type_(AnimationChangeType::IMMEDIATE) { - manager_->shelf()->AddObserver(this); - InitWidget(manager_->dock_container()); - - background_animator_.AddObserver(this); - } - - ~DockedBackgroundWidget() override { - background_animator_.RemoveObserver(this); - manager_->shelf()->RemoveObserver(this); - } - - // Sets widget bounds and sizes opaque background layer to fill the widget. - void SetBackgroundBounds(const gfx::Rect& bounds, DockedAlignment alignment) { - SetBounds(bounds); - opaque_background_.SetBounds(gfx::Rect(bounds.size())); - alignment_ = alignment; - } - - private: - // views::Widget: - void OnNativeWidgetVisibilityChanged(bool visible) override { - views::Widget::OnNativeWidgetVisibilityChanged(visible); - UpdateBackground(); - } - - // ShelfBackgroundAnimatorObserver: - void UpdateShelfBackground(SkColor color) override { - opaque_background_.SetColor(color); - } - - // WmShelfObserver: - void OnBackgroundTypeChanged(ShelfBackgroundType background_type, - AnimationChangeType change_type) override { - // Sets the background type. Starts an animation to transition to - // |background_type| if the widget is visible. If the widget is not visible, - // the animation is postponed till the widget becomes visible. - visible_background_type_ = background_type; - visible_background_change_type_ = change_type; - if (IsVisible()) - UpdateBackground(); - } - - void InitWidget(WmWindow* parent) { - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_POPUP; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.keep_on_top = false; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.accept_events = false; - set_focus_on_creation(false); - parent->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - this, parent->GetShellWindowId(), ¶ms); - Init(params); - SetVisibilityChangedAnimationsEnabled(false); - WmWindow* wm_window = WmWindow::Get(this->GetNativeWindow()); - wm_window->SetLockedToRoot(true); - opaque_background_.SetColor(SK_ColorBLACK); - opaque_background_.SetBounds(gfx::Rect(GetWindowBoundsInScreen().size())); - opaque_background_.SetOpacity(0.0f); - wm_window->GetLayer()->Add(&opaque_background_); - - // This background should be explicitly stacked below any windows already in - // the dock, otherwise the z-order is set by the order in which windows were - // added to the container, and UpdateStacking only manages user windows, not - // the background widget. - parent->StackChildAtBottom(wm_window); - } - - // Transitions to |visible_background_type_| if the widget is visible and to - // SHELF_BACKGROUND_DEFAULT if it is not. - void UpdateBackground() { - ShelfBackgroundType background_type = - IsVisible() ? visible_background_type_ : SHELF_BACKGROUND_DEFAULT; - AnimationChangeType change_type = IsVisible() - ? visible_background_change_type_ - : AnimationChangeType::IMMEDIATE; - background_animator_.PaintBackground(background_type, change_type); - SchedulePaintInRect(gfx::Rect(GetWindowBoundsInScreen().size())); - } - - DockedWindowLayoutManager* manager_; - - DockedAlignment alignment_; - - // The animator for the background transitions. - ShelfBackgroundAnimator background_animator_; - - // TODO(bruthig): Remove opaque_background_ (see https://crbug.com/621551). - // Solid black background that can be made fully opaque. - ui::Layer opaque_background_; - - // The background type to use when the widget is visible. When not visible, - // the widget uses SHELF_BACKGROUND_DEFAULT. - ShelfBackgroundType visible_background_type_; - - // Whether the widget should animate to |visible_background_type_|. - AnimationChangeType visible_background_change_type_; - - DISALLOW_COPY_AND_ASSIGN(DockedBackgroundWidget); -}; - -namespace { - -// Returns true if a window is a popup or a transient child. -bool IsPopupOrTransient(const WmWindow* window) { - return (window->GetType() == ui::wm::WINDOW_TYPE_POPUP || - window->GetTransientParent()); -} - -// Certain windows (minimized, hidden or popups) are not docked and are ignored -// by layout logic even when they are children of a docked container. -bool IsWindowDocked(const WmWindow* window) { - return (window->IsVisible() && !window->GetWindowState()->IsMinimized() && - !IsPopupOrTransient(window)); -} - -void UndockWindow(WmWindow* window) { - gfx::Rect previous_bounds = window->GetBounds(); - WmWindow* old_parent = window->GetParent(); - window->SetParentUsingContext(window, gfx::Rect()); - if (window->GetParent() != old_parent) { - wm::ReparentTransientChildrenOfChild(window, old_parent, - window->GetParent()); - } - // Start maximize or fullscreen (affecting packaged apps) animation from - // previous window bounds. - window->GetLayer()->SetBounds(previous_bounds); -} - -// Returns width that is as close as possible to |target_width| while being -// consistent with docked min and max restrictions and respects the |window|'s -// minimum and maximum size. -int GetWindowWidthCloseTo(const WmWindow* window, int target_width) { - if (!window->GetWindowState()->CanResize()) { - DCHECK_LE(window->GetBounds().width(), - DockedWindowLayoutManager::kMaxDockWidth); - return window->GetBounds().width(); - } - int width = std::max( - DockedWindowLayoutManager::kMinDockWidth, - std::min(target_width, DockedWindowLayoutManager::kMaxDockWidth)); - width = std::max(width, window->GetMinimumSize().width()); - if (window->GetMaximumSize().width() != 0) - width = std::min(width, window->GetMaximumSize().width()); - DCHECK_LE(width, DockedWindowLayoutManager::kMaxDockWidth); - return width; -} - -// Returns height that is as close as possible to |target_height| while -// respecting the |window|'s minimum and maximum size. -int GetWindowHeightCloseTo(const WmWindow* window, int target_height) { - if (!window->GetWindowState()->CanResize()) - return window->GetBounds().height(); - int minimum_height = - std::max(kMinimumHeight, window->GetMinimumSize().height()); - int maximum_height = window->GetMaximumSize().height(); - if (minimum_height) - target_height = std::max(target_height, minimum_height); - if (maximum_height) - target_height = std::min(target_height, maximum_height); - return target_height; -} - -} // namespace - -struct DockedWindowLayoutManager::WindowWithHeight { - explicit WindowWithHeight(WmWindow* window) - : window(window), height(window->GetBounds().height()) {} - WmWindow* window; - int height; -}; - -// A functor used to sort the windows in order of their minimum height. -struct DockedWindowLayoutManager::CompareMinimumHeight { - bool operator()(const WindowWithHeight& win1, const WindowWithHeight& win2) { - return GetWindowHeightCloseTo(win1.window, 0) < - GetWindowHeightCloseTo(win2.window, 0); - } -}; - -// A functor used to sort the windows in order of their center Y position. -// |delta| is a pre-calculated distance from the bottom of one window to the top -// of the next. Its value can be positive (gap) or negative (overlap). -// Half of |delta| is used as a transition point at which windows could ideally -// swap positions. -struct DockedWindowLayoutManager::CompareWindowPos { - CompareWindowPos(WmWindow* dragged_window, - WmWindow* docked_container, - float delta) - : dragged_window_(dragged_window), - docked_container_(docked_container), - delta_(delta / 2) {} - - bool operator()(const WindowWithHeight& window_with_height1, - const WindowWithHeight& window_with_height2) { - // Use target coordinates since animations may be active when windows are - // reordered. - WmWindow* win1(window_with_height1.window); - WmWindow* win2(window_with_height2.window); - gfx::Rect win1_bounds = - docked_container_->ConvertRectToScreen(win1->GetTargetBounds()); - gfx::Rect win2_bounds = - docked_container_->ConvertRectToScreen(win2->GetTargetBounds()); - win1_bounds.set_height(window_with_height1.height); - win2_bounds.set_height(window_with_height2.height); - // If one of the windows is the |dragged_window_| attempt to make an - // earlier swap between the windows than just based on their centers. - // This is possible if the dragged window is at least as tall as the other - // window. - if (win1 == dragged_window_) - return compare_two_windows(win1_bounds, win2_bounds); - if (win2 == dragged_window_) - return !compare_two_windows(win2_bounds, win1_bounds); - // Otherwise just compare the centers. - return win1_bounds.CenterPoint().y() < win2_bounds.CenterPoint().y(); - } - - // Based on center point tries to deduce where the drag is coming from. - // When dragging from below up the transition point is lower. - // When dragging from above down the transition point is higher. - bool compare_bounds(const gfx::Rect& dragged, const gfx::Rect& other) { - if (dragged.CenterPoint().y() < other.CenterPoint().y()) - return dragged.CenterPoint().y() < other.y() - delta_; - return dragged.CenterPoint().y() < other.bottom() + delta_; - } - - // Performs comparison both ways and selects stable result. - bool compare_two_windows(const gfx::Rect& bounds1, const gfx::Rect& bounds2) { - // Try comparing windows in both possible orders and see if the comparison - // is stable. - bool result1 = compare_bounds(bounds1, bounds2); - bool result2 = compare_bounds(bounds2, bounds1); - if (result1 != result2) - return result1; - - // Otherwise it is not possible to be sure that the windows will not bounce. - // In this case just compare the centers. - return bounds1.CenterPoint().y() < bounds2.CenterPoint().y(); - } - - private: - WmWindow* dragged_window_; - WmWindow* docked_container_; - float delta_; -}; - -//////////////////////////////////////////////////////////////////////////////// -// A class that observes shelf for bounds changes. -class DockedWindowLayoutManager::ShelfWindowObserver - : public aura::WindowObserver { - public: - explicit ShelfWindowObserver(DockedWindowLayoutManager* docked_layout_manager) - : docked_layout_manager_(docked_layout_manager) { - DCHECK(docked_layout_manager_->shelf()->GetWindow()); - docked_layout_manager_->shelf()->GetWindow()->aura_window()->AddObserver( - this); - } - - ~ShelfWindowObserver() override { - if (docked_layout_manager_->shelf() && - docked_layout_manager_->shelf()->GetWindow()) { - docked_layout_manager_->shelf() - ->GetWindow() - ->aura_window() - ->RemoveObserver(this); - } - } - - // aura::WindowObserver: - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override { - shelf_bounds_in_screen_ = new_bounds; - ::wm::ConvertRectToScreen(window->parent(), &shelf_bounds_in_screen_); - - // When the shelf is auto-hidden, it has an invisible height of 3px used - // as a hit region which is specific to Chrome OS MD (for non-MD, the 3 - // pixels are visible). In computing the work area we should consider a - // hidden shelf as having a height of 0 (for non-MD, shelf height is 3). - if (docked_layout_manager_->shelf()->GetAutoHideState() == - ShelfAutoHideState::SHELF_AUTO_HIDE_HIDDEN) { - shelf_bounds_in_screen_.set_height( - GetShelfConstant(SHELF_INSETS_FOR_AUTO_HIDE)); - } - docked_layout_manager_->OnShelfBoundsChanged(); - } - - const gfx::Rect& shelf_bounds_in_screen() const { - return shelf_bounds_in_screen_; - } - - private: - DockedWindowLayoutManager* docked_layout_manager_; - gfx::Rect shelf_bounds_in_screen_; - - DISALLOW_COPY_AND_ASSIGN(ShelfWindowObserver); -}; - -//////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager public implementation: -DockedWindowLayoutManager::DockedWindowLayoutManager(WmWindow* dock_container) - : dock_container_(dock_container), - root_window_controller_(dock_container->GetRootWindowController()), - in_layout_(false), - dragged_window_(nullptr), - is_dragged_window_docked_(false), - is_dragged_from_dock_(false), - shelf_(nullptr), - in_fullscreen_(root_window_controller_->GetWorkspaceWindowState() == - wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN), - docked_width_(0), - in_overview_(false), - alignment_(DOCKED_ALIGNMENT_NONE), - preferred_alignment_(DOCKED_ALIGNMENT_NONE), - event_source_(DOCKED_ACTION_SOURCE_UNKNOWN), - last_active_window_(nullptr), - last_action_time_(base::Time::Now()), - background_widget_(nullptr) { - DCHECK(dock_container); - dock_container_->GetShell()->AddShellObserver(this); - dock_container->GetShell()->AddActivationObserver(this); - display::Screen::GetScreen()->AddObserver(this); -} - -DockedWindowLayoutManager::~DockedWindowLayoutManager() { - Shutdown(); -} - -// static -DockedWindowLayoutManager* DockedWindowLayoutManager::Get(WmWindow* window) { - if (!window) - return nullptr; - - WmWindow* root = window->GetRootWindow(); - return static_cast<DockedWindowLayoutManager*>( - root->GetChildByShellWindowId(kShellWindowId_DockedContainer) - ->GetLayoutManager()); -} - -void DockedWindowLayoutManager::Shutdown() { - background_widget_.reset(); - shelf_observer_.reset(); - shelf_ = nullptr; - for (WmWindow* child : dock_container_->GetChildren()) { - child->aura_window()->RemoveObserver(this); - child->GetWindowState()->RemoveObserver(this); - } - dock_container_->GetShell()->RemoveActivationObserver(this); - dock_container_->GetShell()->RemoveShellObserver(this); - display::Screen::GetScreen()->RemoveObserver(this); -} - -void DockedWindowLayoutManager::AddObserver( - DockedWindowLayoutManagerObserver* observer) { - observer_list_.AddObserver(observer); -} - -void DockedWindowLayoutManager::RemoveObserver( - DockedWindowLayoutManagerObserver* observer) { - observer_list_.RemoveObserver(observer); -} - -void DockedWindowLayoutManager::StartDragging(WmWindow* window) { - DCHECK(!dragged_window_); - dragged_window_ = window; - DCHECK(!IsPopupOrTransient(window)); - // Start observing a window unless it is docked container's child in which - // case it is already observed. - wm::WindowState* dragged_state = dragged_window_->GetWindowState(); - if (dragged_window_->GetParent() != dock_container_) { - dragged_window_->aura_window()->AddObserver(this); - dragged_state->AddObserver(this); - } else if (!IsAnyWindowDocked() && dragged_state->drag_details() && - !(dragged_state->drag_details()->bounds_change & - WindowResizer::kBoundsChange_Resizes)) { - // If there are no other docked windows clear alignment when a docked window - // is moved (but not when it is resized or the window could get undocked - // when resized away from the edge while docked). - alignment_ = DOCKED_ALIGNMENT_NONE; - } - is_dragged_from_dock_ = window->GetParent() == dock_container_; - DCHECK(!is_dragged_window_docked_); - - // Resize all windows that are flush with the dock edge together if one of - // them gets resized. - if (dragged_window_->GetBounds().width() == docked_width_ && - (dragged_state->drag_details()->bounds_change & - WindowResizer::kBoundsChange_Resizes) && - (dragged_state->drag_details()->size_change_direction & - WindowResizer::kBoundsChangeDirection_Horizontal)) { - for (WmWindow* window1 : dock_container_->GetChildren()) { - if (IsWindowDocked(window1) && window1 != dragged_window_ && - window1->GetBounds().width() == docked_width_) { - window1->GetWindowState()->set_bounds_changed_by_user(false); - } - } - } -} - -void DockedWindowLayoutManager::DockDraggedWindow(WmWindow* window) { - DCHECK(!IsPopupOrTransient(window)); - OnDraggedWindowDocked(window); - Relayout(); -} - -void DockedWindowLayoutManager::UndockDraggedWindow() { - DCHECK(!IsPopupOrTransient(dragged_window_)); - OnDraggedWindowUndocked(); - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); - is_dragged_from_dock_ = false; -} - -void DockedWindowLayoutManager::FinishDragging(DockedAction action, - DockedActionSource source) { - DCHECK(dragged_window_); - DCHECK(!IsPopupOrTransient(dragged_window_)); - if (is_dragged_window_docked_) - OnDraggedWindowUndocked(); - DCHECK(!is_dragged_window_docked_); - // Stop observing a window unless it is docked container's child in which - // case it needs to keep being observed after the drag completes. - if (dragged_window_->GetParent() != dock_container_) { - dragged_window_->aura_window()->RemoveObserver(this); - dragged_window_->GetWindowState()->RemoveObserver(this); - if (last_active_window_ == dragged_window_) - last_active_window_ = nullptr; - } else { - // If this is the first window that got docked by a move update alignment. - if (alignment_ == DOCKED_ALIGNMENT_NONE) - alignment_ = GetEdgeNearestWindow(dragged_window_); - // A window is no longer dragged and is a child. - // When a window becomes a child at drag start this is - // the only opportunity we will have to enforce a window - // count limit so do it here. - MaybeMinimizeChildrenExcept(dragged_window_); - } - dragged_window_ = nullptr; - dragged_bounds_ = gfx::Rect(); - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); - RecordUmaAction(action, source); -} - -void DockedWindowLayoutManager::SetShelf(WmShelf* shelf) { - DCHECK(!shelf_); - shelf_ = shelf; - shelf_observer_.reset(new ShelfWindowObserver(this)); -} - -DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow( - const WmWindow* window) const { - const gfx::Rect& bounds(window->GetBoundsInScreen()); - - // Test overlap with an existing docked area first. - if (docked_bounds_.Intersects(bounds) && - alignment_ != DOCKED_ALIGNMENT_NONE) { - // A window is being added to other docked windows (on the same side). - return alignment_; - } - - const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen(); - if (bounds.x() <= container_bounds.x() && - bounds.right() > container_bounds.x()) { - return DOCKED_ALIGNMENT_LEFT; - } else if (bounds.x() < container_bounds.right() && - bounds.right() >= container_bounds.right()) { - return DOCKED_ALIGNMENT_RIGHT; - } - return DOCKED_ALIGNMENT_NONE; -} - -DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const { - return CalculateAlignmentExcept(dragged_window_); -} - -DockedAlignment DockedWindowLayoutManager::CalculateAlignmentExcept( - const WmWindow* window) const { - // Find a child that is not the window being queried and is not a popup. - // If such exists the current alignment is returned - even if some of the - // children are hidden or minimized (so they can be restored without losing - // the docked state). - for (WmWindow* child : dock_container_->GetChildren()) { - if (window != child && !IsPopupOrTransient(child)) - return alignment_; - } - // No docked windows remain other than possibly the window being queried. - // Return |NONE| to indicate that windows may get docked on either side. - return DOCKED_ALIGNMENT_NONE; -} - -bool DockedWindowLayoutManager::CanDockWindow( - WmWindow* window, - DockedAlignment desired_alignment) { - // Don't allow interactive docking of windows with transient parents such as - // modal browser dialogs. Prevent docking of panels attached to shelf during - // the drag. - wm::WindowState* window_state = window->GetWindowState(); - bool should_attach_to_shelf = - window_state->drag_details() && - window_state->drag_details()->should_attach_to_shelf; - if (IsPopupOrTransient(window) || should_attach_to_shelf) - return false; - // If a window is wide and cannot be resized down to maximum width allowed - // then it cannot be docked. - // TODO(varkha). Prevent windows from changing size programmatically while - // they are docked. The size will take effect only once a window is undocked. - // See http://crbug.com/307792. - if (window->GetBounds().width() > kMaxDockWidth && - (!window_state->CanResize() || - (window->GetMinimumSize().width() != 0 && - window->GetMinimumSize().width() > kMaxDockWidth))) { - return false; - } - // If a window is tall and cannot be resized down to maximum height allowed - // then it cannot be docked. - const gfx::Rect work_area = - dock_container_->GetDisplayNearestWindow().work_area(); - if (GetWindowHeightCloseTo(window, work_area.height()) > work_area.height()) - return false; - // Cannot dock on the other size from an existing dock. - const DockedAlignment alignment = CalculateAlignmentExcept(window); - if (desired_alignment != DOCKED_ALIGNMENT_NONE && - alignment != DOCKED_ALIGNMENT_NONE && alignment != desired_alignment) { - return false; - } - // Do not allow docking on the same side as shelf. - return IsDockedAlignmentValid(desired_alignment); -} - -bool DockedWindowLayoutManager::IsDockedAlignmentValid( - DockedAlignment alignment) const { - ShelfAlignment shelf_alignment = - shelf_ ? shelf_->GetAlignment() : SHELF_ALIGNMENT_BOTTOM; - if ((alignment == DOCKED_ALIGNMENT_LEFT && - shelf_alignment == SHELF_ALIGNMENT_LEFT) || - (alignment == DOCKED_ALIGNMENT_RIGHT && - shelf_alignment == SHELF_ALIGNMENT_RIGHT)) { - return false; - } - return true; -} - -void DockedWindowLayoutManager::MaybeSetDesiredDockedAlignment( - DockedAlignment alignment) { - // If the requested alignment is |NONE| or there are no - // docked windows return early as we can't change whether there is a - // dock or not. If the requested alignment is the same as the current - // alignment return early as an optimization. - if (alignment == DOCKED_ALIGNMENT_NONE || - alignment_ == DOCKED_ALIGNMENT_NONE || alignment_ == alignment || - !IsDockedAlignmentValid(alignment)) { - return; - } - alignment_ = alignment; - - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - -void DockedWindowLayoutManager::OnShelfBoundsChanged() { - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_INSETS_CHANGED); -} - -//////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, aura::LayoutManager implementation: -void DockedWindowLayoutManager::OnWindowResized() { - MaybeMinimizeChildrenExcept(dragged_window_); - Relayout(); - // When screen resizes update the insets even when dock width or alignment - // does not change. - UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_RESIZED); -} - -void DockedWindowLayoutManager::OnWindowAddedToLayout(WmWindow* child) { - if (IsPopupOrTransient(child)) - return; - // Dragged windows are already observed by StartDragging and do not change - // docked alignment during the drag. - if (child == dragged_window_) - return; - // If this is the first window getting docked - update alignment. - // A window can be added without proper bounds when window is moved to another - // display via API or due to display configuration change, so the alignment - // is set based on which edge is closer in the new display. - if (alignment_ == DOCKED_ALIGNMENT_NONE) { - alignment_ = preferred_alignment_ != DOCKED_ALIGNMENT_NONE - ? preferred_alignment_ - : GetEdgeNearestWindow(child); - } - MaybeMinimizeChildrenExcept(child); - child->aura_window()->AddObserver(this); - child->GetWindowState()->AddObserver(this); - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); - - // Only keyboard-initiated actions are recorded here. Dragging cases - // are handled in FinishDragging. - if (event_source_ != DOCKED_ACTION_SOURCE_UNKNOWN) - RecordUmaAction(DOCKED_ACTION_DOCK, event_source_); -} - -void DockedWindowLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) { - if (IsPopupOrTransient(child)) - return; - // Dragged windows are stopped being observed by FinishDragging and do not - // change alignment during the drag. They also cannot be set to be the - // |last_active_window_|. - if (child == dragged_window_) - return; - // If this is the last window, set alignment and maximize the workspace. - if (!IsAnyWindowDocked()) { - alignment_ = DOCKED_ALIGNMENT_NONE; - UpdateDockedWidth(0); - } - if (last_active_window_ == child) - last_active_window_ = nullptr; - child->aura_window()->RemoveObserver(this); - child->GetWindowState()->RemoveObserver(this); - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - -void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) { - if (IsPopupOrTransient(child)) - return; - - wm::WindowState* window_state = child->GetWindowState(); - if (visible && window_state->IsMinimized()) - window_state->Restore(); - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - -void DockedWindowLayoutManager::SetChildBounds( - WmWindow* child, - const gfx::Rect& requested_bounds) { - // The minimum constraints have to be applied first by the layout manager. - gfx::Rect actual_new_bounds(requested_bounds); - if (child->HasNonClientArea()) { - const gfx::Size min_size = child->GetMinimumSize(); - actual_new_bounds.set_width( - std::max(min_size.width(), actual_new_bounds.width())); - actual_new_bounds.set_height( - std::max(min_size.height(), actual_new_bounds.height())); - } - if (IsWindowDocked(child) && child != dragged_window_) - return; - wm::WmSnapToPixelLayoutManager::SetChildBounds(child, actual_new_bounds); - if (IsPopupOrTransient(child)) - return; - // Whenever one of our windows is moved or resized enforce layout. - if (shelf_) - shelf_->UpdateVisibilityState(); -} - -//////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, display::DisplayObserver implementation: - -void DockedWindowLayoutManager::OnDisplayMetricsChanged( - const display::Display& display, - uint32_t changed_metrics) { - if (dock_container_->GetDisplayNearestWindow().id() != display.id()) - return; - - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::DISPLAY_INSETS_CHANGED); - MaybeMinimizeChildrenExcept(dragged_window_); -} - -///////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, WindowStateObserver implementation: - -void DockedWindowLayoutManager::OnPreWindowStateTypeChange( - wm::WindowState* window_state, - wm::WindowStateType old_type) { - WmWindow* window = window_state->window(); - if (IsPopupOrTransient(window)) - return; - // The window property will still be set, but no actual change will occur - // until OnFullscreenStateChange is called when exiting fullscreen. - if (in_fullscreen_) - return; - if (!window_state->IsDocked()) { - if (window != dragged_window_) { - UndockWindow(window); - if (window_state->IsMaximizedOrFullscreenOrPinned()) - RecordUmaAction(DOCKED_ACTION_MAXIMIZE, event_source_); - else - RecordUmaAction(DOCKED_ACTION_UNDOCK, event_source_); - } - } else if (window_state->IsMinimized()) { - MinimizeDockedWindow(window_state); - } else if (old_type == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED) { - RestoreDockedWindow(window_state); - } else if (old_type == wm::WINDOW_STATE_TYPE_MINIMIZED) { - NOTREACHED() << "Minimized window in docked layout manager"; - } -} - -///////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, WindowObserver implementation: - -void DockedWindowLayoutManager::OnWindowBoundsChanged( - aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - // Only relayout if the dragged window would get docked. - if (WmWindow::Get(window) == dragged_window_ && is_dragged_window_docked_) - Relayout(); -} - -void DockedWindowLayoutManager::OnWindowVisibilityChanging(aura::Window* window, - bool visible) { - if (IsPopupOrTransient(WmWindow::Get(window))) - return; - int animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT; - if (visible) { - animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DROP; - ::wm::SetWindowVisibilityAnimationDuration( - window, base::TimeDelta::FromMilliseconds(kFadeDurationMs)); - } else if (wm::GetWindowState(window)->IsMinimized()) { - animation_type = wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE; - } - ::wm::SetWindowVisibilityAnimationType(window, animation_type); -} - -void DockedWindowLayoutManager::OnWindowDestroying(aura::Window* window) { - if (dragged_window_ == WmWindow::Get(window)) { - FinishDragging(DOCKED_ACTION_NONE, DOCKED_ACTION_SOURCE_UNKNOWN); - DCHECK(!dragged_window_); - DCHECK(!is_dragged_window_docked_); - } - if (WmWindow::Get(window) == last_active_window_) - last_active_window_ = nullptr; - RecordUmaAction(DOCKED_ACTION_CLOSE, event_source_); -} - -//////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, WmActivationObserver implementation: - -void DockedWindowLayoutManager::OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) { - if (gained_active && IsPopupOrTransient(gained_active)) - return; - // Ignore if the window that is not managed by this was activated. - WmWindow* ancestor = nullptr; - for (WmWindow* parent = gained_active; parent; parent = parent->GetParent()) { - if (parent->GetParent() == dock_container_) { - ancestor = parent; - break; - } - } - if (ancestor) { - // Window activation from overview mode may unminimize a window and require - // layout update. - MaybeMinimizeChildrenExcept(gained_active); - Relayout(); - UpdateStacking(ancestor); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager, ShellObserver implementation: - -void DockedWindowLayoutManager::OnShelfAlignmentChanged(WmWindow* root_window) { - if (!shelf_ || alignment_ == DOCKED_ALIGNMENT_NONE || - root_window != shelf_->GetWindow()->GetRootWindow()) { - return; - } - - // Do not allow shelf and dock on the same side. Switch side that - // the dock is attached to and move all dock windows to that new side. - ShelfAlignment shelf_alignment = shelf_->GetAlignment(); - if (alignment_ == DOCKED_ALIGNMENT_LEFT && - shelf_alignment == SHELF_ALIGNMENT_LEFT) { - alignment_ = DOCKED_ALIGNMENT_RIGHT; - } else if (alignment_ == DOCKED_ALIGNMENT_RIGHT && - shelf_alignment == SHELF_ALIGNMENT_RIGHT) { - alignment_ = DOCKED_ALIGNMENT_LEFT; - } - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::SHELF_ALIGNMENT_CHANGED); -} - -void DockedWindowLayoutManager::OnFullscreenStateChanged( - bool is_fullscreen, - WmWindow* root_window) { - if (root_window != dock_container_->GetRootWindow()) - return; - - // Entering fullscreen mode (including immersive) hides docked windows. - in_fullscreen_ = root_window_controller_->GetWorkspaceWindowState() == - wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN; - { - // prevent Relayout from getting called multiple times during this - base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); - // Use a copy of children array because a call to MinimizeDockedWindow or - // RestoreDockedWindow can change order. - for (WmWindow* window : dock_container_->GetChildren()) { - if (IsPopupOrTransient(window)) - continue; - wm::WindowState* window_state = window->GetWindowState(); - if (in_fullscreen_) { - if (window->IsVisible()) - MinimizeDockedWindow(window_state); - } else { - if (!window_state->IsMinimized()) - RestoreDockedWindow(window_state); - } - } - } - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - -void DockedWindowLayoutManager::OnOverviewModeStarting() { - in_overview_ = true; - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - -void DockedWindowLayoutManager::OnOverviewModeEnded() { - in_overview_ = false; - UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED); -} - -//////////////////////////////////////////////////////////////////////////////// -// DockedWindowLayoutManager private implementation: - -void DockedWindowLayoutManager::MaybeMinimizeChildrenExcept(WmWindow* child) { - WindowSelectorController* window_selector_controller = - WmShell::Get()->window_selector_controller(); - if (window_selector_controller->IsRestoringMinimizedWindows()) - return; - // Minimize any windows that don't fit without overlap. - const gfx::Rect work_area = - dock_container_->GetDisplayNearestWindow().work_area(); - int available_room = work_area.height(); - bool gap_needed = !!child; - if (child) - available_room -= GetWindowHeightCloseTo(child, 0); - // Use a copy of children array because a call to Minimize can change order. - std::vector<WmWindow*> children(dock_container_->GetChildren()); - for (auto iter = children.rbegin(); iter != children.rend(); ++iter) { - WmWindow* window(*iter); - if (window == child || !IsWindowDocked(window)) - continue; - int room_needed = - GetWindowHeightCloseTo(window, 0) + (gap_needed ? kMinDockGap : 0); - gap_needed = true; - if (available_room > room_needed) { - available_room -= room_needed; - } else { - // Slow down minimizing animations. Lock duration so that it is not - // overridden by other ScopedLayerAnimationSettings down the stack. - ui::ScopedLayerAnimationSettings settings( - window->GetLayer()->GetAnimator()); - settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kMinimizeDurationMs)); - settings.LockTransitionDuration(); - window->GetWindowState()->Minimize(); - } - } -} - -void DockedWindowLayoutManager::MinimizeDockedWindow( - wm::WindowState* window_state) { - DCHECK(!IsPopupOrTransient(window_state->window())); - window_state->window()->Hide(); - if (window_state->IsActive()) - window_state->Deactivate(); - RecordUmaAction(DOCKED_ACTION_MINIMIZE, event_source_); -} - -void DockedWindowLayoutManager::RestoreDockedWindow( - wm::WindowState* window_state) { - WmWindow* window = window_state->window(); - DCHECK(!IsPopupOrTransient(window)); - - // Evict the window if it can no longer be docked because of its height. - if (!CanDockWindow(window, DOCKED_ALIGNMENT_NONE)) { - window_state->Restore(); - RecordUmaAction(DOCKED_ACTION_EVICT, event_source_); - return; - } - - // Always place restored window at the bottom shuffling the other windows up. - // TODO(varkha): add a separate container for docked windows to keep track - // of ordering. - const gfx::Rect work_area = - dock_container_->GetDisplayNearestWindow().work_area(); - gfx::Rect bounds(window->GetBounds()); - bounds.set_y(work_area.bottom()); - window->SetBounds(bounds); - window->Show(); - MaybeMinimizeChildrenExcept(window); - RecordUmaAction(DOCKED_ACTION_RESTORE, event_source_); -} - -void DockedWindowLayoutManager::RecordUmaAction(DockedAction action, - DockedActionSource source) { - if (action == DOCKED_ACTION_NONE) - return; - UMA_HISTOGRAM_ENUMERATION("Ash.Dock.Action", action, DOCKED_ACTION_COUNT); - UMA_HISTOGRAM_ENUMERATION("Ash.Dock.ActionSource", source, - DOCKED_ACTION_SOURCE_COUNT); - base::Time time_now = base::Time::Now(); - base::TimeDelta time_between_use = time_now - last_action_time_; - UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.Dock.TimeBetweenUse", - time_between_use.InSeconds(), 1, - base::TimeDelta::FromHours(10).InSeconds(), 100); - last_action_time_ = time_now; - int docked_all_count = 0; - int docked_visible_count = 0; - int docked_panels_count = 0; - int large_windows_count = 0; - for (WmWindow* window : dock_container_->GetChildren()) { - if (IsPopupOrTransient(window)) - continue; - docked_all_count++; - if (!IsWindowDocked(window)) - continue; - docked_visible_count++; - if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL) - docked_panels_count++; - const wm::WindowState* window_state = window->GetWindowState(); - if (window_state->HasRestoreBounds()) { - const gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); - if (restore_bounds.width() > kMaxDockWidth) - large_windows_count++; - } - } - UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsAll", docked_all_count); - UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsLarge", large_windows_count); - UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsPanels", docked_panels_count); - UMA_HISTOGRAM_COUNTS_100("Ash.Dock.ItemsVisible", docked_visible_count); -} - -void DockedWindowLayoutManager::UpdateDockedWidth(int width) { - if (docked_width_ == width) - return; - docked_width_ = width; - UMA_HISTOGRAM_COUNTS_10000("Ash.Dock.Width", docked_width_); -} - -void DockedWindowLayoutManager::OnDraggedWindowDocked(WmWindow* window) { - DCHECK(!is_dragged_window_docked_); - is_dragged_window_docked_ = true; -} - -void DockedWindowLayoutManager::OnDraggedWindowUndocked() { - DCHECK(is_dragged_window_docked_); - is_dragged_window_docked_ = false; -} - -bool DockedWindowLayoutManager::IsAnyWindowDocked() { - return CalculateAlignment() != DOCKED_ALIGNMENT_NONE; -} - -DockedAlignment DockedWindowLayoutManager::GetEdgeNearestWindow( - const WmWindow* window) const { - const gfx::Rect bounds(window->GetBoundsInScreen()); - const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen(); - // Give one pixel preference for docking on the right side to a window that - // has odd width and is centered in a screen that has even width (or vice - // versa). This only matters to the tests but could be a source of flakiness. - return (abs(bounds.x() - container_bounds.x()) + 1 < - abs(bounds.right() - container_bounds.right())) - ? DOCKED_ALIGNMENT_LEFT - : DOCKED_ALIGNMENT_RIGHT; -} - -void DockedWindowLayoutManager::Relayout() { - // Suppress layouts during overview mode while restoring minimized windows so - // that docked animations are not interfering with the overview mode. - WindowSelectorController* window_selector_controller = - WmShell::Get()->window_selector_controller(); - if (in_layout_ || (window_selector_controller->IsRestoringMinimizedWindows())) - return; - if (alignment_ == DOCKED_ALIGNMENT_NONE && !is_dragged_window_docked_) - return; - base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); - - WmWindow* active_window = nullptr; - std::vector<WindowWithHeight> visible_windows; - for (WmWindow* window : dock_container_->GetChildren()) { - if (!IsWindowDocked(window) || window == dragged_window_) - continue; - - // If the shelf is currently hidden (full-screen mode), hide window until - // full-screen mode is exited. - if (in_fullscreen_) { - // The call to Hide does not set the minimize property, so the window will - // be restored when the shelf becomes visible again. - window->Hide(); - continue; - } - if (window->IsFocused() || - window->Contains(window->GetShell()->GetFocusedWindow())) { - DCHECK(!active_window); - active_window = window; - } - visible_windows.push_back(WindowWithHeight(window)); - } - // Consider docked dragged_window_ when fanning out other child windows. - if (is_dragged_window_docked_) { - visible_windows.push_back(WindowWithHeight(dragged_window_)); - DCHECK(!active_window); - active_window = dragged_window_; - } - - // Position docked windows as well as the window being dragged. - gfx::Rect work_area = dock_container_->GetDisplayNearestWindow().work_area(); - if (shelf_observer_) - work_area.Subtract(shelf_observer_->shelf_bounds_in_screen()); - int available_room = - CalculateWindowHeightsAndRemainingRoom(work_area, &visible_windows); - FanOutChildren(work_area, CalculateIdealWidth(visible_windows), - available_room, &visible_windows); - - // After the first Relayout allow the windows to change their order easier - // since we know they are docked. - is_dragged_from_dock_ = true; - UpdateStacking(active_window); -} - -int DockedWindowLayoutManager::CalculateWindowHeightsAndRemainingRoom( - const gfx::Rect& work_area, - std::vector<WindowWithHeight>* visible_windows) { - int available_room = work_area.height(); - int remaining_windows = visible_windows->size(); - int gap_height = remaining_windows > 1 ? kMinDockGap : 0; - - // Sort windows by their minimum heights and calculate target heights. - std::sort(visible_windows->begin(), visible_windows->end(), - CompareMinimumHeight()); - // Distribute the free space among the docked windows. Since the windows are - // sorted (tall windows first) we can now assume that any window which - // required more space than the current window will have already been - // accounted for previously in this loop, so we can safely give that window - // its proportional share of the remaining space. - for (std::vector<WindowWithHeight>::reverse_iterator iter = - visible_windows->rbegin(); - iter != visible_windows->rend(); ++iter) { - iter->height = GetWindowHeightCloseTo( - iter->window, - (available_room + gap_height) / remaining_windows - gap_height); - available_room -= (iter->height + gap_height); - remaining_windows--; - } - return available_room + gap_height; -} - -int DockedWindowLayoutManager::CalculateIdealWidth( - const std::vector<WindowWithHeight>& visible_windows) { - int smallest_max_width = kMaxDockWidth; - int largest_min_width = kMinDockWidth; - // Ideal width of the docked area is as close to kIdealWidth as possible - // while still respecting the minimum and maximum width restrictions on the - // individual docked windows as well as the width that was possibly set by a - // user (which needs to be preserved when dragging and rearranging windows). - for (std::vector<WindowWithHeight>::const_iterator iter = - visible_windows.begin(); - iter != visible_windows.end(); ++iter) { - const WmWindow* window = iter->window; - int min_window_width = window->GetBounds().width(); - int max_window_width = min_window_width; - if (!window->GetWindowState()->bounds_changed_by_user()) { - min_window_width = GetWindowWidthCloseTo(window, kMinDockWidth); - max_window_width = GetWindowWidthCloseTo(window, kMaxDockWidth); - } - largest_min_width = std::max(largest_min_width, min_window_width); - smallest_max_width = std::min(smallest_max_width, max_window_width); - } - int ideal_width = - std::max(largest_min_width, std::min(smallest_max_width, kIdealWidth)); - // Restrict docked area width regardless of window restrictions. - ideal_width = std::max(std::min(ideal_width, kMaxDockWidth), kMinDockWidth); - return ideal_width; -} - -void DockedWindowLayoutManager::FanOutChildren( - const gfx::Rect& work_area, - int ideal_docked_width, - int available_room, - std::vector<WindowWithHeight>* visible_windows) { - gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen(); - - // Calculate initial vertical offset and the gap or overlap between windows. - const int num_windows = visible_windows->size(); - const float delta = - static_cast<float>(available_room) / - ((available_room > 0 || num_windows <= 1) ? num_windows + 1 - : num_windows - 1); - float y_pos = work_area.y() + ((delta > 0) ? delta : 0); - - // Docked area is shown only if there is at least one non-dragged visible - // docked window. - int new_width = ideal_docked_width; - if (visible_windows->empty() || - (visible_windows->size() == 1 && - (*visible_windows)[0].window == dragged_window_)) { - new_width = 0; - } - UpdateDockedWidth(new_width); - // Sort windows by their center positions and fan out overlapping - // windows. - std::sort(visible_windows->begin(), visible_windows->end(), - CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : nullptr, - dock_container_, delta)); - for (std::vector<WindowWithHeight>::iterator iter = visible_windows->begin(); - iter != visible_windows->end(); ++iter) { - WmWindow* window = iter->window; - gfx::Rect bounds = - dock_container_->ConvertRectToScreen(window->GetTargetBounds()); - // A window is extended or shrunk to be as close as possible to the ideal - // docked area width. Windows that were resized by a user are kept at their - // existing size. - // This also enforces the min / max restrictions on the docked area width. - bounds.set_width(GetWindowWidthCloseTo( - window, window->GetWindowState()->bounds_changed_by_user() - ? bounds.width() - : ideal_docked_width)); - DCHECK_LE(bounds.width(), ideal_docked_width); - - DockedAlignment alignment = alignment_; - if (alignment == DOCKED_ALIGNMENT_NONE && window == dragged_window_) - alignment = GetEdgeNearestWindow(window); - - // Fan out windows evenly distributing the overlap or remaining free space. - bounds.set_height(iter->height); - bounds.set_y( - std::max(work_area.y(), std::min(work_area.bottom() - bounds.height(), - static_cast<int>(y_pos + 0.5)))); - y_pos += bounds.height() + delta + kMinDockGap; - - // All docked windows other than the one currently dragged remain stuck - // to the screen edge (flush with the edge or centered in the dock area). - switch (alignment) { - case DOCKED_ALIGNMENT_LEFT: - bounds.set_x(dock_bounds.x() + - (ideal_docked_width - bounds.width()) / 2); - break; - case DOCKED_ALIGNMENT_RIGHT: - bounds.set_x(dock_bounds.right() - - (ideal_docked_width + bounds.width()) / 2); - break; - case DOCKED_ALIGNMENT_NONE: - break; - } - if (window == dragged_window_) { - dragged_bounds_ = bounds; - continue; - } - // If the following asserts it is probably because not all the children - // have been removed when dock was closed. - DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE); - bounds = dock_container_->ConvertRectFromScreen(bounds); - if (bounds != window->GetTargetBounds()) { - ui::Layer* layer = window->GetLayer(); - ui::ScopedLayerAnimationSettings slide_settings(layer->GetAnimator()); - slide_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - slide_settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kSlideDurationMs)); - window->SetBoundsDirect(bounds); - } - } -} - -void DockedWindowLayoutManager::UpdateDockBounds( - DockedWindowLayoutManagerObserver::Reason reason) { - int docked_width = in_overview_ ? 0 : docked_width_; - int dock_inset = docked_width + (docked_width > 0 ? kMinDockGap : 0); - const gfx::Rect work_area = - dock_container_->GetDisplayNearestWindow().work_area(); - gfx::Rect bounds = gfx::Rect( - alignment_ == DOCKED_ALIGNMENT_RIGHT && dock_inset > 0 - ? dock_container_->GetBounds().right() - dock_inset - : dock_container_->GetBounds().x(), - dock_container_->GetBounds().y(), dock_inset, work_area.height()); - docked_bounds_ = - bounds + dock_container_->GetBoundsInScreen().OffsetFromOrigin(); - for (auto& observer : observer_list_) - observer.OnDockBoundsChanging(bounds, reason); - // Show or hide background for docked area. - gfx::Rect background_bounds(docked_bounds_); - if (shelf_observer_) - background_bounds.Subtract(shelf_observer_->shelf_bounds_in_screen()); - if (docked_width > 0) { - // TODO: |shelf_| should not be null by the time we get here, but it may - // be in mash as startup sequence doesn't yet match that of ash. Once - // |shelf_| is created at same time as ash we can remove conditional. - // http://crbug.com/632099 - if (shelf_) { - if (!background_widget_) - background_widget_.reset(new DockedBackgroundWidget(this)); - background_widget_->SetBackgroundBounds(background_bounds, alignment_); - background_widget_->Show(); - } - } else if (background_widget_) { - background_widget_->Hide(); - } -} - -void DockedWindowLayoutManager::UpdateStacking(WmWindow* active_window) { - if (!active_window) { - if (!last_active_window_) - return; - active_window = last_active_window_; - } - - // Windows are stacked like a deck of cards: - // ,------. - // |,------.| - // |,------.| - // | active | - // | window | - // |`------'| - // |`------'| - // `------' - // Use the middle of each window to figure out how to stack the window. - // This allows us to update the stacking when a window is being dragged around - // by the titlebar. - std::map<int, WmWindow*> window_ordering; - for (WmWindow* child : dock_container_->GetChildren()) { - if (!IsWindowDocked(child) || - (child == dragged_window_ && !is_dragged_window_docked_)) { - continue; - } - gfx::Rect bounds = child->GetBounds(); - window_ordering.insert( - std::make_pair(bounds.y() + bounds.height() / 2, child)); - } - int active_center_y = active_window->GetBounds().CenterPoint().y(); - - WmWindow* previous_window = nullptr; - for (std::map<int, WmWindow*>::const_iterator it = window_ordering.begin(); - it != window_ordering.end() && it->first < active_center_y; ++it) { - if (previous_window) - dock_container_->StackChildAbove(it->second, previous_window); - previous_window = it->second; - } - for (std::map<int, WmWindow*>::const_reverse_iterator it = - window_ordering.rbegin(); - it != window_ordering.rend() && it->first > active_center_y; ++it) { - if (previous_window) - dock_container_->StackChildAbove(it->second, previous_window); - previous_window = it->second; - } - - if (previous_window && active_window->GetParent() == dock_container_) - dock_container_->StackChildAbove(active_window, previous_window); - if (active_window != dragged_window_) - last_active_window_ = active_window; -} - -//////////////////////////////////////////////////////////////////////////////// -// keyboard::KeyboardControllerObserver implementation: - -void DockedWindowLayoutManager::OnKeyboardBoundsChanging( - const gfx::Rect& keyboard_bounds) { - // This bounds change will have caused a change to the Shelf which does not - // propagate automatically to this class, so manually recalculate bounds. - Relayout(); - UpdateDockBounds(DockedWindowLayoutManagerObserver::KEYBOARD_BOUNDS_CHANGING); -} - -void DockedWindowLayoutManager::OnKeyboardClosed() {} - -} // namespace ash
diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h deleted file mode 100644 index 956a21c..0000000 --- a/ash/wm/dock/docked_window_layout_manager.h +++ /dev/null
@@ -1,322 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ -#define ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_activation_observer.h" -#include "ash/wm/dock/dock_types.h" -#include "ash/wm/dock/docked_window_layout_manager_observer.h" -#include "ash/wm/window_state_observer.h" -#include "ash/wm/wm_snap_to_pixel_layout_manager.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/time/time.h" -#include "ui/aura/window_observer.h" -#include "ui/display/display_observer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace ash { -class DockedBackgroundWidget; -class DockedWindowLayoutManagerObserver; -class DockedWindowResizerTest; -class RootWindowController; -class WmShelf; - -// DockedWindowLayoutManager is responsible for organizing windows when they are -// docked to the side of a screen. It is associated with a specific container -// window (i.e. kShellWindowId_DockedContainer) and controls the layout of any -// windows added to that container. -// -// The constructor takes a |dock_container| argument which is expected to set -// its layout manager to this instance, e.g.: -// dock_container->SetLayoutManager( -// new DockedWindowLayoutManager(dock_container)); -// -// TODO(varkha): extend BaseLayoutManager instead of LayoutManager to inherit -// common functionality. -class ASH_EXPORT DockedWindowLayoutManager - : public wm::WmSnapToPixelLayoutManager, - public display::DisplayObserver, - public aura::WindowObserver, - public WmActivationObserver, - public ShellObserver, - public keyboard::KeyboardControllerObserver, - public wm::WindowStateObserver { - public: - // Maximum width of the docked windows area. - static const int kMaxDockWidth; - - // Minimum width of the docked windows area. - static const int kMinDockWidth; - - explicit DockedWindowLayoutManager(WmWindow* dock_container); - ~DockedWindowLayoutManager() override; - - // Returns the DockedWindowLayoutManager in the specified hierarchy. This - // searches from the root of |window|. - static DockedWindowLayoutManager* Get(WmWindow* window); - - // Disconnects observers before container windows get destroyed. - void Shutdown(); - - // Management of the observer list. - virtual void AddObserver(DockedWindowLayoutManagerObserver* observer); - virtual void RemoveObserver(DockedWindowLayoutManagerObserver* observer); - - // Called by a DockedWindowResizer to update which window is being dragged. - // Starts observing the window unless it is a child. - void StartDragging(WmWindow* window); - - // Called by a DockedWindowResizer when a dragged window is docked. - void DockDraggedWindow(WmWindow* window); - - // Called by a DockedWindowResizer when a dragged window is no longer docked. - void UndockDraggedWindow(); - - // Called by a DockedWindowResizer when a window is no longer being dragged. - // Stops observing the window unless it is a child. - // Records |action| by |source| in UMA. - void FinishDragging(DockedAction action, DockedActionSource source); - - // Checks the rules and possibly updates the docked layout to match - // the |alignment|. May not apply the |alignment| when - // the current shelf alignment conflicts. Never clears the |alignment_|. - void MaybeSetDesiredDockedAlignment(DockedAlignment alignment); - - WmShelf* shelf() { return shelf_; } - void SetShelf(WmShelf* shelf); - - // Calculates if a window is touching the screen edges and returns edge. - DockedAlignment GetAlignmentOfWindow(const WmWindow* window) const; - - // Used to snap docked windows to the side of screen during drag. - DockedAlignment CalculateAlignment() const; - - void set_preferred_alignment(DockedAlignment preferred_alignment) { - preferred_alignment_ = preferred_alignment; - } - - void set_event_source(DockedActionSource event_source) { - event_source_ = event_source; - } - - // Returns true when a window can be docked. Windows cannot be docked at the - // edge used by the shelf or the edge opposite from existing dock. - bool CanDockWindow(WmWindow* window, DockedAlignment desired_alignment); - - WmWindow* dock_container() const { return dock_container_; } - - // Returns current bounding rectangle of docked windows area. - const gfx::Rect& docked_bounds() const { return docked_bounds_; } - - // Returns last known coordinates of |dragged_window_| after Relayout. - const gfx::Rect dragged_bounds() const { return dragged_bounds_; } - - // Returns true if currently dragged window is docked at the screen edge. - bool is_dragged_window_docked() const { return is_dragged_window_docked_; } - - // Updates docked layout when shelf bounds change. - void OnShelfBoundsChanged(); - - // SnapLayoutManager: - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override {} - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - // display::DisplayObserver: - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) override; - - // wm::WindowStateObserver: - void OnPreWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) override; - - // aura::WindowObserver: - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override; - void OnWindowVisibilityChanging(aura::Window* window, bool visible) override; - void OnWindowDestroying(aura::Window* window) override; - - // WmActivationObserver: - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override; - - // ShellObserver: - void OnShelfAlignmentChanged(WmWindow* root_window) override; - void OnFullscreenStateChanged(bool is_fullscreen, - WmWindow* root_window) override; - void OnOverviewModeStarting() override; - void OnOverviewModeEnded() override; - - private: - struct CompareMinimumHeight; - struct CompareWindowPos; - class ShelfWindowObserver; - struct WindowWithHeight; - - friend class DockedWindowLayoutManagerTest; - friend class DockedWindowResizerTest; - - // Width of the gap between the docked windows and a workspace. - static const int kMinDockGap; - - // Ideal (starting) width of the dock. - static const int kIdealWidth; - - // Returns the alignment of the docked windows other than the |child|. - DockedAlignment CalculateAlignmentExcept(const WmWindow* child) const; - - // Determines if the |alignment| is applicable taking into account - // the shelf alignment. - bool IsDockedAlignmentValid(DockedAlignment alignment) const; - - // Keep at most kMaxVisibleWindows visible in the dock and minimize the rest - // (except for |child|). - void MaybeMinimizeChildrenExcept(WmWindow* child); - - // Minimize / restore window and relayout. - void MinimizeDockedWindow(wm::WindowState* window_state); - void RestoreDockedWindow(wm::WindowState* window_state); - - // Record user-initiated |action| by |source| in UMA metrics. - void RecordUmaAction(DockedAction action, DockedActionSource source); - - // Updates |docked_width_| and UMA histograms. - void UpdateDockedWidth(int width); - - // Updates docked layout state when a window gets inside the dock. - void OnDraggedWindowDocked(WmWindow* window); - - // Updates docked layout state when a window gets outside the dock. - void OnDraggedWindowUndocked(); - - // Returns true if there are any windows currently docked. - bool IsAnyWindowDocked(); - - // Returns DOCKED_ALIGNMENT_LEFT if the |window|'s left edge is closer to - // the |dock_container_|'s left edge than the |window|'s right edge to - // the |dock_container_|'s right edge. Returns DOCKED_ALIGNMENT_RIGHT - // otherwise. - DockedAlignment GetEdgeNearestWindow(const WmWindow* window) const; - - // Called whenever the window layout might change. - void Relayout(); - - // Calculates target heights (and fills it in |visible_windows| array) such - // that the vertical space is fairly distributed among the windows taking - // into account their minimum and maximum size. Returns free vertical space - // (positive value) that remains after resizing all windows or deficit - // (negative value) if not all the windows fit. - int CalculateWindowHeightsAndRemainingRoom( - const gfx::Rect& work_area, - std::vector<WindowWithHeight>* visible_windows); - - // Calculate ideal width for the docked area. It will get used to adjust the - // dragged window or other windows as necessary. - int CalculateIdealWidth(const std::vector<WindowWithHeight>& visible_windows); - - // Fan out windows evenly distributing the overlap or remaining free space. - // Adjust the widths of the windows trying to make them all same. If this - // is not possible, center the windows in the docked area. - void FanOutChildren(const gfx::Rect& work_area, - int ideal_docked_width, - int available_room, - std::vector<WindowWithHeight>* visible_windows); - - // Updates |docked_bounds_| and workspace insets when bounds of docked windows - // area change. Passing |reason| to observers allows selectively skipping - // notifications. - void UpdateDockBounds(DockedWindowLayoutManagerObserver::Reason reason); - - // Called whenever the window stacking order needs to be updated (e.g. focus - // changes or a window is moved). - void UpdateStacking(WmWindow* active_window); - - // keyboard::KeyboardControllerObserver: - void OnKeyboardBoundsChanging(const gfx::Rect& keyboard_bounds) override; - void OnKeyboardClosed() override; - - // Parent window associated with this layout manager. - WmWindow* dock_container_; - - RootWindowController* root_window_controller_; - - // Protect against recursive calls to Relayout(). - bool in_layout_; - - // A window that is being dragged (whether docked or not). - // Windows are tracked by docked layout manager only if they are docked; - // however we need to know if a window is being dragged in order to avoid - // positioning it or even considering it for layout. - WmWindow* dragged_window_; - - // True if the window being dragged is currently docked. - bool is_dragged_window_docked_; - - // Previously docked windows use a more relaxed dragging sorting algorithm - // that uses assumption that a window starts being dragged out of position - // that was previously established in Relayout. This allows easier reordering. - bool is_dragged_from_dock_; - - // The shelf to respond to alignment changes. - WmShelf* shelf_; - - // Tracks if any window in the same root window is in fullscreen mode. - bool in_fullscreen_; - // Current width of the dock. - int docked_width_; - - // Last bounds that were sent to observers. - gfx::Rect docked_bounds_; - - // Target bounds of a docked window being dragged. - gfx::Rect dragged_bounds_; - - // True while in overview mode. - bool in_overview_; - - // Side of the screen that the dock is positioned at. - DockedAlignment alignment_; - - // The preferred alignment of the next window to be added to docked layout. - DockedAlignment preferred_alignment_; - - // The current event source - DockedActionSource event_source_; - - // The last active window. Used to maintain stacking order even if no windows - // are currently focused. - WmWindow* last_active_window_; - - // Timestamp of the last user-initiated action that changed docked state. - // Used in UMA metrics. - base::Time last_action_time_; - - // Observes shelf for bounds changes. - std::unique_ptr<ShelfWindowObserver> shelf_observer_; - - // Widget used to paint a background for the docked area. - std::unique_ptr<DockedBackgroundWidget> background_widget_; - - // Observers of dock bounds changes. - base::ObserverList<DockedWindowLayoutManagerObserver> observer_list_; - - DISALLOW_COPY_AND_ASSIGN(DockedWindowLayoutManager); -}; - -} // namespace ash - -#endif // ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_
diff --git a/ash/wm/dock/docked_window_layout_manager_observer.h b/ash/wm/dock/docked_window_layout_manager_observer.h deleted file mode 100644 index 34d6546..0000000 --- a/ash/wm/dock/docked_window_layout_manager_observer.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_OBSERVER_H_ -#define ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Rect; -} - -namespace ash { - -// Observers to the DockedWindowLayoutManager are notified of significant -// events that occur with the docked windows, such as the bounds change. -class ASH_EXPORT DockedWindowLayoutManagerObserver { - public: - // Reason for notification. Allows selectively ignoring notifications to - // prevent a notification loop. - enum Reason { - CHILD_CHANGED, - DISPLAY_RESIZED, - DISPLAY_INSETS_CHANGED, - SHELF_ALIGNMENT_CHANGED, - KEYBOARD_BOUNDS_CHANGING - }; - // Called after the dock bounds are changed. - virtual void OnDockBoundsChanging(const gfx::Rect& new_bounds, - Reason reason) = 0; - - protected: - virtual ~DockedWindowLayoutManagerObserver() {} -}; - -} // namespace ash - -#endif // ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_OBSERVER_H_
diff --git a/ash/wm/dock/docked_window_layout_manager_unittest.cc b/ash/wm/dock/docked_window_layout_manager_unittest.cc index 9e4b3f7..d3426e7 100644 --- a/ash/wm/dock/docked_window_layout_manager_unittest.cc +++ b/ash/wm/dock/docked_window_layout_manager_unittest.cc
@@ -2,22 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" #include "ash/common/ash_switches.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/shelf_view_test_api.h" #include "ash/test/shell_test_api.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/window_resizer.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/command_line.h"
diff --git a/ash/wm/dock/docked_window_resizer.cc b/ash/wm/dock/docked_window_resizer.cc deleted file mode 100644 index 68f4da5..0000000 --- a/ash/wm/dock/docked_window_resizer.cc +++ /dev/null
@@ -1,324 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/dock/docked_window_resizer.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/root_window_controller.h" -#include "ash/shell.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/window_parenting_utils.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace/magnetism_matcher.h" -#include "ui/base/hit_test.h" -#include "ui/base/ui_base_types.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" - -namespace ash { -namespace { - -DockedWindowLayoutManager* GetDockedLayoutManagerAtPoint( - const gfx::Point& point) { - display::Display display = - display::Screen::GetScreen()->GetDisplayNearestPoint(point); - if (!display.bounds().Contains(point)) - return nullptr; - - return DockedWindowLayoutManager::Get( - Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow()); -} - -} // namespace - -DockedWindowResizer::~DockedWindowResizer() {} - -// static -DockedWindowResizer* DockedWindowResizer::Create( - WindowResizer* next_window_resizer, - wm::WindowState* window_state) { - return new DockedWindowResizer(next_window_resizer, window_state); -} - -void DockedWindowResizer::Drag(const gfx::Point& location, int event_flags) { - last_location_ = GetTarget()->GetParent()->ConvertPointToScreen(location); - base::WeakPtr<DockedWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr()); - - if (!did_move_or_resize_) { - did_move_or_resize_ = true; - StartedDragging(resizer); - } - if (!resizer) - return; - - gfx::Point offset; - gfx::Rect bounds(CalculateBoundsForDrag(location)); - MaybeSnapToEdge(bounds, &offset); - gfx::Point modified_location(location); - modified_location += offset.OffsetFromOrigin(); - - next_window_resizer_->Drag(modified_location, event_flags); - if (!resizer) - return; - - DockedWindowLayoutManager* new_dock_layout = - GetDockedLayoutManagerAtPoint(last_location_); - if (new_dock_layout && new_dock_layout != dock_layout_) { - // The window is being dragged to a new display. If the previous - // container is the current parent of the window it will be informed of - // the end of drag when the window is reparented, otherwise let the - // previous container know the drag is complete. If we told the - // window's parent that the drag was complete it would begin - // positioning the window. - if (is_docked_ && dock_layout_->is_dragged_window_docked()) - dock_layout_->UndockDraggedWindow(); - if (dock_layout_ != initial_dock_layout_) - dock_layout_->FinishDragging( - DOCKED_ACTION_NONE, - details().source == aura::client::WINDOW_MOVE_SOURCE_MOUSE - ? DOCKED_ACTION_SOURCE_MOUSE - : DOCKED_ACTION_SOURCE_TOUCH); - is_docked_ = false; - dock_layout_ = new_dock_layout; - // The window's initial layout manager already knows that the drag is - // in progress for this window. - if (new_dock_layout != initial_dock_layout_) - new_dock_layout->StartDragging(GetTarget()); - } - // Window could get docked by the WorkspaceWindowResizer, update the state. - is_docked_ = dock_layout_->is_dragged_window_docked(); - // Whenever a window is dragged out of the dock it will be auto-sized - // in the dock if it gets docked again. - if (!is_docked_) - was_bounds_changed_by_user_ = false; -} - -void DockedWindowResizer::CompleteDrag() { - // The root window can change when dragging into a different screen. - next_window_resizer_->CompleteDrag(); - FinishedDragging(aura::client::MOVE_SUCCESSFUL); -} - -void DockedWindowResizer::RevertDrag() { - next_window_resizer_->RevertDrag(); - // Restore docked state to what it was before the drag if necessary. - if (is_docked_ != was_docked_) { - is_docked_ = was_docked_; - if (is_docked_) - dock_layout_->DockDraggedWindow(GetTarget()); - else - dock_layout_->UndockDraggedWindow(); - } - FinishedDragging(aura::client::MOVE_CANCELED); -} - -DockedWindowResizer::DockedWindowResizer(WindowResizer* next_window_resizer, - wm::WindowState* window_state) - : WindowResizer(window_state), - next_window_resizer_(next_window_resizer), - dock_layout_(NULL), - initial_dock_layout_(NULL), - did_move_or_resize_(false), - was_docked_(false), - is_docked_(false), - was_bounds_changed_by_user_(window_state->bounds_changed_by_user()), - weak_ptr_factory_(this) { - DCHECK(details().is_resizable); - dock_layout_ = DockedWindowLayoutManager::Get(GetTarget()->GetRootWindow()); - initial_dock_layout_ = dock_layout_; - was_docked_ = GetTarget()->GetParent() == dock_layout_->dock_container(); - is_docked_ = was_docked_; -} - -void DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, - gfx::Point* offset) { - // Windows only snap magnetically when they were previously docked. - if (!was_docked_) - return; - DockedAlignment dock_alignment = dock_layout_->CalculateAlignment(); - gfx::Rect dock_bounds = GetTarget()->GetParent()->ConvertRectFromScreen( - dock_layout_->dock_container()->GetBoundsInScreen()); - - // Short-range magnetism when retaining docked state. Same constant as in - // MagnetismMatcher is used for consistency. - const int kSnapToDockDistance = MagnetismMatcher::kMagneticDistance; - - if (dock_alignment == DOCKED_ALIGNMENT_LEFT || - dock_alignment == DOCKED_ALIGNMENT_NONE) { - const int distance = bounds.x() - dock_bounds.x(); - if (distance < kSnapToDockDistance && distance > 0) { - offset->set_x(-distance); - return; - } - } - if (dock_alignment == DOCKED_ALIGNMENT_RIGHT || - dock_alignment == DOCKED_ALIGNMENT_NONE) { - const int distance = dock_bounds.right() - bounds.right(); - if (distance < kSnapToDockDistance && distance > 0) - offset->set_x(distance); - } -} - -void DockedWindowResizer::StartedDragging( - base::WeakPtr<DockedWindowResizer>& resizer) { - // During resizing the window width is preserved by DockedwindowLayoutManager. - if (is_docked_ && - (details().bounds_change & WindowResizer::kBoundsChange_Resizes)) { - window_state_->set_bounds_changed_by_user(true); - } - - // Tell the dock layout manager that we are dragging this window. - // At this point we are not yet animating the window as it may not be - // inside the docked area. - dock_layout_->StartDragging(GetTarget()); - if (!resizer) - return; - // Reparent workspace windows during the drag to elevate them above workspace. - // Other windows for which the DockedWindowResizer is instantiated include - // panels and windows that are already docked. Those do not need reparenting. - if (GetTarget()->GetType() != ui::wm::WINDOW_TYPE_PANEL && - GetTarget()->GetParent()->GetShellWindowId() == - kShellWindowId_DefaultContainer) { - // Reparent the window into the docked windows container in order to get it - // on top of other docked windows. - WmWindow* docked_container = - GetTarget()->GetRootWindow()->GetChildByShellWindowId( - kShellWindowId_DockedContainer); - wm::ReparentChildWithTransientChildren( - GetTarget(), GetTarget()->GetParent(), docked_container); - if (!resizer) - return; - } - if (is_docked_) - dock_layout_->DockDraggedWindow(GetTarget()); -} - -void DockedWindowResizer::FinishedDragging( - aura::client::WindowMoveResult move_result) { - if (!did_move_or_resize_) - return; - did_move_or_resize_ = false; - WmWindow* window = GetTarget(); - const bool is_attached_panel = - window->GetType() == ui::wm::WINDOW_TYPE_PANEL && - window->aura_window()->GetProperty(kPanelAttachedKey); - const bool is_resized = - (details().bounds_change & WindowResizer::kBoundsChange_Resizes) != 0; - - // Undock the window if it is not in the normal, docked or minimized state - // type. This happens if a user snaps or maximizes a window using a - // keyboard shortcut while it is being dragged. - if (!window_state_->IsMinimized() && !window_state_->IsDocked() && - !window_state_->IsNormalStateType()) - is_docked_ = false; - - // When drag is completed the dragged docked window is resized to the bounds - // calculated by the layout manager that conform to other docked windows. - if (!is_attached_panel && is_docked_ && !is_resized) { - gfx::Rect bounds = window->GetParent()->ConvertRectFromScreen( - dock_layout_->dragged_bounds()); - if (!bounds.IsEmpty() && bounds.width() != window->GetBounds().width()) { - window->SetBounds(bounds); - } - } - // If a window has restore bounds, update the restore origin but not the size. - // The size gets restored when a window is undocked. - if (is_resized && is_docked_ && window_state_->HasRestoreBounds()) { - gfx::Rect restore_bounds = window->GetBoundsInScreen(); - restore_bounds.set_size(window_state_->GetRestoreBoundsInScreen().size()); - window_state_->SetRestoreBoundsInScreen(restore_bounds); - } - - // Check if the window needs to be docked or returned to workspace. - DockedAction action = - MaybeReparentWindowOnDragCompletion(is_resized, is_attached_panel); - dock_layout_->FinishDragging( - move_result == aura::client::MOVE_CANCELED ? DOCKED_ACTION_NONE : action, - details().source == aura::client::WINDOW_MOVE_SOURCE_MOUSE - ? DOCKED_ACTION_SOURCE_MOUSE - : DOCKED_ACTION_SOURCE_TOUCH); - - // If we started the drag in one root window and moved into another root - // but then canceled the drag we may need to inform the original layout - // manager that the drag is finished. - if (initial_dock_layout_ != dock_layout_) - initial_dock_layout_->FinishDragging( - DOCKED_ACTION_NONE, - details().source == aura::client::WINDOW_MOVE_SOURCE_MOUSE - ? DOCKED_ACTION_SOURCE_MOUSE - : DOCKED_ACTION_SOURCE_TOUCH); - is_docked_ = false; -} - -DockedAction DockedWindowResizer::MaybeReparentWindowOnDragCompletion( - bool is_resized, - bool is_attached_panel) { - WmWindow* window = GetTarget(); - - // Check if the window needs to be docked or returned to workspace. - DockedAction action = DOCKED_ACTION_NONE; - WmWindow* dock_container = window->GetRootWindow()->GetChildByShellWindowId( - kShellWindowId_DockedContainer); - if ((is_resized || !is_attached_panel) && - is_docked_ != (window->GetParent() == dock_container)) { - if (is_docked_) { - wm::ReparentChildWithTransientChildren(window, window->GetParent(), - dock_container); - action = DOCKED_ACTION_DOCK; - } else if (window->GetParent()->GetShellWindowId() == - kShellWindowId_DockedContainer) { - // Reparent the window back to workspace. - // We need to be careful to give ParentWindowWithContext a location in - // the right root window (matching the logic in DragWindowResizer) based - // on which root window a mouse pointer is in. We want to undock into the - // right screen near the edge of a multiscreen setup (based on where the - // mouse is). - gfx::Rect near_last_location(last_location_, gfx::Size()); - // Reparenting will cause Relayout and possible dock shrinking. - WmWindow* previous_parent = window->GetParent(); - window->SetParentUsingContext(window, near_last_location); - if (window->GetParent() != previous_parent) { - wm::ReparentTransientChildrenOfChild(window, previous_parent, - window->GetParent()); - } - action = was_docked_ ? DOCKED_ACTION_UNDOCK : DOCKED_ACTION_NONE; - } - } else { - // |action| is recorded in UMA and used to maintain |window_state_|. - if (is_resized && is_docked_ && was_docked_) - action = DOCKED_ACTION_RESIZE; - else if (is_docked_ && was_docked_) - action = DOCKED_ACTION_REORDER; - else if (is_docked_ && !was_docked_) - action = DOCKED_ACTION_DOCK; - else if (!is_docked_ && was_docked_) - action = DOCKED_ACTION_UNDOCK; - else - action = DOCKED_ACTION_NONE; - } - // When a window is newly docked it is auto-sized by docked layout adjusting - // to other windows. If it is just dragged (but not resized) while being - // docked it is auto-sized unless it has been resized while being docked - // before. - if (is_docked_) { - window->GetWindowState()->set_bounds_changed_by_user( - was_docked_ && (is_resized || was_bounds_changed_by_user_)); - } - - if (action == DOCKED_ACTION_DOCK) { - const wm::WMEvent event(wm::WM_EVENT_DOCK); - window_state_->OnWMEvent(&event); - } else if (window->GetWindowState()->IsDocked() && - action == DOCKED_ACTION_UNDOCK) { - const wm::WMEvent event(wm::WM_EVENT_NORMAL); - window_state_->OnWMEvent(&event); - } - - return action; -} - -} // namespace ash
diff --git a/ash/wm/dock/docked_window_resizer.h b/ash/wm/dock/docked_window_resizer.h deleted file mode 100644 index e1144b4a..0000000 --- a/ash/wm/dock/docked_window_resizer.h +++ /dev/null
@@ -1,101 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DOCK_DOCKED_WINDOW_RESIZER_H_ -#define ASH_WM_DOCK_DOCKED_WINDOW_RESIZER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/dock/dock_types.h" -#include "ash/wm/window_resizer.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" - -namespace gfx { -class Point; -class Rect; -} - -namespace ash { -class DockedWindowLayoutManager; - -// DockWindowResizer is used by ToplevelWindowEventFilter to handle dragging, -// moving or resizing of a window while it is docked to the side of a screen. -class ASH_EXPORT DockedWindowResizer : public WindowResizer { - public: - ~DockedWindowResizer() override; - - // Creates a new DockWindowResizer. The caller takes ownership of the - // returned object. The ownership of |next_window_resizer| is taken by the - // returned object. Returns NULL if not resizable. - static DockedWindowResizer* Create(WindowResizer* next_window_resizer, - wm::WindowState* window_state); - - // WindowResizer: - void Drag(const gfx::Point& location, int event_flags) override; - void CompleteDrag() override; - void RevertDrag() override; - - private: - // Creates DockWindowResizer that adds the ability to attach / detach - // windows to / from the dock. This object takes ownership of - // |next_window_resizer|. - DockedWindowResizer(WindowResizer* next_window_resizer, - wm::WindowState* window_state); - - // If the provided window bounds should snap to the side of a screen, - // returns the offset that gives the necessary adjustment to snap. - void MaybeSnapToEdge(const gfx::Rect& bounds, gfx::Point* offset); - - // Tracks the window's initial position and attachment at the start of a drag - // and informs the DockLayoutManager that a drag has started if necessary. - // |resizer| can be used to check if the resizer has been deleted during - // StartedDragging. - void StartedDragging(base::WeakPtr<DockedWindowResizer>& resizer); - - // Informs the DockLayoutManager that the drag is complete if it was informed - // of the drag start. |move_result| specifies if the drag was completed or - // reverted. - void FinishedDragging(aura::client::WindowMoveResult move_result); - - // Reparents dragged window as necessary to the docked container or back to - // workspace at the end of the drag. Calculates and returns action taken that - // can be reported in UMA stats. |is_resized| reports if the window is merely - // being resized rather than repositioned. |attached_panel| is necessary to - // avoid docking panels that have been attached to the launcher shelf at the - // end of the drag. - DockedAction MaybeReparentWindowOnDragCompletion(bool is_resized, - bool is_attached_panel); - - gfx::Point last_location_; - - // Wraps a window resizer and adds detaching / reattaching during drags. - std::unique_ptr<WindowResizer> next_window_resizer_; - - // Dock container window. - DockedWindowLayoutManager* dock_layout_; - DockedWindowLayoutManager* initial_dock_layout_; - - // Set to true once Drag() is invoked and the bounds of the window change. - bool did_move_or_resize_; - - // Set to true if the window that is being dragged was docked before drag. - bool was_docked_; - - // True if the dragged window is docked during the drag. - bool is_docked_; - - // True if the dragged window had |bounds_changed_by_user| before the drag. - // Cleared whenever the target window gets dragged outside of the docked area. - bool was_bounds_changed_by_user_; - - base::WeakPtrFactory<DockedWindowResizer> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(DockedWindowResizer); -}; - -} // namespace ash - -#endif // ASH_WM_DOCK_DOCKED_WINDOW_RESIZER_H_
diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc index 4e607de..7cf4583 100644 --- a/ash/wm/dock/docked_window_resizer_unittest.cc +++ b/ash/wm/dock/docked_window_resizer_unittest.cc
@@ -2,9 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/dock/docked_window_resizer.h" +#include "ash/common/wm/dock/docked_window_resizer.h" #include "ash/common/ash_switches.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/window_tree_host_manager.h" @@ -13,19 +20,12 @@ #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/cursor_manager_test_api.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/wm/dock/docked_window_layout_manager.h" #include "ash/wm/drag_window_resizer.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/command_line.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/window_parenting_client.h"
diff --git a/ash/wm/drag_details.cc b/ash/wm/drag_details.cc deleted file mode 100644 index 97dce25b..0000000 --- a/ash/wm/drag_details.cc +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/drag_details.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/wm/window_resizer.h" -#include "ui/aura/window.h" -#include "ui/base/hit_test.h" -#include "ui/compositor/layer.h" - -namespace ash { - -namespace { - -int GetSizeChangeDirectionForWindowComponent(int window_component) { - int size_change_direction = WindowResizer::kBoundsChangeDirection_None; - switch (window_component) { - case HTTOPLEFT: - case HTTOPRIGHT: - case HTBOTTOMLEFT: - case HTBOTTOMRIGHT: - case HTGROWBOX: - case HTCAPTION: - size_change_direction |= - WindowResizer::kBoundsChangeDirection_Horizontal | - WindowResizer::kBoundsChangeDirection_Vertical; - break; - case HTTOP: - case HTBOTTOM: - size_change_direction |= WindowResizer::kBoundsChangeDirection_Vertical; - break; - case HTRIGHT: - case HTLEFT: - size_change_direction |= WindowResizer::kBoundsChangeDirection_Horizontal; - break; - default: - break; - } - return size_change_direction; -} - -} // namespace - -DragDetails::DragDetails(WmWindow* window, - const gfx::Point& location, - int window_component, - aura::client::WindowMoveSource source) - : initial_state_type(window->GetWindowState()->GetStateType()), - initial_bounds_in_parent(window->GetBounds()), - initial_location_in_parent(location), - // When drag starts, we might be in the middle of a window opacity - // animation, on drag completion we must set the opacity to the target - // opacity rather than the current opacity (crbug.com/687003). - initial_opacity(window->GetLayer()->GetTargetOpacity()), - window_component(window_component), - bounds_change( - WindowResizer::GetBoundsChangeForWindowComponent(window_component)), - position_change_direction( - WindowResizer::GetPositionChangeDirectionForWindowComponent( - window_component)), - size_change_direction( - GetSizeChangeDirectionForWindowComponent(window_component)), - is_resizable(bounds_change != WindowResizer::kBoundsChangeDirection_None), - source(source), - should_attach_to_shelf( - window->GetType() == ui::wm::WINDOW_TYPE_PANEL && - window->aura_window()->GetProperty(kPanelAttachedKey)) { - wm::WindowState* window_state = window->GetWindowState(); - if ((window_state->IsNormalOrSnapped() || window_state->IsDocked()) && - window_state->HasRestoreBounds() && window_component == HTCAPTION) { - restore_bounds = window_state->GetRestoreBoundsInScreen(); - } -} - -DragDetails::~DragDetails() {} - -} // namespace ash
diff --git a/ash/wm/drag_details.h b/ash/wm/drag_details.h deleted file mode 100644 index 6f7d596f..0000000 --- a/ash/wm/drag_details.h +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_DRAG_DETAILS_H_ -#define ASH_WM_DRAG_DETAILS_H_ - -#include "ash/ash_export.h" -#include "ash/wm/wm_types.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/wm/public/window_move_client.h" - -namespace ash { - -class WmWindow; - -struct ASH_EXPORT DragDetails { - DragDetails(WmWindow* window, - const gfx::Point& location, - int window_component, - // TODO(sky): make wm type. - aura::client::WindowMoveSource source); - ~DragDetails(); - - ash::wm::WindowStateType initial_state_type; - - // Initial bounds of the window in parent coordinates. - const gfx::Rect initial_bounds_in_parent; - - // Restore bounds (in screen coordinates) of the window before the drag - // started. Only set if the window is normal and is being dragged. - gfx::Rect restore_bounds; - - // Location passed to the constructor, in |window->parent()|'s coordinates. - const gfx::Point initial_location_in_parent; - - // Initial opacity of the window. - const float initial_opacity; - - // The component the user pressed on. - const int window_component; - - // Bitmask of the |kBoundsChange_| constants. - const int bounds_change; - - // Bitmask of the |kBoundsChangeDirection_| constants. - const int position_change_direction; - - // Bitmask of the |kBoundsChangeDirection_| constants. - const int size_change_direction; - - // Will the drag actually modify the window? - const bool is_resizable; - - // Source of the event initiating the drag. - const aura::client::WindowMoveSource source; - - // True if the window should attach to the shelf after releasing. - bool should_attach_to_shelf; -}; - -} // namespace ash - -#endif // ASH_WM_DRAG_DETAILS_H_
diff --git a/ash/wm/drag_window_resizer.cc b/ash/wm/drag_window_resizer.cc index b792990..0ccaf949 100644 --- a/ash/wm/drag_window_resizer.cc +++ b/ash/wm/drag_window_resizer.cc
@@ -4,12 +4,12 @@ #include "ash/wm/drag_window_resizer.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/display/mouse_cursor_event_filter.h" #include "ash/shell.h" #include "ash/wm/drag_window_controller.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "base/memory/weak_ptr.h" #include "ui/aura/client/aura_constants.h"
diff --git a/ash/wm/drag_window_resizer.h b/ash/wm/drag_window_resizer.h index b8831528..ab49be7d 100644 --- a/ash/wm/drag_window_resizer.h +++ b/ash/wm/drag_window_resizer.h
@@ -8,7 +8,7 @@ #include <memory> #include "ash/ash_export.h" -#include "ash/wm/window_resizer.h" +#include "ash/common/wm/window_resizer.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h"
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc index 37e71150..c0514a7 100644 --- a/ash/wm/drag_window_resizer_unittest.cc +++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -4,16 +4,16 @@ #include "ash/wm/drag_window_resizer.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/wm/window_positioning_utils.h" #include "ash/common/wm_window.h" #include "ash/display/mouse_cursor_event_filter.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/cursor_manager_test_api.h" #include "ash/wm/drag_window_controller.h" -#include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h"
diff --git a/ash/wm/focus_rules.cc b/ash/wm/focus_rules.cc deleted file mode 100644 index bfe3df6..0000000 --- a/ash/wm/focus_rules.cc +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/focus_rules.h" - -#include "ash/common/shell_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/window_state.h" - -namespace ash { - -bool IsToplevelWindow(WmWindow* window) { - DCHECK(window); - // The window must in a valid hierarchy. - if (!window->GetRootWindow()) - return false; - - // The window must exist within a container that supports activation. - // The window cannot be blocked by a modal transient. - return IsActivatableShellWindowId(window->GetParent()->GetShellWindowId()); -} - -bool IsWindowConsideredActivatable(WmWindow* window) { - DCHECK(window); - // Only toplevel windows can be activated. - if (!IsToplevelWindow(window)) - return false; - - // The window must be visible. - return IsWindowConsideredVisibleForActivation(window); -} - -bool IsWindowConsideredVisibleForActivation(WmWindow* window) { - DCHECK(window); - // If the |window| doesn't belong to the current active user and also doesn't - // show for the current active user, then it should not be activated. - if (!WmShell::Get()->delegate()->CanShowWindowForUser(window)) - return false; - - if (window->IsVisible()) - return true; - - // Minimized windows are hidden in their minimized state, but they can always - // be activated. - if (window->GetWindowState()->IsMinimized()) - return true; - - if (!window->GetTargetVisibility()) - return false; - - const int parent_shell_window_id = window->GetParent()->GetShellWindowId(); - return parent_shell_window_id == kShellWindowId_DefaultContainer || - parent_shell_window_id == kShellWindowId_LockScreenContainer; -} - -} // namespace ash
diff --git a/ash/wm/focus_rules.h b/ash/wm/focus_rules.h deleted file mode 100644 index bd3e62f..0000000 --- a/ash/wm/focus_rules.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_FOCUS_RULES_H_ -#define ASH_WM_FOCUS_RULES_H_ - -#include "ash/ash_export.h" - -namespace ash { - -class WmWindow; - -// These functions provide the ash implementation wm::FocusRules. See -// description there for details. -ASH_EXPORT bool IsToplevelWindow(WmWindow* window); -ASH_EXPORT bool IsWindowConsideredActivatable(WmWindow* window); -ASH_EXPORT bool IsWindowConsideredVisibleForActivation(WmWindow* window); - -} // namespace ash - -#endif // ASH_WM_FOCUS_RULES_H_
diff --git a/ash/wm/fullscreen_window_finder.cc b/ash/wm/fullscreen_window_finder.cc deleted file mode 100644 index 90704f4..0000000 --- a/ash/wm/fullscreen_window_finder.cc +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/fullscreen_window_finder.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/switchable_windows.h" -#include "ash/wm/window_state.h" -#include "ui/compositor/layer.h" - -namespace ash { -namespace wm { - -WmWindow* GetWindowForFullscreenMode(WmWindow* context) { - WmWindow* topmost_window = nullptr; - WmWindow* active_window = context->GetShell()->GetActiveWindow(); - if (active_window && - active_window->GetRootWindow() == context->GetRootWindow() && - IsSwitchableContainer(active_window->GetParent())) { - // Use the active window when it is on the current root window to determine - // the fullscreen state to allow temporarily using a panel or docked window - // (which are always above the default container) while a fullscreen - // window is open. We only use the active window when in a switchable - // container as the launcher should not exit fullscreen mode. - topmost_window = active_window; - } else { - // Otherwise, use the topmost window on the root window's default container - // when there is no active window on this root window. - std::vector<WmWindow*> windows = - context->GetRootWindow() - ->GetChildByShellWindowId(kShellWindowId_DefaultContainer) - ->GetChildren(); - for (auto iter = windows.rbegin(); iter != windows.rend(); ++iter) { - if ((*iter)->GetWindowState()->IsUserPositionable() && - (*iter)->GetLayerTargetVisibility()) { - topmost_window = *iter; - break; - } - } - } - while (topmost_window) { - if (topmost_window->GetWindowState()->IsFullscreen()) - return topmost_window; - topmost_window = topmost_window->GetTransientParent(); - } - return nullptr; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/fullscreen_window_finder.h b/ash/wm/fullscreen_window_finder.h deleted file mode 100644 index 3831eb4..0000000 --- a/ash/wm/fullscreen_window_finder.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_FULLSCREEN_WINDOW_FINDER_H_ -#define ASH_WM_FULLSCREEN_WINDOW_FINDER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -class WmWindow; - -namespace wm { - -// Returns the topmost window or one of its transient parents, if any of them -// are in fullscreen mode. This searches for a window in the root of |context|. -ASH_EXPORT WmWindow* GetWindowForFullscreenMode(WmWindow* context); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_FULLSCREEN_WINDOW_FINDER_H_
diff --git a/ash/wm/gestures/overview_gesture_handler.cc b/ash/wm/gestures/overview_gesture_handler.cc index aee408c..8d84fee 100644 --- a/ash/wm/gestures/overview_gesture_handler.cc +++ b/ash/wm/gestures/overview_gesture_handler.cc
@@ -4,8 +4,8 @@ #include "ash/wm/gestures/overview_gesture_handler.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ui/events/event.h" #include "ui/events/event_constants.h"
diff --git a/ash/wm/gestures/overview_gesture_handler_unittest.cc b/ash/wm/gestures/overview_gesture_handler_unittest.cc index ec5ee028..90d2639 100644 --- a/ash/wm/gestures/overview_gesture_handler_unittest.cc +++ b/ash/wm/gestures/overview_gesture_handler_unittest.cc
@@ -4,11 +4,11 @@ #include "ash/wm/gestures/overview_gesture_handler.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" #include "ash/wm/window_util.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_windows.h"
diff --git a/ash/wm/immersive_context_ash.cc b/ash/wm/immersive_context_ash.cc deleted file mode 100644 index 2cfabb4b..0000000 --- a/ash/wm/immersive_context_ash.cc +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/immersive_context_ash.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/shared/immersive_fullscreen_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/window_state.h" -#include "base/logging.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/views/widget/widget.h" - -namespace ash { - -ImmersiveContextAsh::ImmersiveContextAsh() {} - -ImmersiveContextAsh::~ImmersiveContextAsh() {} - -void ImmersiveContextAsh::InstallResizeHandleWindowTargeter( - ImmersiveFullscreenController* controller) { - WmWindow* window = WmWindow::Get(controller->widget()->GetNativeWindow()); - window->InstallResizeHandleWindowTargeter(controller); -} - -void ImmersiveContextAsh::OnEnteringOrExitingImmersive( - ImmersiveFullscreenController* controller, - bool entering) { - WmWindow* window = WmWindow::Get(controller->widget()->GetNativeWindow()); - wm::WindowState* window_state = window->GetWindowState(); - // Auto hide the shelf in immersive fullscreen instead of hiding it. - window_state->set_hide_shelf_when_fullscreen(!entering); - // Update the window's immersive mode state for the window manager. - window_state->set_in_immersive_fullscreen(entering); - - for (WmWindow* root_window : WmShell::Get()->GetAllRootWindows()) - WmShelf::ForWindow(root_window)->UpdateVisibilityState(); -} - -gfx::Rect ImmersiveContextAsh::GetDisplayBoundsInScreen(views::Widget* widget) { - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - return window->GetDisplayNearestWindow().bounds(); -} - -void ImmersiveContextAsh::AddPointerWatcher( - views::PointerWatcher* watcher, - views::PointerWatcherEventTypes events) { - WmShell::Get()->AddPointerWatcher(watcher, events); -} - -void ImmersiveContextAsh::RemovePointerWatcher(views::PointerWatcher* watcher) { - WmShell::Get()->RemovePointerWatcher(watcher); -} - -bool ImmersiveContextAsh::DoesAnyWindowHaveCapture() { - return WmShell::Get()->GetCaptureWindow() != nullptr; -} - -bool ImmersiveContextAsh::IsMouseEventsEnabled() { - return WmShell::Get()->IsMouseEventsEnabled(); -} - -} // namespace ash
diff --git a/ash/wm/immersive_context_ash.h b/ash/wm/immersive_context_ash.h deleted file mode 100644 index 71098e1..0000000 --- a/ash/wm/immersive_context_ash.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_IMMERSIVE_CONTEXT_ASH_H_ -#define ASH_WM_IMMERSIVE_CONTEXT_ASH_H_ - -#include "ash/shared/immersive_context.h" -#include "base/macros.h" - -namespace ash { - -class ASH_EXPORT ImmersiveContextAsh : public ImmersiveContext { - public: - ImmersiveContextAsh(); - ~ImmersiveContextAsh() override; - - // ImmersiveContext: - void InstallResizeHandleWindowTargeter( - ImmersiveFullscreenController* controller) override; - void OnEnteringOrExitingImmersive(ImmersiveFullscreenController* controller, - bool entering) override; - gfx::Rect GetDisplayBoundsInScreen(views::Widget* widget) override; - void AddPointerWatcher(views::PointerWatcher* watcher, - views::PointerWatcherEventTypes events) override; - void RemovePointerWatcher(views::PointerWatcher* watcher) override; - bool DoesAnyWindowHaveCapture() override; - bool IsMouseEventsEnabled() override; - - private: - DISALLOW_COPY_AND_ASSIGN(ImmersiveContextAsh); -}; - -} // namespace ash - -#endif // ASH_WM_IMMERSIVE_CONTEXT_ASH_H_
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc index db136aa..45e67ae4 100644 --- a/ash/wm/immersive_fullscreen_controller_unittest.cc +++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -4,16 +4,16 @@ #include "ash/shared/immersive_fullscreen_controller.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/display/mouse_cursor_event_filter.h" #include "ash/public/cpp/shelf_types.h" #include "ash/root_window_controller.h" #include "ash/shared/immersive_fullscreen_controller_delegate.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/immersive_fullscreen_controller_test_api.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/cursor_client.h"
diff --git a/ash/wm/lock_layout_manager.cc b/ash/wm/lock_layout_manager.cc deleted file mode 100644 index d6b7766..0000000 --- a/ash/wm/lock_layout_manager.cc +++ /dev/null
@@ -1,121 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/lock_layout_manager.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/lock_window_state.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ui/events/event.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_util.h" - -namespace ash { - -LockLayoutManager::LockLayoutManager(WmWindow* window) - : wm::WmSnapToPixelLayoutManager(), - window_(window), - root_window_(window->GetRootWindow()), - is_observing_keyboard_(false) { - WmShell::Get()->AddShellObserver(this); - root_window_->aura_window()->AddObserver(this); - if (keyboard::KeyboardController::GetInstance()) { - keyboard::KeyboardController::GetInstance()->AddObserver(this); - is_observing_keyboard_ = true; - } -} - -LockLayoutManager::~LockLayoutManager() { - if (root_window_) - root_window_->aura_window()->RemoveObserver(this); - - for (WmWindow* child : window_->GetChildren()) - child->aura_window()->RemoveObserver(this); - - WmShell::Get()->RemoveShellObserver(this); - - if (keyboard::KeyboardController::GetInstance() && is_observing_keyboard_) { - keyboard::KeyboardController::GetInstance()->RemoveObserver(this); - is_observing_keyboard_ = false; - } -} - -void LockLayoutManager::OnWindowResized() { - const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); - AdjustWindowsForWorkAreaChange(&event); -} - -void LockLayoutManager::OnWindowAddedToLayout(WmWindow* child) { - child->aura_window()->AddObserver(this); - - // LockWindowState replaces default WindowState of a child. - wm::WindowState* window_state = LockWindowState::SetLockWindowState(child); - wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); - window_state->OnWMEvent(&event); -} - -void LockLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) { - child->aura_window()->RemoveObserver(this); -} - -void LockLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {} - -void LockLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) {} - -void LockLayoutManager::SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) { - wm::WindowState* window_state = child->GetWindowState(); - wm::SetBoundsEvent event(wm::WM_EVENT_SET_BOUNDS, requested_bounds); - window_state->OnWMEvent(&event); -} - -void LockLayoutManager::OnWindowDestroying(aura::Window* window) { - window->RemoveObserver(this); - if (root_window_ == WmWindow::Get(window)) - root_window_ = nullptr; -} - -void LockLayoutManager::OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - if (root_window_ == WmWindow::Get(window)) { - const wm::WMEvent wm_event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); - AdjustWindowsForWorkAreaChange(&wm_event); - } -} - -void LockLayoutManager::OnVirtualKeyboardStateChanged(bool activated) { - if (keyboard::KeyboardController::GetInstance()) { - if (activated) { - if (!is_observing_keyboard_) { - keyboard::KeyboardController::GetInstance()->AddObserver(this); - is_observing_keyboard_ = true; - } - } else { - keyboard::KeyboardController::GetInstance()->RemoveObserver(this); - is_observing_keyboard_ = false; - } - } -} - -void LockLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) { - keyboard_bounds_ = new_bounds; - OnWindowResized(); -} - -void LockLayoutManager::OnKeyboardClosed() {} - -void LockLayoutManager::AdjustWindowsForWorkAreaChange( - const wm::WMEvent* event) { - DCHECK(event->type() == wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED || - event->type() == wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); - - for (WmWindow* child : window_->GetChildren()) - child->GetWindowState()->OnWMEvent(event); -} - -} // namespace ash
diff --git a/ash/wm/lock_layout_manager.h b/ash/wm/lock_layout_manager.h deleted file mode 100644 index dc08d23d..0000000 --- a/ash/wm/lock_layout_manager.h +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_LOCK_LAYOUT_MANAGER_H_ -#define ASH_WM_LOCK_LAYOUT_MANAGER_H_ - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/wm/wm_snap_to_pixel_layout_manager.h" -#include "ash/wm/wm_types.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace ash { -namespace wm { -class WindowState; -class WMEvent; -} - -// LockLayoutManager is used for the windows created in LockScreenContainer. -// For Chrome OS this includes out-of-box/login/lock/multi-profile login use -// cases. LockScreenContainer does not use default work area definition. -// By default work area is defined as display area minus shelf, docked windows -// and minus virtual keyboard bounds. -// For windows in LockScreenContainer work area is display area minus virtual -// keyboard bounds (only if keyboard overscroll is disabled). If keyboard -// overscroll is enabled then work area always equals to display area size since -// virtual keyboard changes inner workspace of each WebContents. -// For all windows in LockScreenContainer default wm::WindowState is replaced -// with LockWindowState. -class ASH_EXPORT LockLayoutManager - : public wm::WmSnapToPixelLayoutManager, - public aura::WindowObserver, - public ShellObserver, - public keyboard::KeyboardControllerObserver { - public: - explicit LockLayoutManager(WmWindow* window); - ~LockLayoutManager() override; - - // Overridden from WmSnapToPixelLayoutManager: - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override; - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - // Overriden from aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override; - - // ShellObserver: - void OnVirtualKeyboardStateChanged(bool activated) override; - - // keyboard::KeyboardControllerObserver overrides: - void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; - void OnKeyboardClosed() override; - - private: - // Adjusts the bounds of all managed windows when the display area changes. - // This happens when the display size, work area insets has changed. - void AdjustWindowsForWorkAreaChange(const wm::WMEvent* event); - - WmWindow* window_; - WmWindow* root_window_; - - // True is subscribed as keyboard controller observer. - bool is_observing_keyboard_; - - // The bounds of the keyboard. - gfx::Rect keyboard_bounds_; - - DISALLOW_COPY_AND_ASSIGN(LockLayoutManager); -}; - -} // namespace ash - -#endif // ASH_WM_LOCK_LAYOUT_MANAGER_H_
diff --git a/ash/wm/lock_layout_manager_unittest.cc b/ash/wm/lock_layout_manager_unittest.cc index 6d46717..ca2bbf98 100644 --- a/ash/wm/lock_layout_manager_unittest.cc +++ b/ash/wm/lock_layout_manager_unittest.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/wm/window_state.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/command_line.h" #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc index 981fa83..51af510 100644 --- a/ash/wm/lock_state_controller_unittest.cc +++ b/ash/wm/lock_state_controller_unittest.cc
@@ -9,15 +9,15 @@ #include "ash/common/session/session_state_delegate.h" #include "ash/common/shutdown_controller.h" +#include "ash/common/test/test_session_state_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/lock_state_controller_test_api.h" #include "ash/test/test_screenshot_delegate.h" #include "ash/test/test_session_state_animator.h" -#include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/power_button_controller.h" #include "ash/wm/session_state_animator.h" #include "base/memory/ptr_util.h"
diff --git a/ash/wm/lock_state_observer.h b/ash/wm/lock_state_observer.h deleted file mode 100644 index d247e828..0000000 --- a/ash/wm/lock_state_observer.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_LOCK_STATE_OBSERVER_H_ -#define ASH_WM_LOCK_STATE_OBSERVER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -// Interface for classes that want to be notified by LockStateController when -// session-related events occur. -class ASH_EXPORT LockStateObserver { - public: - enum EventType { - EVENT_PRELOCK_ANIMATION_STARTED, - EVENT_LOCK_ANIMATION_STARTED, - EVENT_LOCK_ANIMATION_FINISHED, - }; - - virtual void OnLockStateEvent(EventType event) = 0; - virtual ~LockStateObserver() {} -}; - -} // namespace ash - -#endif // ASH_WM_LOCK_STATE_OBSERVER_H_
diff --git a/ash/wm/lock_window_state.cc b/ash/wm/lock_window_state.cc deleted file mode 100644 index 7b36315..0000000 --- a/ash/wm/lock_window_state.cc +++ /dev/null
@@ -1,184 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/lock_window_state.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/lock_layout_manager.h" -#include "ash/wm/window_animation_types.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_delegate.h" -#include "ash/wm/window_state_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "base/memory/ptr_util.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_util.h" - -namespace ash { - -LockWindowState::LockWindowState(WmWindow* window) - : current_state_type_(window->GetWindowState()->GetStateType()) {} - -LockWindowState::~LockWindowState() {} - -void LockWindowState::OnWMEvent(wm::WindowState* window_state, - const wm::WMEvent* event) { - switch (event->type()) { - case wm::WM_EVENT_TOGGLE_FULLSCREEN: - ToggleFullScreen(window_state, window_state->delegate()); - break; - case wm::WM_EVENT_FULLSCREEN: - UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN); - break; - case wm::WM_EVENT_PIN: - case wm::WM_EVENT_TRUSTED_PIN: - NOTREACHED(); - break; - case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: - case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: - case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: - case wm::WM_EVENT_TOGGLE_MAXIMIZE: - case wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT: - case wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: - case wm::WM_EVENT_CENTER: - case wm::WM_EVENT_SNAP_LEFT: - case wm::WM_EVENT_SNAP_RIGHT: - case wm::WM_EVENT_NORMAL: - case wm::WM_EVENT_MAXIMIZE: - case wm::WM_EVENT_DOCK: - UpdateWindow(window_state, - GetMaximizedOrCenteredWindowType(window_state)); - return; - case wm::WM_EVENT_MINIMIZE: - UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED); - return; - case wm::WM_EVENT_SHOW_INACTIVE: - return; - case wm::WM_EVENT_SET_BOUNDS: - if (window_state->IsMaximized() || window_state->IsFullscreen()) { - UpdateBounds(window_state); - } else { - const ash::wm::SetBoundsEvent* bounds_event = - static_cast<const ash::wm::SetBoundsEvent*>(event); - window_state->SetBoundsConstrained(bounds_event->requested_bounds()); - } - break; - case wm::WM_EVENT_ADDED_TO_WORKSPACE: - if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) { - UpdateWindow(window_state, - GetMaximizedOrCenteredWindowType(window_state)); - } else { - UpdateBounds(window_state); - } - break; - case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED: - case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED: - UpdateBounds(window_state); - break; - } -} - -wm::WindowStateType LockWindowState::GetType() const { - return current_state_type_; -} - -void LockWindowState::AttachState(wm::WindowState* window_state, - wm::WindowState::State* previous_state) { - current_state_type_ = previous_state->GetType(); - - // Initialize the state to a good preset. - if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN) { - UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state)); - } -} - -void LockWindowState::DetachState(wm::WindowState* window_state) {} - -// static -wm::WindowState* LockWindowState::SetLockWindowState(WmWindow* window) { - std::unique_ptr<wm::WindowState::State> lock_state = - base::MakeUnique<LockWindowState>(window); - std::unique_ptr<wm::WindowState::State> old_state( - window->GetWindowState()->SetStateObject(std::move(lock_state))); - return window->GetWindowState(); -} - -void LockWindowState::UpdateWindow(wm::WindowState* window_state, - wm::WindowStateType target_state) { - DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED || - target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED || - (target_state == wm::WINDOW_STATE_TYPE_NORMAL && - !window_state->CanMaximize()) || - target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN); - - if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) { - if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED) - return; - - current_state_type_ = target_state; - window_state->window()->SetVisibilityAnimationType( - wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); - window_state->window()->Hide(); - if (window_state->IsActive()) - window_state->Deactivate(); - return; - } - - if (current_state_type_ == target_state) { - // If the state type did not change, update it accordingly. - UpdateBounds(window_state); - return; - } - - const wm::WindowStateType old_state_type = current_state_type_; - current_state_type_ = target_state; - window_state->UpdateWindowShowStateFromStateType(); - window_state->NotifyPreStateTypeChange(old_state_type); - UpdateBounds(window_state); - window_state->NotifyPostStateTypeChange(old_state_type); - - if ((window_state->window()->GetTargetVisibility() || - old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) && - !window_state->window()->GetLayer()->visible()) { - // The layer may be hidden if the window was previously minimized. Make - // sure it's visible. - window_state->window()->Show(); - } -} - -wm::WindowStateType LockWindowState::GetMaximizedOrCenteredWindowType( - wm::WindowState* window_state) { - return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED - : wm::WINDOW_STATE_TYPE_NORMAL; -} - -void LockWindowState::UpdateBounds(wm::WindowState* window_state) { - if (!window_state->IsMaximized() && !window_state->IsFullscreen()) - return; - - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - gfx::Rect keyboard_bounds; - - if (keyboard_controller && !keyboard::IsKeyboardOverscrollEnabled() && - keyboard_controller->keyboard_visible()) { - keyboard_bounds = keyboard_controller->current_keyboard_bounds(); - } - gfx::Rect bounds = wm::GetDisplayBoundsWithShelf(window_state->window()); - bounds.set_height(bounds.height() - keyboard_bounds.height()); - - VLOG(1) << "Updating window bounds to: " << bounds.ToString(); - window_state->SetBoundsDirect(bounds); -} - -} // namespace ash
diff --git a/ash/wm/lock_window_state.h b/ash/wm/lock_window_state.h deleted file mode 100644 index 9a164ca..0000000 --- a/ash/wm/lock_window_state.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_LOCK_WINDOW_STATE_H_ -#define ASH_WM_LOCK_WINDOW_STATE_H_ - -#include "ash/wm/window_state.h" -#include "base/macros.h" - -namespace ash { - -// The LockWindowState implementation which reduces all possible window -// states to maximized (or normal if can't be maximized)/minimized/full-screen -// and is applied only on lock (login) window container. -// LockWindowState implements Ash behavior without state machine. -class LockWindowState : public wm::WindowState::State { - public: - // The |window|'s state object will be modified to use this new window mode - // state handler. - explicit LockWindowState(WmWindow* window); - ~LockWindowState() override; - - // WindowState::State overrides: - void OnWMEvent(wm::WindowState* window_state, - const wm::WMEvent* event) override; - wm::WindowStateType GetType() const override; - void AttachState(wm::WindowState* window_state, - wm::WindowState::State* previous_state) override; - void DetachState(wm::WindowState* window_state) override; - - // Creates new LockWindowState instance and attaches it to |window|. - static wm::WindowState* SetLockWindowState(WmWindow* window); - - private: - // Updates the window to |new_state_type| and resulting bounds: - // Either full screen, maximized centered or minimized. If the state does not - // change, only the bounds will be changed. - void UpdateWindow(wm::WindowState* window_state, - wm::WindowStateType new_state_type); - - // Depending on the capabilities of the window we either return - // |WINDOW_STATE_TYPE_MAXIMIZED| or |WINDOW_STATE_TYPE_NORMAL|. - wm::WindowStateType GetMaximizedOrCenteredWindowType( - wm::WindowState* window_state); - - // Updates the bounds taking virtual keyboard bounds into consideration. - void UpdateBounds(wm::WindowState* window_state); - - // The current state type. Due to the nature of this state, this can only be - // WM_STATE_TYPE{NORMAL, MINIMIZED, MAXIMIZED}. - wm::WindowStateType current_state_type_; - - DISALLOW_COPY_AND_ASSIGN(LockWindowState); -}; - -} // namespace ash - -#endif // ASH_WM_LOCK_WINDOW_STATE_H_
diff --git a/ash/wm/maximize_mode/maximize_mode_controller.cc b/ash/wm/maximize_mode/maximize_mode_controller.cc deleted file mode 100644 index 7b1d9c2..0000000 --- a/ash/wm/maximize_mode/maximize_mode_controller.cc +++ /dev/null
@@ -1,427 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/maximize_mode/maximize_mode_controller.h" - -#include <utility> - -#include "ash/common/ash_switches.h" -#include "ash/common/wm_shell.h" -#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" -#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" -#include "base/command_line.h" -#include "base/metrics/histogram_macros.h" -#include "base/time/default_tick_clock.h" -#include "base/time/tick_clock.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/chromeos/accelerometer/accelerometer_util.h" -#include "ui/display/display.h" -#include "ui/events/event.h" -#include "ui/events/keycodes/keyboard_codes.h" -#include "ui/gfx/geometry/vector3d_f.h" - -namespace ash { - -namespace { - -// The hinge angle at which to enter maximize mode. -const float kEnterMaximizeModeAngle = 200.0f; - -// The angle at which to exit maximize mode, this is specifically less than the -// angle to enter maximize mode to prevent rapid toggling when near the angle. -const float kExitMaximizeModeAngle = 160.0f; - -// Defines a range for which accelerometer readings are considered accurate. -// When the lid is near open (or near closed) the accelerometer readings may be -// inaccurate and a lid that is fully open may appear to be near closed (and -// vice versa). -const float kMinStableAngle = 20.0f; -const float kMaxStableAngle = 340.0f; - -// The time duration to consider the lid to be recently opened. -// This is used to prevent entering maximize mode if an erroneous accelerometer -// reading makes the lid appear to be fully open when the user is opening the -// lid from a closed position. -const int kLidRecentlyOpenedDurationSeconds = 2; - -// When the device approaches vertical orientation (i.e. portrait orientation) -// the accelerometers for the base and lid approach the same values (i.e. -// gravity pointing in the direction of the hinge). When this happens abrupt -// small acceleration perpendicular to the hinge can lead to incorrect hinge -// angle calculations. To prevent this the accelerometer updates will be -// smoothed over time in order to reduce this noise. -// This is the minimum acceleration parallel to the hinge under which to begin -// smoothing in m/s^2. -const float kHingeVerticalSmoothingStart = 7.0f; -// This is the maximum acceleration parallel to the hinge under which smoothing -// will incorporate new acceleration values, in m/s^2. -const float kHingeVerticalSmoothingMaximum = 8.7f; - -// The maximum deviation between the magnitude of the two accelerometers under -// which to detect hinge angle in m/s^2. These accelerometers are attached to -// the same physical device and so should be under the same acceleration. -const float kNoisyMagnitudeDeviation = 1.0f; - -// The angle between chromeos::AccelerometerReadings are considered stable if -// their magnitudes do not differ greatly. This returns false if the deviation -// between the screen and keyboard accelerometers is too high. -bool IsAngleBetweenAccelerometerReadingsStable( - const chromeos::AccelerometerUpdate& update) { - return std::abs( - ui::ConvertAccelerometerReadingToVector3dF( - update.get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) - .Length() - - ui::ConvertAccelerometerReadingToVector3dF( - update.get(chromeos::ACCELEROMETER_SOURCE_SCREEN)) - .Length()) <= kNoisyMagnitudeDeviation; -} - -bool IsEnabled() { - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshEnableTouchView); -} - -} // namespace - -MaximizeModeController::MaximizeModeController() - : have_seen_accelerometer_data_(false), - touchview_usage_interval_start_time_(base::Time::Now()), - tick_clock_(new base::DefaultTickClock()), - tablet_mode_switch_is_on_(false), - lid_is_closed_(false) { - WmShell::Get()->AddShellObserver(this); - WmShell::Get()->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_INITIALLY_DISABLED); - - // TODO(jonross): Do not create MaximizeModeController if the flag is - // unavailable. This will require refactoring - // IsMaximizeModeWindowManagerEnabled to check for the existance of the - // controller. - if (IsEnabled()) { - WmShell::Get()->AddDisplayObserver(this); - chromeos::AccelerometerReader::GetInstance()->AddObserver(this); - } - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( - this); -} - -MaximizeModeController::~MaximizeModeController() { - WmShell::Get()->RemoveShellObserver(this); - - if (IsEnabled()) { - WmShell::Get()->RemoveDisplayObserver(this); - chromeos::AccelerometerReader::GetInstance()->RemoveObserver(this); - } - chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( - this); -} - -bool MaximizeModeController::CanEnterMaximizeMode() { - // If we have ever seen accelerometer data, then HandleHingeRotation may - // trigger maximize mode at some point in the future. - // All TouchView-enabled devices can enter maximized mode. - return have_seen_accelerometer_data_ || IsEnabled(); -} - -// TODO(jcliang): Hide or remove EnableMaximizeModeWindowManager -// (http://crbug.com/620241). -void MaximizeModeController::EnableMaximizeModeWindowManager( - bool should_enable) { - bool is_enabled = !!maximize_mode_window_manager_.get(); - if (should_enable == is_enabled) - return; - - WmShell* shell = WmShell::Get(); - - if (should_enable) { - maximize_mode_window_manager_.reset(new MaximizeModeWindowManager()); - // TODO(jonross): Move the maximize mode notifications from ShellObserver - // to MaximizeModeController::Observer - shell->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_ENABLED); - shell->OnMaximizeModeStarted(); - - observers_.ForAllPtrs([](mojom::TouchViewObserver* observer) { - observer->OnTouchViewToggled(true); - }); - - } else { - shell->OnMaximizeModeEnding(); - maximize_mode_window_manager_.reset(); - shell->RecordUserMetricsAction(UMA_MAXIMIZE_MODE_DISABLED); - shell->OnMaximizeModeEnded(); - - observers_.ForAllPtrs([](mojom::TouchViewObserver* observer) { - observer->OnTouchViewToggled(false); - }); - } -} - -bool MaximizeModeController::IsMaximizeModeWindowManagerEnabled() const { - return maximize_mode_window_manager_.get() != NULL; -} - -void MaximizeModeController::AddWindow(WmWindow* window) { - if (IsMaximizeModeWindowManagerEnabled()) - maximize_mode_window_manager_->AddWindow(window); -} - -void MaximizeModeController::BindRequest( - mojom::TouchViewManagerRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - -void MaximizeModeController::OnAccelerometerUpdated( - scoped_refptr<const chromeos::AccelerometerUpdate> update) { - bool first_accelerometer_update = !have_seen_accelerometer_data_; - have_seen_accelerometer_data_ = true; - - if (!update->has(chromeos::ACCELEROMETER_SOURCE_SCREEN)) - return; - - if (!display::Display::HasInternalDisplay()) - return; - - if (!WmShell::Get()->IsActiveDisplayId( - display::Display::InternalDisplayId())) { - return; - } - - // Whether or not we enter maximize mode affects whether we handle screen - // rotation, so determine whether to enter maximize mode first. - if (!update->has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD)) { - if (first_accelerometer_update) - EnterMaximizeMode(); - } else if (ui::IsAccelerometerReadingStable( - *update, chromeos::ACCELEROMETER_SOURCE_SCREEN) && - ui::IsAccelerometerReadingStable( - *update, chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) && - IsAngleBetweenAccelerometerReadingsStable(*update)) { - // update.has(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD) - // Ignore the reading if it appears unstable. The reading is considered - // unstable if it deviates too much from gravity and/or the magnitude of the - // reading from the lid differs too much from the reading from the base. - HandleHingeRotation(update); - } -} - -void MaximizeModeController::LidEventReceived(bool open, - const base::TimeTicks& time) { - if (open) - last_lid_open_time_ = time; - lid_is_closed_ = !open; - LeaveMaximizeMode(); -} - -void MaximizeModeController::TabletModeEventReceived( - bool on, - const base::TimeTicks& time) { - tablet_mode_switch_is_on_ = on; - // Do not change if docked. - if (!display::Display::HasInternalDisplay() || - !WmShell::Get()->IsActiveDisplayId( - display::Display::InternalDisplayId())) { - return; - } - if (on && !IsMaximizeModeWindowManagerEnabled()) - EnterMaximizeMode(); -} - -void MaximizeModeController::SuspendImminent() { - // The system is about to suspend, so record TouchView usage interval metrics - // based on whether TouchView mode is currently active. - RecordTouchViewUsageInterval(CurrentTouchViewIntervalType()); -} - -void MaximizeModeController::SuspendDone( - const base::TimeDelta& sleep_duration) { - // We do not want TouchView usage metrics to include time spent in suspend. - touchview_usage_interval_start_time_ = base::Time::Now(); -} - -void MaximizeModeController::HandleHingeRotation( - scoped_refptr<const chromeos::AccelerometerUpdate> update) { - static const gfx::Vector3dF hinge_vector(1.0f, 0.0f, 0.0f); - gfx::Vector3dF base_reading(ui::ConvertAccelerometerReadingToVector3dF( - update->get(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD))); - gfx::Vector3dF lid_reading(ui::ConvertAccelerometerReadingToVector3dF( - update->get(chromeos::ACCELEROMETER_SOURCE_SCREEN))); - - // As the hinge approaches a vertical angle, the base and lid accelerometers - // approach the same values making any angle calculations highly inaccurate. - // Smooth out instantaneous acceleration when nearly vertical to increase - // accuracy. - float largest_hinge_acceleration = - std::max(std::abs(base_reading.x()), std::abs(lid_reading.x())); - float smoothing_ratio = - std::max(0.0f, std::min(1.0f, (largest_hinge_acceleration - - kHingeVerticalSmoothingStart) / - (kHingeVerticalSmoothingMaximum - - kHingeVerticalSmoothingStart))); - - // We cannot trust the computed lid angle when the device is held vertically. - bool is_angle_reliable = - largest_hinge_acceleration <= kHingeVerticalSmoothingMaximum; - - base_smoothed_.Scale(smoothing_ratio); - base_reading.Scale(1.0f - smoothing_ratio); - base_smoothed_.Add(base_reading); - - lid_smoothed_.Scale(smoothing_ratio); - lid_reading.Scale(1.0f - smoothing_ratio); - lid_smoothed_.Add(lid_reading); - - if (tablet_mode_switch_is_on_) - return; - - // Ignore the component of acceleration parallel to the hinge for the purposes - // of hinge angle calculation. - gfx::Vector3dF base_flattened(base_smoothed_); - gfx::Vector3dF lid_flattened(lid_smoothed_); - base_flattened.set_x(0.0f); - lid_flattened.set_x(0.0f); - - // Compute the angle between the base and the lid. - float lid_angle = 180.0f - gfx::ClockwiseAngleBetweenVectorsInDegrees( - base_flattened, lid_flattened, hinge_vector); - if (lid_angle < 0.0f) - lid_angle += 360.0f; - - bool is_angle_stable = is_angle_reliable && lid_angle >= kMinStableAngle && - lid_angle <= kMaxStableAngle; - - // Clear the last_lid_open_time_ for a stable reading so that there is less - // chance of a delay if the lid is moved from the close state to the fully - // open state very quickly. - if (is_angle_stable) - last_lid_open_time_ = base::TimeTicks(); - - // Toggle maximize mode on or off when corresponding thresholds are passed. - if (IsMaximizeModeWindowManagerEnabled() && is_angle_stable && - lid_angle <= kExitMaximizeModeAngle) { - LeaveMaximizeMode(); - } else if (!IsMaximizeModeWindowManagerEnabled() && !lid_is_closed_ && - lid_angle >= kEnterMaximizeModeAngle && - (is_angle_stable || !WasLidOpenedRecently())) { - EnterMaximizeMode(); - } -} - -void MaximizeModeController::EnterMaximizeMode() { - // Always reset first to avoid creation before destruction of a previous - // object. - event_blocker_ = - WmShell::Get()->CreateScopedDisableInternalMouseAndKeyboard(); - - if (IsMaximizeModeWindowManagerEnabled()) - return; - EnableMaximizeModeWindowManager(true); -} - -void MaximizeModeController::LeaveMaximizeMode() { - event_blocker_.reset(); - - if (!IsMaximizeModeWindowManagerEnabled()) - return; - EnableMaximizeModeWindowManager(false); -} - -// Called after maximize mode has started, windows might still animate though. -void MaximizeModeController::OnMaximizeModeStarted() { - RecordTouchViewUsageInterval(TOUCH_VIEW_INTERVAL_INACTIVE); -} - -// Called after maximize mode has ended, windows might still be returning to -// their original position. -void MaximizeModeController::OnMaximizeModeEnded() { - RecordTouchViewUsageInterval(TOUCH_VIEW_INTERVAL_ACTIVE); -} - -void MaximizeModeController::OnDisplayConfigurationChanged() { - if (!display::Display::HasInternalDisplay() || - !WmShell::Get()->IsActiveDisplayId( - display::Display::InternalDisplayId())) { - LeaveMaximizeMode(); - } else if (tablet_mode_switch_is_on_ && - !IsMaximizeModeWindowManagerEnabled()) { - // The internal display has returned, as we are exiting docked mode. - // The device is still in tablet mode, so trigger maximize mode, as this - // switch leads to the ignoring of accelerometer events. When the switch is - // not set the next stable accelerometer readings will trigger maximize - // mode. - EnterMaximizeMode(); - } -} - -void MaximizeModeController::RecordTouchViewUsageInterval( - TouchViewIntervalType type) { - if (!CanEnterMaximizeMode()) - return; - - base::Time current_time = base::Time::Now(); - base::TimeDelta delta = current_time - touchview_usage_interval_start_time_; - switch (type) { - case TOUCH_VIEW_INTERVAL_INACTIVE: - UMA_HISTOGRAM_LONG_TIMES("Ash.TouchView.TouchViewInactive", delta); - total_non_touchview_time_ += delta; - break; - case TOUCH_VIEW_INTERVAL_ACTIVE: - UMA_HISTOGRAM_LONG_TIMES("Ash.TouchView.TouchViewActive", delta); - total_touchview_time_ += delta; - break; - } - - touchview_usage_interval_start_time_ = current_time; -} - -MaximizeModeController::TouchViewIntervalType -MaximizeModeController::CurrentTouchViewIntervalType() { - if (IsMaximizeModeWindowManagerEnabled()) - return TOUCH_VIEW_INTERVAL_ACTIVE; - return TOUCH_VIEW_INTERVAL_INACTIVE; -} - -void MaximizeModeController::AddObserver(mojom::TouchViewObserverPtr observer) { - observer->OnTouchViewToggled(IsMaximizeModeWindowManagerEnabled()); - observers_.AddPtr(std::move(observer)); -} - -void MaximizeModeController::OnAppTerminating() { - // The system is about to shut down, so record TouchView usage interval - // metrics based on whether TouchView mode is currently active. - RecordTouchViewUsageInterval(CurrentTouchViewIntervalType()); - - if (CanEnterMaximizeMode()) { - UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchView.TouchViewActiveTotal", - total_touchview_time_.InMinutes(), 1, - base::TimeDelta::FromDays(7).InMinutes(), 50); - UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.TouchView.TouchViewInactiveTotal", - total_non_touchview_time_.InMinutes(), 1, - base::TimeDelta::FromDays(7).InMinutes(), 50); - base::TimeDelta total_runtime = - total_touchview_time_ + total_non_touchview_time_; - if (total_runtime.InSeconds() > 0) { - UMA_HISTOGRAM_PERCENTAGE( - "Ash.TouchView.TouchViewActivePercentage", - 100 * total_touchview_time_.InSeconds() / total_runtime.InSeconds()); - } - } -} - -bool MaximizeModeController::WasLidOpenedRecently() const { - if (last_lid_open_time_.is_null()) - return false; - - base::TimeTicks now = tick_clock_->NowTicks(); - DCHECK(now >= last_lid_open_time_); - base::TimeDelta elapsed_time = now - last_lid_open_time_; - return elapsed_time.InSeconds() <= kLidRecentlyOpenedDurationSeconds; -} - -void MaximizeModeController::SetTickClockForTest( - std::unique_ptr<base::TickClock> tick_clock) { - DCHECK(tick_clock_); - tick_clock_ = std::move(tick_clock); -} - -} // namespace ash
diff --git a/ash/wm/maximize_mode/maximize_mode_controller.h b/ash/wm/maximize_mode/maximize_mode_controller.h deleted file mode 100644 index 4d9a217f..0000000 --- a/ash/wm/maximize_mode/maximize_mode_controller.h +++ /dev/null
@@ -1,192 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_CONTROLLER_H_ -#define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_display_observer.h" -#include "ash/public/interfaces/touch_view.mojom.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "chromeos/accelerometer/accelerometer_reader.h" -#include "chromeos/accelerometer/accelerometer_types.h" -#include "chromeos/dbus/power_manager_client.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "mojo/public/cpp/bindings/interface_ptr_set.h" -#include "ui/gfx/geometry/vector3d_f.h" - -namespace base { -class TickClock; -} - -namespace gfx { -class Vector3dF; -} - -namespace ash { - -class MaximizeModeControllerTest; -class ScopedDisableInternalMouseAndKeyboard; -class MaximizeModeWindowManager; -class MaximizeModeWindowManagerTest; -class WmWindow; -namespace test { -class MultiUserWindowManagerChromeOSTest; -class VirtualKeyboardControllerTest; -} - -// MaximizeModeController listens to accelerometer events and automatically -// enters and exits maximize mode when the lid is opened beyond the triggering -// angle and rotates the display to match the device when in maximize mode. -class ASH_EXPORT MaximizeModeController : - public chromeos::AccelerometerReader::Observer, - public chromeos::PowerManagerClient::Observer, - NON_EXPORTED_BASE(public mojom::TouchViewManager), - public ShellObserver, - public WmDisplayObserver { - public: - MaximizeModeController(); - ~MaximizeModeController() override; - - // True if it is possible to enter maximize mode in the current - // configuration. If this returns false, it should never be the case that - // maximize mode becomes enabled. - bool CanEnterMaximizeMode(); - - // TODO(jonross): Merge this with EnterMaximizeMode. Currently these are - // separate for several reasons: there is no internal display when running - // unittests; the event blocker prevents keyboard input when running ChromeOS - // on linux. http://crbug.com/362881 - // Turn the always maximize mode window manager on or off. - void EnableMaximizeModeWindowManager(bool should_enable); - - // Test if the MaximizeModeWindowManager is enabled or not. - bool IsMaximizeModeWindowManagerEnabled() const; - - // Add a special window to the MaximizeModeWindowManager for tracking. This is - // only required for special windows which are handled by other window - // managers like the |MultiUserWindowManager|. - // If the maximize mode is not enabled no action will be performed. - void AddWindow(WmWindow* window); - - // Binds the mojom::TouchViewManager interface request to this object. - void BindRequest(mojom::TouchViewManagerRequest request); - - // ShellObserver: - void OnAppTerminating() override; - void OnMaximizeModeStarted() override; - void OnMaximizeModeEnded() override; - - // WmDisplayObserver: - void OnDisplayConfigurationChanged() override; - - // chromeos::AccelerometerReader::Observer: - void OnAccelerometerUpdated( - scoped_refptr<const chromeos::AccelerometerUpdate> update) override; - - // PowerManagerClient::Observer: - void LidEventReceived(bool open, const base::TimeTicks& time) override; - void TabletModeEventReceived(bool on, const base::TimeTicks& time) override; - void SuspendImminent() override; - void SuspendDone(const base::TimeDelta& sleep_duration) override; - - private: - friend class MaximizeModeControllerTest; - friend class MaximizeModeWindowManagerTest; - friend class test::MultiUserWindowManagerChromeOSTest; - friend class test::VirtualKeyboardControllerTest; - - // Used for recording metrics for intervals of time spent in - // and out of TouchView. - enum TouchViewIntervalType { - TOUCH_VIEW_INTERVAL_INACTIVE, - TOUCH_VIEW_INTERVAL_ACTIVE - }; - - // Set the TickClock. This is only to be used by tests that need to - // artificially and deterministically control the current time. - void SetTickClockForTest(std::unique_ptr<base::TickClock> tick_clock); - - // Detect hinge rotation from base and lid accelerometers and automatically - // start / stop maximize mode. - void HandleHingeRotation( - scoped_refptr<const chromeos::AccelerometerUpdate> update); - - // Returns true if the lid was recently opened. - bool WasLidOpenedRecently() const; - - // Enables MaximizeModeWindowManager, and determines the current state of - // rotation lock. - void EnterMaximizeMode(); - - // Removes MaximizeModeWindowManager and resets the display rotation if there - // is no rotation lock. - void LeaveMaximizeMode(); - - // Record UMA stats tracking TouchView usage. If |type| is - // TOUCH_VIEW_INTERVAL_INACTIVE, then record that TouchView has been - // inactive from |touchview_usage_interval_start_time_| until now. - // Similarly, record that TouchView has been active if |type| is - // TOUCH_VIEW_INTERVAL_ACTIVE. - void RecordTouchViewUsageInterval(TouchViewIntervalType type); - - // Returns TOUCH_VIEW_INTERVAL_ACTIVE if TouchView is currently active, - // otherwise returns TOUCH_VIEW_INTERNAL_INACTIVE. - TouchViewIntervalType CurrentTouchViewIntervalType(); - - // mojom::TouchViewManager: - void AddObserver(mojom::TouchViewObserverPtr observer) override; - - // The maximized window manager (if enabled). - std::unique_ptr<MaximizeModeWindowManager> maximize_mode_window_manager_; - - // A helper class which when instantiated will block native events from the - // internal keyboard and touchpad. - std::unique_ptr<ScopedDisableInternalMouseAndKeyboard> event_blocker_; - - // Whether we have ever seen accelerometer data. - bool have_seen_accelerometer_data_; - - // Tracks time spent in (and out of) touchview mode. - base::Time touchview_usage_interval_start_time_; - base::TimeDelta total_touchview_time_; - base::TimeDelta total_non_touchview_time_; - - // Tracks the last time we received a lid open event. This is used to suppress - // erroneous accelerometer readings as the lid is opened but the accelerometer - // reports readings that make the lid to appear near fully open. - base::TimeTicks last_lid_open_time_; - - // Source for the current time in base::TimeTicks. - std::unique_ptr<base::TickClock> tick_clock_; - - // Set when tablet mode switch is on. This is used to force maximize mode. - bool tablet_mode_switch_is_on_; - - // Tracks when the lid is closed. Used to prevent entering maximize mode. - bool lid_is_closed_; - - // Tracks smoothed accelerometer data over time. This is done when the hinge - // is approaching vertical to remove abrupt acceleration that can lead to - // incorrect calculations of hinge angles. - gfx::Vector3dF base_smoothed_; - gfx::Vector3dF lid_smoothed_; - - // Bindings for the TouchViewManager interface. - mojo::BindingSet<mojom::TouchViewManager> bindings_; - - // The set of touchview observers to be notified about mode changes. - mojo::InterfacePtrSet<mojom::TouchViewObserver> observers_; - - DISALLOW_COPY_AND_ASSIGN(MaximizeModeController); -}; - -} // namespace ash - -#endif // ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_CONTROLLER_H_
diff --git a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc index 49fafcfbc..2bd0958 100644 --- a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc +++ b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
@@ -2,19 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include <math.h> #include <utility> #include <vector> #include "ash/common/ash_switches.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/test/test_system_tray_delegate.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" -#include "ash/test/test_system_tray_delegate.h" -#include "ash/wm/overview/window_selector_controller.h" #include "base/command_line.h" #include "base/test/simple_test_tick_clock.h" #include "base/test/user_action_tester.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_event_handler.cc b/ash/wm/maximize_mode/maximize_mode_event_handler.cc deleted file mode 100644 index cfe077c0..0000000 --- a/ash/wm/maximize_mode/maximize_mode_event_handler.cc +++ /dev/null
@@ -1,72 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/maximize_mode/maximize_mode_event_handler.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ui/events/event.h" - -namespace ash { -namespace wm { -namespace { - -// The height of the area in which a touch operation leads to exiting the -// full screen mode. -const int kLeaveFullScreenAreaHeightInPixel = 2; - -} // namespace - -MaximizeModeEventHandler::MaximizeModeEventHandler() {} - -MaximizeModeEventHandler::~MaximizeModeEventHandler() {} - -bool MaximizeModeEventHandler::ToggleFullscreen(const ui::TouchEvent& event) { - if (event.type() != ui::ET_TOUCH_PRESSED) - return false; - - const SessionStateDelegate* delegate = - WmShell::Get()->GetSessionStateDelegate(); - - if (delegate->IsScreenLocked() || - delegate->GetSessionState() != session_manager::SessionState::ACTIVE) { - return false; - } - - // Find the active window (from the primary screen) to un-fullscreen. - WmWindow* window = WmShell::Get()->GetActiveWindow(); - if (!window) - return false; - - WindowState* window_state = window->GetWindowState(); - if (!window_state->IsFullscreen() || window_state->in_immersive_fullscreen()) - return false; - - // Test that the touch happened in the top or bottom lines. - int y = event.y(); - if (y >= kLeaveFullScreenAreaHeightInPixel && - y < (window->GetBounds().height() - kLeaveFullScreenAreaHeightInPixel)) { - return false; - } - - // Do not exit fullscreen in kiosk mode. - SystemTrayDelegate* system_tray_delegate = - WmShell::Get()->system_tray_delegate(); - if (system_tray_delegate->GetUserLoginStatus() == LoginStatus::KIOSK_APP || - system_tray_delegate->GetUserLoginStatus() == - LoginStatus::ARC_KIOSK_APP) { - return false; - } - - WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN); - window->GetWindowState()->OnWMEvent(&toggle_fullscreen); - return true; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/maximize_mode/maximize_mode_event_handler.h b/ash/wm/maximize_mode/maximize_mode_event_handler.h deleted file mode 100644 index 658be05..0000000 --- a/ash/wm/maximize_mode/maximize_mode_event_handler.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_H_ -#define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_H_ - -#include "base/macros.h" - -namespace ui { -class TouchEvent; -} - -namespace ash { -namespace wm { - -// MaximizeModeEventHandler handles toggling fullscreen when appropriate. -// MaximizeModeEventHandler installs event handlers in an environment specific -// way, e.g. EventHandler for aura. -class MaximizeModeEventHandler { - public: - MaximizeModeEventHandler(); - virtual ~MaximizeModeEventHandler(); - - protected: - // Subclasses call this to toggle fullscreen. If a toggle happened returns - // true. - bool ToggleFullscreen(const ui::TouchEvent& event); - - private: - DISALLOW_COPY_AND_ASSIGN(MaximizeModeEventHandler); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_H_
diff --git a/ash/wm/maximize_mode/maximize_mode_event_handler_aura.h b/ash/wm/maximize_mode/maximize_mode_event_handler_aura.h index a6702f2..2107309 100644 --- a/ash/wm/maximize_mode/maximize_mode_event_handler_aura.h +++ b/ash/wm/maximize_mode/maximize_mode_event_handler_aura.h
@@ -5,7 +5,7 @@ #ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_AURA_H_ #define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_EVENT_HANDLER_AURA_H_ -#include "ash/wm/maximize_mode/maximize_mode_event_handler.h" +#include "ash/common/wm/maximize_mode/maximize_mode_event_handler.h" #include "ui/events/event_handler.h" namespace ash {
diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/wm/maximize_mode/maximize_mode_window_manager.cc deleted file mode 100644 index 3b92f3c..0000000 --- a/ash/wm/maximize_mode/maximize_mode_window_manager.cc +++ /dev/null
@@ -1,332 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" - -#include "ash/common/ash_switches.h" -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shell.h" -#include "ash/wm/maximize_mode/maximize_mode_event_handler.h" -#include "ash/wm/maximize_mode/maximize_mode_window_state.h" -#include "ash/wm/maximize_mode/workspace_backdrop_delegate.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace_controller.h" -#include "base/command_line.h" -#include "base/memory/ptr_util.h" -#include "base/stl_util.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/display/screen.h" - -namespace ash { - -namespace { - -// Exits overview mode if it is currently active. -void CancelOverview() { - WindowSelectorController* controller = - WmShell::Get()->window_selector_controller(); - if (controller->IsSelecting()) - controller->OnSelectionEnded(); -} - -} // namespace - -MaximizeModeWindowManager::~MaximizeModeWindowManager() { - // Overview mode needs to be ended before exiting maximize mode to prevent - // transforming windows which are currently in - // overview: http://crbug.com/366605 - CancelOverview(); - for (aura::Window* window : added_windows_) - window->RemoveObserver(this); - added_windows_.clear(); - WmShell::Get()->RemoveShellObserver(this); - display::Screen::GetScreen()->RemoveObserver(this); - EnableBackdropBehindTopWindowOnEachDisplay(false); - RemoveWindowCreationObservers(); - RestoreAllWindows(); -} - -int MaximizeModeWindowManager::GetNumberOfManagedWindows() { - return window_state_map_.size(); -} - -void MaximizeModeWindowManager::AddWindow(WmWindow* window) { - // Only add the window if it is a direct dependent of a container window - // and not yet tracked. - if (!ShouldHandleWindow(window) || - base::ContainsKey(window_state_map_, window) || - !IsContainerWindow(window->GetParent()->aura_window())) { - return; - } - - MaximizeAndTrackWindow(window); -} - -void MaximizeModeWindowManager::WindowStateDestroyed(WmWindow* window) { - // At this time ForgetWindow() should already have been called. If not, - // someone else must have replaced the "window manager's state object". - DCHECK(!window->aura_window()->HasObserver(this)); - - auto it = window_state_map_.find(window); - DCHECK(it != window_state_map_.end()); - window_state_map_.erase(it); -} - -void MaximizeModeWindowManager::OnOverviewModeStarting() { - if (backdrops_hidden_) - return; - - EnableBackdropBehindTopWindowOnEachDisplay(false); - SetDeferBoundsUpdates(true); - backdrops_hidden_ = true; -} - -void MaximizeModeWindowManager::OnOverviewModeEnded() { - if (!backdrops_hidden_) - return; - - backdrops_hidden_ = false; - EnableBackdropBehindTopWindowOnEachDisplay(true); - SetDeferBoundsUpdates(false); -} - -void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) { - if (IsContainerWindow(window)) { - // container window can be removed on display destruction. - window->RemoveObserver(this); - observed_container_windows_.erase(window); - } else if (base::ContainsValue(added_windows_, window)) { - // Added window was destroyed before being shown. - added_windows_.erase(window); - window->RemoveObserver(this); - } else { - // If a known window gets destroyed we need to remove all knowledge about - // it. - ForgetWindow(WmWindow::Get(window)); - } -} - -void MaximizeModeWindowManager::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - // A window can get removed and then re-added by a drag and drop operation. - if (params.new_parent && IsContainerWindow(params.new_parent) && - !base::ContainsKey(window_state_map_, WmWindow::Get(params.target))) { - // Don't register the window if the window is invisible. Instead, - // wait until it becomes visible because the client may update the - // flag to control if the window should be added. - if (!params.target->IsVisible()) { - if (!base::ContainsValue(added_windows_, params.target)) { - added_windows_.insert(params.target); - params.target->AddObserver(this); - } - return; - } - MaximizeAndTrackWindow(WmWindow::Get(params.target)); - // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got - // already sent and we have to notify our state again. - if (base::ContainsKey(window_state_map_, WmWindow::Get(params.target))) { - wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); - wm::GetWindowState(params.target)->OnWMEvent(&event); - } - } -} - -void MaximizeModeWindowManager::OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) { - // Stop managing |window| if the always-on-top property is added. - if (key == aura::client::kAlwaysOnTopKey && - window->GetProperty(aura::client::kAlwaysOnTopKey)) { - ForgetWindow(WmWindow::Get(window)); - } -} - -void MaximizeModeWindowManager::OnWindowBoundsChanged( - aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - if (!IsContainerWindow(window)) - return; - // Reposition all non maximizeable windows. - for (auto& pair : window_state_map_) - pair.second->UpdateWindowPosition(pair.first->GetWindowState()); -} - -void MaximizeModeWindowManager::OnWindowVisibilityChanged(aura::Window* window, - bool visible) { - // Skip if it's already managed. - if (base::ContainsKey(window_state_map_, WmWindow::Get(window))) - return; - - if (IsContainerWindow(window->parent()) && - base::ContainsValue(added_windows_, window) && visible) { - added_windows_.erase(window); - window->RemoveObserver(this); - MaximizeAndTrackWindow(WmWindow::Get(window)); - // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got - // already sent and we have to notify our state again. - if (base::ContainsKey(window_state_map_, WmWindow::Get(window))) { - wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); - wm::GetWindowState(window)->OnWMEvent(&event); - } - } -} - -void MaximizeModeWindowManager::OnDisplayAdded( - const display::Display& display) { - DisplayConfigurationChanged(); -} - -void MaximizeModeWindowManager::OnDisplayRemoved( - const display::Display& display) { - DisplayConfigurationChanged(); -} - -void MaximizeModeWindowManager::OnDisplayMetricsChanged(const display::Display&, - uint32_t) { - // Nothing to do here. -} - -MaximizeModeWindowManager::MaximizeModeWindowManager() - : backdrops_hidden_(false) { - // The overview mode needs to be ended before the maximize mode is started. To - // guarantee the proper order, it will be turned off from here. - CancelOverview(); - - MaximizeAllWindows(); - AddWindowCreationObservers(); - EnableBackdropBehindTopWindowOnEachDisplay(true); - display::Screen::GetScreen()->AddObserver(this); - WmShell::Get()->AddShellObserver(this); - event_handler_ = WmShell::Get()->CreateMaximizeModeEventHandler(); -} - -void MaximizeModeWindowManager::MaximizeAllWindows() { - MruWindowTracker::WindowList windows = - WmShell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal(); - // Add all existing Mru windows. - for (WmWindow* window : windows) - MaximizeAndTrackWindow(window); -} - -void MaximizeModeWindowManager::RestoreAllWindows() { - while (window_state_map_.size()) - ForgetWindow(window_state_map_.begin()->first); -} - -void MaximizeModeWindowManager::SetDeferBoundsUpdates( - bool defer_bounds_updates) { - for (auto& pair : window_state_map_) - pair.second->SetDeferBoundsUpdates(defer_bounds_updates); -} - -void MaximizeModeWindowManager::MaximizeAndTrackWindow(WmWindow* window) { - if (!ShouldHandleWindow(window)) - return; - - DCHECK(!base::ContainsKey(window_state_map_, window)); - window->aura_window()->AddObserver(this); - - // We create and remember a maximize mode state which will attach itself to - // the provided state object. - window_state_map_[window] = new MaximizeModeWindowState(window, this); -} - -void MaximizeModeWindowManager::ForgetWindow(WmWindow* window) { - WindowToState::iterator it = window_state_map_.find(window); - - // The following DCHECK could fail if our window state object was destroyed - // earlier by someone else. However - at this point there is no other client - // which replaces the state object and therefore this should not happen. - DCHECK(it != window_state_map_.end()); - window->aura_window()->RemoveObserver(this); - - // By telling the state object to revert, it will switch back the old - // State object and destroy itself, calling WindowStateDestroyed(). - it->second->LeaveMaximizeMode(it->first->GetWindowState()); - DCHECK(!base::ContainsKey(window_state_map_, window)); -} - -bool MaximizeModeWindowManager::ShouldHandleWindow(WmWindow* window) { - DCHECK(window); - - // Windows with the always-on-top property should be free-floating and thus - // not managed by us. - if (window->IsAlwaysOnTop()) - return false; - - // Windows in the dock should not be managed by us. - if (window->GetWindowState()->IsDocked()) - return false; - - // If the changing bounds in the maximized/fullscreen is allowed, then - // let the client manage it even in maximized mode. - if (window->GetWindowState()->allow_set_bounds_in_maximized()) - return false; - - return window->GetType() == ui::wm::WINDOW_TYPE_NORMAL; -} - -void MaximizeModeWindowManager::AddWindowCreationObservers() { - DCHECK(observed_container_windows_.empty()); - // Observe window activations/creations in the default containers on all root - // windows. - for (aura::Window* root : Shell::GetInstance()->GetAllRootWindows()) { - aura::Window* default_container = - root->GetChildById(kShellWindowId_DefaultContainer); - DCHECK(!base::ContainsKey(observed_container_windows_, default_container)); - default_container->AddObserver(this); - observed_container_windows_.insert(default_container); - } -} - -void MaximizeModeWindowManager::RemoveWindowCreationObservers() { - for (aura::Window* window : observed_container_windows_) - window->RemoveObserver(this); - observed_container_windows_.clear(); -} - -void MaximizeModeWindowManager::DisplayConfigurationChanged() { - EnableBackdropBehindTopWindowOnEachDisplay(false); - RemoveWindowCreationObservers(); - AddWindowCreationObservers(); - EnableBackdropBehindTopWindowOnEachDisplay(true); -} - -bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) { - return base::ContainsKey(observed_container_windows_, window); -} - -void MaximizeModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay( - bool enable) { - // This function should be a no-op if backdrops have been disabled. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAshDisableMaximizeModeWindowBackdrop)) { - return; - } - - if (backdrops_hidden_) - return; - - // Inform the WorkspaceLayoutManager that we want to show a backdrop behind - // the topmost window of its container. - for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) { - RootWindowController* controller = root->GetRootWindowController(); - WmWindow* default_container = - root->GetChildByShellWindowId(kShellWindowId_DefaultContainer); - controller->workspace_controller()->SetMaximizeBackdropDelegate( - enable ? base::MakeUnique<WorkspaceBackdropDelegate>(default_container) - : nullptr); - } -} - -} // namespace ash
diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager.h b/ash/wm/maximize_mode/maximize_mode_window_manager.h deleted file mode 100644 index d1a532a3b..0000000 --- a/ash/wm/maximize_mode/maximize_mode_window_manager.h +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_MANAGER_H_ -#define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_MANAGER_H_ - -#include <stdint.h> - -#include <map> -#include <unordered_set> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/wm/window_state.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/display/display_observer.h" - -namespace ash { -class MaximizeModeController; -class MaximizeModeWindowState; - -namespace wm { -class MaximizeModeEventHandler; -} - -// A window manager which - when created - will force all windows into maximized -// mode. Exception are panels and windows which cannot be maximized. -// Windows which cannot be maximized / resized are centered with a layer placed -// behind the window so that no other windows are visible and/or obscured. -// With the destruction of the manager all windows will be restored to their -// original state. -class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, - public display::DisplayObserver, - public ShellObserver { - public: - // This should only be deleted by the creator (ash::Shell). - ~MaximizeModeWindowManager() override; - - // Returns the number of maximized & tracked windows by this manager. - int GetNumberOfManagedWindows(); - - // Adds a window which needs to be maximized. This is used by other window - // managers for windows which needs to get tracked due to (upcoming) state - // changes. - // The call gets ignored if the window was already or should not be handled. - void AddWindow(WmWindow* window); - - // Called from a window state object when it gets destroyed. - void WindowStateDestroyed(WmWindow* window); - - // ShellObserver overrides: - void OnOverviewModeStarting() override; - void OnOverviewModeEnded() override; - - // Overridden from WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override; - void OnWindowVisibilityChanged(aura::Window* window, bool visible) override; - - // display::DisplayObserver overrides: - void OnDisplayAdded(const display::Display& display) override; - void OnDisplayRemoved(const display::Display& display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t metrics) override; - - protected: - friend class MaximizeModeController; - - // The object should only be created by the ash::Shell. - MaximizeModeWindowManager(); - - private: - using WindowToState = std::map<WmWindow*, MaximizeModeWindowState*>; - - // Maximize all windows and restore their current state. - void MaximizeAllWindows(); - - // Restore all windows to their previous state. - void RestoreAllWindows(); - - // Set whether to defer bounds updates on all tracked windows. When set to - // false bounds will be updated as they may be stale. - void SetDeferBoundsUpdates(bool defer_bounds_updates); - - // If the given window should be handled by us, this function will maximize it - // and add it to the list of known windows (remembering the initial show - // state). - // Note: If the given window cannot be handled by us the function will return - // immediately. - void MaximizeAndTrackWindow(WmWindow* window); - - // Remove a window from our tracking list. - void ForgetWindow(WmWindow* window); - - // Returns true when the given window should be modified in any way by us. - bool ShouldHandleWindow(WmWindow* window); - - // Add window creation observers to track creation of new windows. - void AddWindowCreationObservers(); - - // Remove Window creation observers. - void RemoveWindowCreationObservers(); - - // Change the internal state (e.g. observers) when the display configuration - // changes. - void DisplayConfigurationChanged(); - - // Returns true when the |window| is a container window. - bool IsContainerWindow(aura::Window* window); - - // Add a backdrop behind the currently active window on each desktop. - void EnableBackdropBehindTopWindowOnEachDisplay(bool enable); - - // Every window which got touched by our window manager gets added here. - WindowToState window_state_map_; - - // All container windows which have to be tracked. - std::unordered_set<aura::Window*> observed_container_windows_; - - // Windows added to the container, but not yet shown. - std::unordered_set<aura::Window*> added_windows_; - - // True if all backdrops are hidden. - bool backdrops_hidden_; - - std::unique_ptr<wm::MaximizeModeEventHandler> event_handler_; - - DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowManager); -}; - -} // namespace ash - -#endif // ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_MANAGER_H_
diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc b/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc index 16cf02e..b2f9411e 100644 --- a/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc +++ b/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc
@@ -2,29 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" +#include "ash/common/wm/maximize_mode/maximize_mode_window_manager.h" #include <string> #include "ash/common/ash_switches.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/switchable_windows.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_observer.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" #include "ash/screen_util.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/shell_test_api.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/switchable_windows.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/window_state_observer.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/command_line.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_window_state.cc b/ash/wm/maximize_mode/maximize_mode_window_state.cc deleted file mode 100644 index 8021bc49..0000000 --- a/ash/wm/maximize_mode/maximize_mode_window_state.cc +++ /dev/null
@@ -1,337 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/maximize_mode/maximize_mode_window_state.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" -#include "ash/wm/window_animation_types.h" -#include "ash/wm/window_state_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { -namespace { - -// Returns the biggest possible size for a window which is about to be -// maximized. -gfx::Size GetMaximumSizeOfWindow(wm::WindowState* window_state) { - DCHECK(window_state->CanMaximize() || window_state->CanResize()); - - gfx::Size workspace_size = - wm::GetMaximizedWindowBoundsInParent(window_state->window()).size(); - - gfx::Size size = window_state->window()->GetMaximumSize(); - if (size.IsEmpty()) - return workspace_size; - - size.SetToMin(workspace_size); - return size; -} - -// Returns the centered bounds of the given bounds in the work area. -gfx::Rect GetCenteredBounds(const gfx::Rect& bounds_in_parent, - wm::WindowState* state_object) { - gfx::Rect work_area_in_parent = - wm::GetDisplayWorkAreaBoundsInParent(state_object->window()); - work_area_in_parent.ClampToCenteredSize(bounds_in_parent.size()); - return work_area_in_parent; -} - -// Returns the maximized/full screen and/or centered bounds of a window. -gfx::Rect GetBoundsInMaximizedMode(wm::WindowState* state_object) { - if (state_object->IsFullscreen() || state_object->IsPinned()) - return wm::GetDisplayBoundsInParent(state_object->window()); - - gfx::Rect bounds_in_parent; - // Make the window as big as possible. - if (state_object->CanMaximize() || state_object->CanResize()) { - bounds_in_parent.set_size(GetMaximumSizeOfWindow(state_object)); - } else { - // We prefer the user given window dimensions over the current windows - // dimensions since they are likely to be the result from some other state - // object logic. - if (state_object->HasRestoreBounds()) - bounds_in_parent = state_object->GetRestoreBoundsInParent(); - else - bounds_in_parent = state_object->window()->GetBounds(); - } - return GetCenteredBounds(bounds_in_parent, state_object); -} - -gfx::Rect GetRestoreBounds(wm::WindowState* window_state) { - if (window_state->IsMinimized() || window_state->IsMaximized() || - window_state->IsFullscreen()) { - gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); - if (!restore_bounds.IsEmpty()) - return restore_bounds; - } - gfx::Rect bounds = window_state->window()->GetBoundsInScreen(); - if (window_state->IsDocked()) { - gfx::Rect restore_bounds = window_state->GetRestoreBoundsInScreen(); - // Use current window horizontal offset origin in order to preserve docked - // alignment but preserve restored size and vertical offset for the time - // when the window gets undocked. - if (!restore_bounds.IsEmpty()) { - bounds.set_size(restore_bounds.size()); - bounds.set_y(restore_bounds.y()); - } - } - return bounds; -} - -} // namespace - -// static -void MaximizeModeWindowState::UpdateWindowPosition( - wm::WindowState* window_state) { - gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); - if (bounds_in_parent == window_state->window()->GetBounds()) - return; - window_state->SetBoundsDirect(bounds_in_parent); -} - -MaximizeModeWindowState::MaximizeModeWindowState( - WmWindow* window, - MaximizeModeWindowManager* creator) - : window_(window), - creator_(creator), - current_state_type_(window->GetWindowState()->GetStateType()), - defer_bounds_updates_(false) { - old_state_.reset(window_->GetWindowState() - ->SetStateObject(std::unique_ptr<State>(this)) - .release()); -} - -MaximizeModeWindowState::~MaximizeModeWindowState() { - creator_->WindowStateDestroyed(window_); -} - -void MaximizeModeWindowState::LeaveMaximizeMode(wm::WindowState* window_state) { - // Note: When we return we will destroy ourselves with the |our_reference|. - std::unique_ptr<wm::WindowState::State> our_reference = - window_state->SetStateObject(std::move(old_state_)); -} - -void MaximizeModeWindowState::SetDeferBoundsUpdates(bool defer_bounds_updates) { - if (defer_bounds_updates_ == defer_bounds_updates) - return; - - defer_bounds_updates_ = defer_bounds_updates; - if (!defer_bounds_updates_) - UpdateBounds(window_->GetWindowState(), true); -} - -void MaximizeModeWindowState::OnWMEvent(wm::WindowState* window_state, - const wm::WMEvent* event) { - switch (event->type()) { - case wm::WM_EVENT_TOGGLE_FULLSCREEN: - ToggleFullScreen(window_state, window_state->delegate()); - break; - case wm::WM_EVENT_FULLSCREEN: - UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_FULLSCREEN, true); - break; - case wm::WM_EVENT_PIN: - if (!WmShell::Get()->IsPinned()) - UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_PINNED, true); - break; - case wm::WM_EVENT_TRUSTED_PIN: - if (!WmShell::Get()->IsPinned()) - UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_TRUSTED_PINNED, true); - break; - case wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION: - case wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE: - case wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE: - case wm::WM_EVENT_TOGGLE_MAXIMIZE: - case wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT: - case wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT: - case wm::WM_EVENT_CENTER: - case wm::WM_EVENT_SNAP_LEFT: - case wm::WM_EVENT_SNAP_RIGHT: - case wm::WM_EVENT_NORMAL: - case wm::WM_EVENT_MAXIMIZE: - case wm::WM_EVENT_DOCK: - UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state), - true); - return; - case wm::WM_EVENT_MINIMIZE: - UpdateWindow(window_state, wm::WINDOW_STATE_TYPE_MINIMIZED, true); - return; - case wm::WM_EVENT_SHOW_INACTIVE: - return; - case wm::WM_EVENT_SET_BOUNDS: - if (window_state->allow_set_bounds_in_maximized()) { - window_state->SetBoundsConstrained( - static_cast<const wm::SetBoundsEvent*>(event)->requested_bounds()); - } else if (current_state_type_ == wm::WINDOW_STATE_TYPE_MAXIMIZED) { - // Having a maximized window, it could have been created with an empty - // size and the caller should get his size upon leaving the maximized - // mode. As such we set the restore bounds to the requested bounds. - gfx::Rect bounds_in_parent = - (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); - if (!bounds_in_parent.IsEmpty()) - window_state->SetRestoreBoundsInParent(bounds_in_parent); - } else if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && - current_state_type_ != wm::WINDOW_STATE_TYPE_PINNED && - current_state_type_ != wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { - // In all other cases (except for minimized windows) we respect the - // requested bounds and center it to a fully visible area on the screen. - gfx::Rect bounds_in_parent = - (static_cast<const wm::SetBoundsEvent*>(event))->requested_bounds(); - bounds_in_parent = GetCenteredBounds(bounds_in_parent, window_state); - if (bounds_in_parent != window_state->window()->GetBounds()) { - if (window_state->window()->IsVisible()) - window_state->SetBoundsDirectAnimated(bounds_in_parent); - else - window_state->SetBoundsDirect(bounds_in_parent); - } - } - break; - case wm::WM_EVENT_ADDED_TO_WORKSPACE: - if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && - current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) { - wm::WindowStateType new_state = - GetMaximizedOrCenteredWindowType(window_state); - UpdateWindow(window_state, new_state, true); - } - break; - case wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED: - if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) - UpdateBounds(window_state, true); - break; - case wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED: - // Don't animate on a screen rotation - just snap to new size. - if (current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED) - UpdateBounds(window_state, false); - break; - } -} - -wm::WindowStateType MaximizeModeWindowState::GetType() const { - return current_state_type_; -} - -void MaximizeModeWindowState::AttachState( - wm::WindowState* window_state, - wm::WindowState::State* previous_state) { - current_state_type_ = previous_state->GetType(); - - gfx::Rect restore_bounds = GetRestoreBounds(window_state); - if (!restore_bounds.IsEmpty()) { - // We do not want to do a session restore to our window states. Therefore - // we tell the window to use the current default states instead. - window_state->window()->SetRestoreOverrides(restore_bounds, - window_state->GetShowState()); - } - - // Initialize the state to a good preset. - if (current_state_type_ != wm::WINDOW_STATE_TYPE_MAXIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_MINIMIZED && - current_state_type_ != wm::WINDOW_STATE_TYPE_FULLSCREEN && - current_state_type_ != wm::WINDOW_STATE_TYPE_PINNED && - current_state_type_ != wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { - UpdateWindow(window_state, GetMaximizedOrCenteredWindowType(window_state), - true); - } - - window_state->set_can_be_dragged(false); -} - -void MaximizeModeWindowState::DetachState(wm::WindowState* window_state) { - // From now on, we can use the default session restore mechanism again. - window_state->window()->SetRestoreOverrides(gfx::Rect(), - ui::SHOW_STATE_NORMAL); - window_state->set_can_be_dragged(true); -} - -void MaximizeModeWindowState::UpdateWindow(wm::WindowState* window_state, - wm::WindowStateType target_state, - bool animated) { - DCHECK(target_state == wm::WINDOW_STATE_TYPE_MINIMIZED || - target_state == wm::WINDOW_STATE_TYPE_MAXIMIZED || - target_state == wm::WINDOW_STATE_TYPE_PINNED || - target_state == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED || - (target_state == wm::WINDOW_STATE_TYPE_NORMAL && - !window_state->CanMaximize()) || - target_state == wm::WINDOW_STATE_TYPE_FULLSCREEN); - - if (current_state_type_ == target_state) { - if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) - return; - // If the state type did not change, update it accordingly. - UpdateBounds(window_state, animated); - return; - } - - const wm::WindowStateType old_state_type = current_state_type_; - current_state_type_ = target_state; - window_state->UpdateWindowShowStateFromStateType(); - window_state->NotifyPreStateTypeChange(old_state_type); - - if (target_state == wm::WINDOW_STATE_TYPE_MINIMIZED) { - window_state->window()->SetVisibilityAnimationType( - wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); - window_state->window()->Hide(); - if (window_state->IsActive()) - window_state->Deactivate(); - } else { - UpdateBounds(window_state, animated); - } - - window_state->NotifyPostStateTypeChange(old_state_type); - - if (old_state_type == wm::WINDOW_STATE_TYPE_PINNED || - target_state == wm::WINDOW_STATE_TYPE_PINNED || - old_state_type == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED || - target_state == wm::WINDOW_STATE_TYPE_TRUSTED_PINNED) { - WmShell::Get()->SetPinnedWindow(window_state->window()); - } - - if ((window_state->window()->GetTargetVisibility() || - old_state_type == wm::WINDOW_STATE_TYPE_MINIMIZED) && - !window_state->window()->GetLayer()->visible()) { - // The layer may be hidden if the window was previously minimized. Make - // sure it's visible. - window_state->window()->Show(); - } -} - -wm::WindowStateType MaximizeModeWindowState::GetMaximizedOrCenteredWindowType( - wm::WindowState* window_state) { - return window_state->CanMaximize() ? wm::WINDOW_STATE_TYPE_MAXIMIZED - : wm::WINDOW_STATE_TYPE_NORMAL; -} - -void MaximizeModeWindowState::UpdateBounds(wm::WindowState* window_state, - bool animated) { - if (defer_bounds_updates_) - return; - gfx::Rect bounds_in_parent = GetBoundsInMaximizedMode(window_state); - // If we have a target bounds rectangle, we center it and set it - // accordingly. - if (!bounds_in_parent.IsEmpty() && - bounds_in_parent != window_state->window()->GetBounds()) { - if (current_state_type_ == wm::WINDOW_STATE_TYPE_MINIMIZED || - !window_state->window()->IsVisible() || !animated) { - window_state->SetBoundsDirect(bounds_in_parent); - } else { - // If we animate (to) maximized mode, we want to use the cross fade to - // avoid flashing. - if (window_state->IsMaximized()) - window_state->SetBoundsDirectCrossFade(bounds_in_parent); - else - window_state->SetBoundsDirectAnimated(bounds_in_parent); - } - } -} - -} // namespace ash
diff --git a/ash/wm/maximize_mode/maximize_mode_window_state.h b/ash/wm/maximize_mode/maximize_mode_window_state.h deleted file mode 100644 index fe0878f..0000000 --- a/ash/wm/maximize_mode/maximize_mode_window_state.h +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_STATE_H_ -#define ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_STATE_H_ - -#include <memory> - -#include "ash/wm/window_state.h" -#include "base/macros.h" - -namespace ash { -class MaximizeModeWindowManager; -class WmWindow; - -// The MaximizeModeWindowState implementation which reduces all possible window -// states to minimized and maximized. If a window cannot be maximized it will be -// set to normal. If a window cannot fill the entire workspace it will be -// centered within the workspace. -class MaximizeModeWindowState : public wm::WindowState::State { - public: - // Called when the window position might need to be updated. - static void UpdateWindowPosition(wm::WindowState* window_state); - - // The |window|'s state object will be modified to use this new window mode - // state handler. Upon destruction it will restore the previous state handler - // and call |creator::WindowStateDestroyed()| to inform that the window mode - // was reverted to the old window manager. - MaximizeModeWindowState(WmWindow* window, MaximizeModeWindowManager* creator); - ~MaximizeModeWindowState() override; - - // Leaves the maximize mode by reverting to previous state object. - void LeaveMaximizeMode(wm::WindowState* window_state); - - // Sets whether to ignore bounds updates. If set to false, immediately does a - // bounds update as the current window bounds may no longer be correct. - void SetDeferBoundsUpdates(bool defer_bounds_updates); - - // WindowState::State overrides: - void OnWMEvent(wm::WindowState* window_state, - const wm::WMEvent* event) override; - - wm::WindowStateType GetType() const override; - void AttachState(wm::WindowState* window_state, - wm::WindowState::State* previous_state) override; - void DetachState(wm::WindowState* window_state) override; - - private: - // Updates the window to |new_state_type| and resulting bounds: - // Either full screen, maximized centered or minimized. If the state does not - // change, only the bounds will be changed. If |animate| is set, the bound - // change get animated. - void UpdateWindow(wm::WindowState* window_state, - wm::WindowStateType new_state_type, - bool animate); - - // Depending on the capabilities of the window we either return - // |WINDOW_STATE_TYPE_MAXIMIZED| or |WINDOW_STATE_TYPE_NORMAL|. - wm::WindowStateType GetMaximizedOrCenteredWindowType( - wm::WindowState* window_state); - - // Updates the bounds to the maximum possible bounds according to the current - // window state. If |animated| is set we animate the change. - void UpdateBounds(wm::WindowState* window_state, bool animated); - - // The original state object of the window. - std::unique_ptr<wm::WindowState::State> old_state_; - - // The state object for this object which owns this instance. - WmWindow* window_; - - // The creator which needs to be informed when this state goes away. - MaximizeModeWindowManager* creator_; - - // The current state type. Due to the nature of this state, this can only be - // WM_STATE_TYPE{NORMAL, MINIMIZED, MAXIMIZED}. - wm::WindowStateType current_state_type_; - - // If true, do not update bounds. - bool defer_bounds_updates_; - - DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowState); -}; - -} // namespace ash - -#endif // ASH_WM_MAXIMIZE_MODE_MAXIMIZE_MODE_WINDOW_STATE_H_
diff --git a/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h b/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h deleted file mode 100644 index 6a1cbde..0000000 --- a/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_H_ -#define ASH_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_H_ - -namespace ash { - -class ScopedDisableInternalMouseAndKeyboard { - public: - virtual ~ScopedDisableInternalMouseAndKeyboard() {} -}; - -} // namespace ash - -#endif // ASH_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_H_
diff --git a/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h b/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h index 6783fcb..835a45d 100644 --- a/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h +++ b/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h
@@ -5,7 +5,7 @@ #ifndef ASH_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_OZONE_H_ #define ASH_WM_MAXIMIZE_MODE_SCOPED_DISABLE_INTERNAL_MOUSE_AND_KEYBOARD_OZONE_H_ -#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" +#include "ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" #include "base/macros.h" namespace ash {
diff --git a/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h b/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h index 6c8f47d..ea69d79 100644 --- a/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h +++ b/ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h
@@ -8,7 +8,7 @@ #include <vector> #include "ash/ash_export.h" -#include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" +#include "ash/common/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h" #include "base/macros.h" #include "ui/events/platform/platform_event_observer.h" #include "ui/gfx/geometry/point.h"
diff --git a/ash/wm/maximize_mode/workspace_backdrop_delegate.cc b/ash/wm/maximize_mode/workspace_backdrop_delegate.cc deleted file mode 100644 index 95c4596..0000000 --- a/ash/wm/maximize_mode/workspace_backdrop_delegate.cc +++ /dev/null
@@ -1,177 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/maximize_mode/workspace_backdrop_delegate.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h" -#include "base/auto_reset.h" -#include "ui/aura/window_observer.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/views/background.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/core/window_animations.h" -#include "ui/wm/core/window_util.h" - -namespace ash { -namespace { - -// The opacity of the backdrop. -const float kBackdropOpacity = 0.5f; - -} // namespace - -class WorkspaceBackdropDelegate::WindowObserverImpl - : public aura::WindowObserver { - public: - explicit WindowObserverImpl(WorkspaceBackdropDelegate* delegate) - : delegate_(delegate) {} - ~WindowObserverImpl() override {} - - private: - // aura::WindowObserver overrides: - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override { - // The container size has changed and the layer needs to be adapt to it. - delegate_->AdjustToContainerBounds(); - } - - WorkspaceBackdropDelegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(WindowObserverImpl); -}; - -WorkspaceBackdropDelegate::WorkspaceBackdropDelegate(WmWindow* container) - : container_observer_(new WindowObserverImpl(this)), - container_(container), - in_restacking_(false) { - background_ = new views::Widget; - views::Widget::InitParams params( - views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); - params.bounds = container_->GetBoundsInScreen(); - params.layer_type = ui::LAYER_SOLID_COLOR; - params.name = "WorkspaceBackdropDelegate"; - // To disallow the MRU list from picking this window up it should not be - // activateable. - params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; - DCHECK_NE(kShellWindowId_Invalid, container_->GetShellWindowId()); - container_->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - background_, container_->GetShellWindowId(), ¶ms); - background_->Init(params); - background_window_ = WmWindow::Get(background_->GetNativeWindow()); - // Do not use the animation system. We don't want the bounds animation and - // opacity needs to get set to |kBackdropOpacity|. - background_window_->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); - background_window_->GetLayer()->SetColor(SK_ColorBLACK); - // Make sure that the layer covers visibly everything - including the shelf. - background_window_->GetLayer()->SetBounds(params.bounds); - DCHECK(background_window_->GetBounds() == params.bounds); - Show(); - RestackBackdrop(); - container_->aura_window()->AddObserver(container_observer_.get()); -} - -WorkspaceBackdropDelegate::~WorkspaceBackdropDelegate() { - container_->aura_window()->RemoveObserver(container_observer_.get()); - // TODO: animations won't work right with mus: http://crbug.com/548396. - ::wm::ScopedHidingAnimationSettings hiding_settings( - background_->GetNativeView()); - background_->Close(); - background_window_->GetLayer()->SetOpacity(0.0f); -} - -void WorkspaceBackdropDelegate::OnWindowAddedToLayout(WmWindow* child) { - RestackBackdrop(); -} - -void WorkspaceBackdropDelegate::OnWindowRemovedFromLayout(WmWindow* child) { - RestackBackdrop(); -} - -void WorkspaceBackdropDelegate::OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) { - RestackBackdrop(); -} - -void WorkspaceBackdropDelegate::OnWindowStackingChanged(WmWindow* window) { - RestackBackdrop(); -} - -void WorkspaceBackdropDelegate::OnPostWindowStateTypeChange( - wm::WindowState* window_state, - wm::WindowStateType old_type) { - RestackBackdrop(); -} - -void WorkspaceBackdropDelegate::OnDisplayWorkAreaInsetsChanged() { - AdjustToContainerBounds(); -} - -void WorkspaceBackdropDelegate::RestackBackdrop() { - // Avoid recursive calls. - if (in_restacking_) - return; - - WmWindow* window = GetCurrentTopWindow(); - if (!window) { - // Hide backdrop since no suitable window was found. - background_->Hide(); - return; - } - if (window == background_window_ && background_->IsVisible()) - return; - if (window->GetRootWindow() != background_window_->GetRootWindow()) - return; - // We are changing the order of windows which will cause recursion. - base::AutoReset<bool> lock(&in_restacking_, true); - if (!background_->IsVisible()) - Show(); - // Since the backdrop needs to be immediately behind the window and the - // stacking functions only guarantee a "it's above or below", we need - // to re-arrange the two windows twice. - container_->StackChildAbove(background_window_, window); - container_->StackChildAbove(window, background_window_); -} - -WmWindow* WorkspaceBackdropDelegate::GetCurrentTopWindow() { - const WmWindow::Windows windows = container_->GetChildren(); - for (auto window_iter = windows.rbegin(); window_iter != windows.rend(); - ++window_iter) { - WmWindow* window = *window_iter; - if (window->GetTargetVisibility() && - window->GetType() == ui::wm::WINDOW_TYPE_NORMAL && - window->CanActivate()) - return window; - } - return nullptr; -} - -void WorkspaceBackdropDelegate::AdjustToContainerBounds() { - // Cover the entire container window. - gfx::Rect target_rect(gfx::Point(0, 0), container_->GetBounds().size()); - if (target_rect != background_window_->GetBounds()) { - // TODO: this won't work right with mus: http://crbug.com/548396. - // This needs to be instant. - ui::ScopedLayerAnimationSettings settings( - background_window_->GetLayer()->GetAnimator()); - settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(0)); - background_window_->SetBounds(target_rect); - if (!background_->IsVisible()) - background_window_->GetLayer()->SetOpacity(kBackdropOpacity); - } -} - -void WorkspaceBackdropDelegate::Show() { - background_window_->GetLayer()->SetOpacity(0.0f); - background_->Show(); - ui::ScopedLayerAnimationSettings settings( - background_window_->GetLayer()->GetAnimator()); - background_window_->GetLayer()->SetOpacity(kBackdropOpacity); -} - -} // namespace ash
diff --git a/ash/wm/maximize_mode/workspace_backdrop_delegate.h b/ash/wm/maximize_mode/workspace_backdrop_delegate.h deleted file mode 100644 index a7e574d..0000000 --- a/ash/wm/maximize_mode/workspace_backdrop_delegate.h +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ -#define ASH_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h" -#include "base/macros.h" - -namespace views { -class Widget; -} - -namespace ash { - -class WmWindow; - -// A background which gets created for a container |window| and which gets -// stacked behind the topmost window (within that container) covering the -// entire container. -class ASH_EXPORT WorkspaceBackdropDelegate - : public WorkspaceLayoutManagerBackdropDelegate { - public: - explicit WorkspaceBackdropDelegate(WmWindow* container); - ~WorkspaceBackdropDelegate() override; - - // WorkspaceLayoutManagerBackdropDelegate overrides: - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override; - void OnWindowStackingChanged(WmWindow* window) override; - void OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) override; - void OnDisplayWorkAreaInsetsChanged() override; - - private: - class WindowObserverImpl; - - // Restack the backdrop relatively to the other windows in the container. - void RestackBackdrop(); - - // Returns the current visible top level window in the container. - WmWindow* GetCurrentTopWindow(); - - // Position & size the background over the container window. - void AdjustToContainerBounds(); - - // Show the overlay. - void Show(); - - std::unique_ptr<WindowObserverImpl> container_observer_; - - // The background which covers the rest of the screen. - views::Widget* background_ = nullptr; - // WmWindow for |background_|. - WmWindow* background_window_ = nullptr; - - // The window which is being "maximized". - WmWindow* container_; - - // If true, the |RestackOrHideWindow| might recurse. - bool in_restacking_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceBackdropDelegate); -}; - -} // namespace ash - -#endif // ASH_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc deleted file mode 100644 index c9e59805..0000000 --- a/ash/wm/mru_window_tracker.cc +++ /dev/null
@@ -1,161 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/mru_window_tracker.h" - -#include <algorithm> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/focus_rules.h" -#include "ash/wm/switchable_windows.h" -#include "ash/wm/window_state.h" -#include "base/bind.h" -#include "ui/aura/window.h" - -namespace ash { - -namespace { - -using CanActivateWindowPredicate = base::Callback<bool(WmWindow*)>; - -bool CallCanActivate(WmWindow* window) { - return window->CanActivate(); -} - -// Adds the windows that can be cycled through for the specified window id to -// |windows|. -void AddTrackedWindows(WmWindow* root, - int container_id, - MruWindowTracker::WindowList* windows) { - WmWindow* container = root->GetChildByShellWindowId(container_id); - const MruWindowTracker::WindowList children(container->GetChildren()); - windows->insert(windows->end(), children.begin(), children.end()); -} - -// Returns a list of windows ordered by their stacking order. -// If |mru_windows| is passed, these windows are moved to the front of the list. -// It uses the given |should_include_window_predicate| to determine whether to -// include a window in the returned list or not. -MruWindowTracker::WindowList BuildWindowListInternal( - const std::list<WmWindow*>* mru_windows, - const CanActivateWindowPredicate& should_include_window_predicate) { - MruWindowTracker::WindowList windows; - WmWindow* active_root = WmShell::Get()->GetRootWindowForNewWindows(); - for (WmWindow* window : WmShell::Get()->GetAllRootWindows()) { - if (window == active_root) - continue; - for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) - AddTrackedWindows(window, wm::kSwitchableWindowContainerIds[i], &windows); - } - - // Add windows in the active root windows last so that the topmost window - // in the active root window becomes the front of the list. - for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) - AddTrackedWindows(active_root, wm::kSwitchableWindowContainerIds[i], - &windows); - - // Removes unfocusable windows. - std::vector<WmWindow*>::iterator itr = windows.begin(); - while (itr != windows.end()) { - if (!should_include_window_predicate.Run(*itr)) - itr = windows.erase(itr); - else - ++itr; - } - - // Put the windows in the mru_windows list at the head, if it's available. - if (mru_windows) { - // Iterate through the list backwards, so that we can move each window to - // the front of the windows list as we find them. - for (auto ix = mru_windows->rbegin(); ix != mru_windows->rend(); ++ix) { - // Exclude windows in non-switchable containers and those which cannot - // be activated. - if (!wm::IsSwitchableContainer((*ix)->GetParent()) || - !should_include_window_predicate.Run(*ix)) { - continue; - } - - MruWindowTracker::WindowList::iterator window = - std::find(windows.begin(), windows.end(), *ix); - if (window != windows.end()) { - windows.erase(window); - windows.push_back(*ix); - } - } - } - - // Window cycling expects the topmost window at the front of the list. - std::reverse(windows.begin(), windows.end()); - - return windows; -} - -} // namespace - -////////////////////////////////////////////////////////////////////////////// -// MruWindowTracker, public: - -MruWindowTracker::MruWindowTracker() : ignore_window_activations_(false) { - WmShell::Get()->AddActivationObserver(this); -} - -MruWindowTracker::~MruWindowTracker() { - WmShell::Get()->RemoveActivationObserver(this); - for (WmWindow* window : mru_windows_) - window->aura_window()->RemoveObserver(this); -} - -MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList() const { - return BuildWindowListInternal(&mru_windows_, base::Bind(&CallCanActivate)); -} - -MruWindowTracker::WindowList MruWindowTracker::BuildWindowListIgnoreModal() - const { - return BuildWindowListInternal(nullptr, - base::Bind(&IsWindowConsideredActivatable)); -} - -void MruWindowTracker::SetIgnoreActivations(bool ignore) { - ignore_window_activations_ = ignore; - - // If no longer ignoring window activations, move currently active window - // to front. - if (!ignore) - SetActiveWindow(WmShell::Get()->GetActiveWindow()); -} - -////////////////////////////////////////////////////////////////////////////// -// MruWindowTracker, private: - -void MruWindowTracker::SetActiveWindow(WmWindow* active_window) { - if (!active_window) - return; - - std::list<WmWindow*>::iterator iter = - std::find(mru_windows_.begin(), mru_windows_.end(), active_window); - // Observe all newly tracked windows. - if (iter == mru_windows_.end()) - active_window->aura_window()->AddObserver(this); - else - mru_windows_.erase(iter); - mru_windows_.push_front(active_window); -} - -void MruWindowTracker::OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) { - if (!ignore_window_activations_) - SetActiveWindow(gained_active); -} - -void MruWindowTracker::OnWindowDestroyed(aura::Window* window) { - // It's possible for OnWindowActivated() to be called after - // OnWindowDestroying(). This means we need to override OnWindowDestroyed() - // else we may end up with a deleted window in |mru_windows_|. - mru_windows_.remove(WmWindow::Get(window)); - window->RemoveObserver(this); -} - -} // namespace ash
diff --git a/ash/wm/mru_window_tracker.h b/ash/wm/mru_window_tracker.h deleted file mode 100644 index 76ec2db..0000000 --- a/ash/wm/mru_window_tracker.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_MRU_WINDOW_TRACKER_H_ -#define ASH_WM_MRU_WINDOW_TRACKER_H_ - -#include <list> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/common/wm_activation_observer.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" - -namespace ash { - -class WmWindow; - -// Maintains a most recently used list of windows. This is used for window -// cycling using Alt+Tab and overview mode. -class ASH_EXPORT MruWindowTracker : public WmActivationObserver, - public aura::WindowObserver { - public: - using WindowList = std::vector<WmWindow*>; - - MruWindowTracker(); - ~MruWindowTracker() override; - - // Returns the set of windows which can be cycled through using the tracked - // list of most recently used windows. - WindowList BuildMruWindowList() const; - - // This does the same thing as the above, but ignores the system modal dialog - // state and hence the returned list could contain more windows if a system - // modal dialog window is present. - WindowList BuildWindowListIgnoreModal() const; - - // Starts or stops ignoring window activations. If no longer ignoring - // activations the currently active window is moved to the front of the - // MRU window list. Used by WindowCycleList to avoid adding all cycled - // windows to the front of the MRU window list. - void SetIgnoreActivations(bool ignore); - - private: - // Updates the mru_windows_ list to insert/move |active_window| at/to the - // front. - void SetActiveWindow(WmWindow* active_window); - - // Overridden from WmActivationObserver: - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override; - - // Overridden from aura::WindowObserver: - void OnWindowDestroyed(aura::Window* window) override; - - // List of windows that have been activated in containers that we cycle - // through, sorted by most recently used. - std::list<WmWindow*> mru_windows_; - - bool ignore_window_activations_; - - DISALLOW_COPY_AND_ASSIGN(MruWindowTracker); -}; - -} // namespace ash - -#endif // ASH_WM_MRU_WINDOW_TRACKER_H_
diff --git a/ash/wm/mru_window_tracker_unittest.cc b/ash/wm/mru_window_tracker_unittest.cc deleted file mode 100644 index 3e83708..0000000 --- a/ash/wm/mru_window_tracker_unittest.cc +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/mru_window_tracker.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/test/ash_test.h" -#include "ash/wm/window_state.h" -#include "ui/base/hit_test.h" - -namespace ash { - -class MruWindowTrackerTest : public AshTest { - public: - MruWindowTrackerTest() {} - ~MruWindowTrackerTest() override {} - - std::unique_ptr<WindowOwner> CreateTestWindow() { - return AshTest::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); - } - - MruWindowTracker* mru_window_tracker() { - return WmShell::Get()->mru_window_tracker(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(MruWindowTrackerTest); -}; - -// Basic test that the activation order is tracked. -TEST_F(MruWindowTrackerTest, Basic) { - std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); - WmWindow* w1 = w1_owner->window(); - std::unique_ptr<WindowOwner> w2_owner(CreateTestWindow()); - WmWindow* w2 = w2_owner->window(); - std::unique_ptr<WindowOwner> w3_owner(CreateTestWindow()); - WmWindow* w3 = w3_owner->window(); - w3->Activate(); - w2->Activate(); - w1->Activate(); - - WmWindow::Windows window_list = mru_window_tracker()->BuildMruWindowList(); - ASSERT_EQ(3u, window_list.size()); - EXPECT_EQ(w1, window_list[0]); - EXPECT_EQ(w2, window_list[1]); - EXPECT_EQ(w3, window_list[2]); -} - -// Test that minimized windows are not treated specially. -TEST_F(MruWindowTrackerTest, MinimizedWindowsAreLru) { - // TODO(sky): fix me. Fails in mash because of http://crbug.com/654887. - if (WmShell::Get()->IsRunningInMash()) - return; - - std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); - WmWindow* w1 = w1_owner->window(); - std::unique_ptr<WindowOwner> w2_owner(CreateTestWindow()); - WmWindow* w2 = w2_owner->window(); - std::unique_ptr<WindowOwner> w3_owner(CreateTestWindow()); - WmWindow* w3 = w3_owner->window(); - std::unique_ptr<WindowOwner> w4_owner(CreateTestWindow()); - WmWindow* w4 = w4_owner->window(); - std::unique_ptr<WindowOwner> w5_owner(CreateTestWindow()); - WmWindow* w5 = w5_owner->window(); - std::unique_ptr<WindowOwner> w6_owner(CreateTestWindow()); - WmWindow* w6 = w6_owner->window(); - w6->Activate(); - w5->Activate(); - w4->Activate(); - w3->Activate(); - w2->Activate(); - w1->Activate(); - - w1->GetWindowState()->Minimize(); - w4->GetWindowState()->Minimize(); - w5->GetWindowState()->Minimize(); - - // By minimizing the first window, we activate w2 which will move it to the - // front of the MRU queue. - EXPECT_TRUE(w2->IsActive()); - - WmWindow::Windows window_list = mru_window_tracker()->BuildMruWindowList(); - EXPECT_EQ(w2, window_list[0]); - EXPECT_EQ(w1, window_list[1]); - EXPECT_EQ(w3, window_list[2]); - EXPECT_EQ(w4, window_list[3]); - EXPECT_EQ(w5, window_list[4]); - EXPECT_EQ(w6, window_list[5]); -} - -// Tests that windows being dragged are only in the WindowList once. -TEST_F(MruWindowTrackerTest, DraggedWindowsInListOnlyOnce) { - std::unique_ptr<WindowOwner> w1_owner(CreateTestWindow()); - WmWindow* w1 = w1_owner->window(); - w1->Activate(); - - // Start dragging the window. - w1->GetWindowState()->CreateDragDetails( - gfx::Point(), HTRIGHT, aura::client::WINDOW_MOVE_SOURCE_TOUCH); - - // During a drag the window is reparented by the Docked container. - WmWindow* drag_container = w1->GetRootWindow()->GetChildByShellWindowId( - kShellWindowId_DockedContainer); - drag_container->AddChild(w1); - EXPECT_TRUE(w1->GetWindowState()->is_dragged()); - - // The dragged window should only be in the list once. - WmWindow::Windows window_list = - mru_window_tracker()->BuildWindowListIgnoreModal(); - EXPECT_EQ(1, std::count(window_list.begin(), window_list.end(), w1)); -} - -} // namespace ash
diff --git a/ash/wm/overview/cleanup_animation_observer.cc b/ash/wm/overview/cleanup_animation_observer.cc deleted file mode 100644 index 32f9c98..0000000 --- a/ash/wm/overview/cleanup_animation_observer.cc +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/cleanup_animation_observer.h" - -#include "ui/views/widget/widget.h" - -namespace ash { - -CleanupAnimationObserver::CleanupAnimationObserver( - std::unique_ptr<views::Widget> widget) - : widget_(std::move(widget)), owner_(nullptr) { - DCHECK(widget_); -} - -CleanupAnimationObserver::~CleanupAnimationObserver() {} - -void CleanupAnimationObserver::OnImplicitAnimationsCompleted() { - // |widget_| may get reset if Shutdown() is called prior to this method. - if (!widget_) - return; - if (owner_) { - owner_->RemoveAndDestroyAnimationObserver(this); - return; - } - delete this; -} - -void CleanupAnimationObserver::SetOwner(WindowSelectorDelegate* owner) { - owner_ = owner; -} - -void CleanupAnimationObserver::Shutdown() { - widget_.reset(); - owner_ = nullptr; -} - -} // namespace ash
diff --git a/ash/wm/overview/cleanup_animation_observer.h b/ash/wm/overview/cleanup_animation_observer.h deleted file mode 100644 index 06e5757e..0000000 --- a/ash/wm/overview/cleanup_animation_observer.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_ -#define ASH_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "base/macros.h" -#include "ui/compositor/layer_animation_observer.h" - -namespace views { -class Widget; -} - -namespace ash { - -// An observer which holds onto the passed widget until the animation is -// complete. -class ASH_EXPORT CleanupAnimationObserver - : public ui::ImplicitAnimationObserver, - public DelayedAnimationObserver { - public: - explicit CleanupAnimationObserver(std::unique_ptr<views::Widget> widget); - ~CleanupAnimationObserver() override; - - // ui::ImplicitAnimationObserver: - // TODO(varkha): Look into all cases when animations are not started such as - // zero-duration animations and ensure that the object lifetime is handled. - void OnImplicitAnimationsCompleted() override; - - // DelayedAnimationObserver: - void SetOwner(WindowSelectorDelegate* owner) override; - void Shutdown() override; - - private: - std::unique_ptr<views::Widget> widget_; - WindowSelectorDelegate* owner_; - - DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserver); -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_CLEANUP_ANIMATION_OBSERVER_H_
diff --git a/ash/wm/overview/cleanup_animation_observer_unittest.cc b/ash/wm/overview/cleanup_animation_observer_unittest.cc deleted file mode 100644 index 4a16de6..0000000 --- a/ash/wm/overview/cleanup_animation_observer_unittest.cc +++ /dev/null
@@ -1,185 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/cleanup_animation_observer.h" - -#include <vector> - -#include "ash/common/wm_window.h" -#include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_observer.h" - -namespace ash { -namespace { - -class TestWindowSelectorDelegate : public WindowSelectorDelegate { - public: - TestWindowSelectorDelegate() = default; - - ~TestWindowSelectorDelegate() override { - // Destroy widgets that may be still animating if shell shuts down soon - // after exiting overview mode. - for (std::unique_ptr<DelayedAnimationObserver>& observer : observers_) - observer->Shutdown(); - } - - // WindowSelectorDelegate: - void OnSelectionEnded() override {} - - void AddDelayedAnimationObserver( - std::unique_ptr<DelayedAnimationObserver> animation_observer) override { - animation_observer->SetOwner(this); - observers_.push_back(std::move(animation_observer)); - } - - void RemoveAndDestroyAnimationObserver( - DelayedAnimationObserver* animation_observer) override { - class IsEqual { - public: - explicit IsEqual(DelayedAnimationObserver* animation_observer) - : animation_observer_(animation_observer) {} - bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) { - return (other.get() == animation_observer_); - } - - private: - const DelayedAnimationObserver* animation_observer_; - }; - observers_.erase(std::remove_if(observers_.begin(), observers_.end(), - IsEqual(animation_observer)), - observers_.end()); - } - - private: - std::vector<std::unique_ptr<DelayedAnimationObserver>> observers_; - - DISALLOW_COPY_AND_ASSIGN(TestWindowSelectorDelegate); -}; - -class CleanupAnimationObserverTest : public test::AshTestBase, - public views::WidgetObserver { - public: - CleanupAnimationObserverTest() = default; - - ~CleanupAnimationObserverTest() override { - if (widget_) - widget_->RemoveObserver(this); - } - - // Creates a Widget containing a Window with the given |bounds|. This should - // be used when the test requires a Widget. For example any test that will - // cause a window to be closed via - // views::Widget::GetWidgetForNativeView(window)->Close(). - std::unique_ptr<views::Widget> CreateWindowWidget(const gfx::Rect& bounds) { - std::unique_ptr<views::Widget> widget(new views::Widget); - views::Widget::InitParams params; - params.bounds = bounds; - params.type = views::Widget::InitParams::TYPE_WINDOW; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - widget->Init(params); - widget->Show(); - ParentWindowInPrimaryRootWindow(widget->GetNativeWindow()); - widget->AddObserver(this); - widget_ = widget.get(); - return widget; - } - - protected: - bool widget_destroyed() { return !widget_; } - - private: - void OnWidgetDestroyed(views::Widget* widget) override { - if (widget_ == widget) - widget_ = nullptr; - } - - views::Widget* widget_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(CleanupAnimationObserverTest); -}; - -} // namespace - -// Tests that basic create-destroy sequence does not crash. -TEST_F(CleanupAnimationObserverTest, CreateDestroy) { - TestWindowSelectorDelegate delegate; - std::unique_ptr<views::Widget> widget( - CreateWindowWidget(gfx::Rect(0, 0, 40, 40))); - std::unique_ptr<CleanupAnimationObserver> observer( - new CleanupAnimationObserver(std::move(widget))); - delegate.AddDelayedAnimationObserver(std::move(observer)); -} - -// Tests that completing animation deletes the animation observer and the -// test widget and that deleting the WindowSelectorDelegate instance which -// owns the observer does not crash. -TEST_F(CleanupAnimationObserverTest, CreateAnimateComplete) { - TestWindowSelectorDelegate delegate; - std::unique_ptr<views::Widget> widget( - CreateWindowWidget(gfx::Rect(0, 0, 40, 40))); - WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); - { - ui::ScopedLayerAnimationSettings animation_settings( - widget_window->GetLayer()->GetAnimator()); - animation_settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(1000)); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - - std::unique_ptr<CleanupAnimationObserver> observer( - new CleanupAnimationObserver(std::move(widget))); - animation_settings.AddObserver(observer.get()); - delegate.AddDelayedAnimationObserver(std::move(observer)); - - widget_window->SetBounds(gfx::Rect(50, 50, 60, 60)); - } - // The widget should be destroyed when |animation_settings| gets out of scope - // which in absence of NON_ZERO_DURATION animation duration mode completes - // the animation and calls OnImplicitAnimationsCompleted() on the cleanup - // observer and auto-deletes the owned widget. - EXPECT_TRUE(widget_destroyed()); - // TestWindowSelectorDelegate going out of scope should not crash. -} - -// Tests that starting an animation and exiting doesn't crash. If not for -// TestWindowSelectorDelegate calling Shutdown() on a CleanupAnimationObserver -// instance in destructor, this test would have crashed. -TEST_F(CleanupAnimationObserverTest, CreateAnimateShutdown) { - TestWindowSelectorDelegate delegate; - std::unique_ptr<views::Widget> widget( - CreateWindowWidget(gfx::Rect(0, 0, 40, 40))); - WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); - { - // Normal animations for tests have ZERO_DURATION, make sure we are actually - // animating the movement. - ui::ScopedAnimationDurationScaleMode animation_scale_mode( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); - ui::ScopedLayerAnimationSettings animation_settings( - widget_window->GetLayer()->GetAnimator()); - animation_settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(1000)); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - - std::unique_ptr<CleanupAnimationObserver> observer( - new CleanupAnimationObserver(std::move(widget))); - animation_settings.AddObserver(observer.get()); - delegate.AddDelayedAnimationObserver(std::move(observer)); - - widget_window->SetBounds(gfx::Rect(50, 50, 60, 60)); - } - // The widget still exists. - EXPECT_FALSE(widget_destroyed()); - // The test widget is auto-deleted when |delegate| that owns it goes out of - // scope. The animation is still active when this happens which should not - // crash. -} - -} // namespace ash
diff --git a/ash/wm/overview/overview_animation_type.h b/ash/wm/overview/overview_animation_type.h deleted file mode 100644 index 089277e..0000000 --- a/ash/wm/overview/overview_animation_type.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_OVERVIEW_ANIMATION_TYPE_H_ -#define ASH_WM_OVERVIEW_OVERVIEW_ANIMATION_TYPE_H_ - -namespace ash { - -// Enumeration of the different overview mode animations. -enum OverviewAnimationType { - // TODO(bruthig): Remove OVERVIEW_ANIMATION_NONE value and replace it with - // correct animation type actions. - OVERVIEW_ANIMATION_NONE, - // Used to fade in the close button and label. - OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, - // Used to fade out the label. - OVERVIEW_ANIMATION_EXIT_OVERVIEW_MODE_FADE_OUT, - // Used to position windows when entering/exiting overview mode and when a - // window is closed while overview mode is active. - OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS, - // Used to restore windows to their original position when exiting overview - // mode. - OVERVIEW_ANIMATION_RESTORE_WINDOW, - // Used to animate scaling down of a window that is about to get closed while - // overview mode is active. - OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM, - // Used to animate hiding of a window that is closed while overview mode is - // active. - OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_OVERVIEW_ANIMATION_TYPE_H_
diff --git a/ash/wm/overview/scoped_overview_animation_settings.h b/ash/wm/overview/scoped_overview_animation_settings.h deleted file mode 100644 index a8898bfb..0000000 --- a/ash/wm/overview/scoped_overview_animation_settings.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_H_ -#define ASH_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_H_ - -namespace ui { -class ImplicitAnimationObserver; -} // namespace ui - -namespace ash { - -// ScopedOverviewAnimationSettings correctly configures the animation -// settings for a WmWindow given an OverviewAnimationType. -class ScopedOverviewAnimationSettings { - public: - virtual ~ScopedOverviewAnimationSettings() {} - virtual void AddObserver(ui::ImplicitAnimationObserver* observer) = 0; -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_H_
diff --git a/ash/wm/overview/scoped_overview_animation_settings_aura.h b/ash/wm/overview/scoped_overview_animation_settings_aura.h index 2203ff2..966b0edc 100644 --- a/ash/wm/overview/scoped_overview_animation_settings_aura.h +++ b/ash/wm/overview/scoped_overview_animation_settings_aura.h
@@ -7,8 +7,8 @@ #include <memory> -#include "ash/wm/overview/overview_animation_type.h" -#include "ash/wm/overview/scoped_overview_animation_settings.h" +#include "ash/common/wm/overview/overview_animation_type.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings.h" #include "base/macros.h" namespace aura {
diff --git a/ash/wm/overview/scoped_overview_animation_settings_factory.cc b/ash/wm/overview/scoped_overview_animation_settings_factory.cc deleted file mode 100644 index 5efc30d6..0000000 --- a/ash/wm/overview/scoped_overview_animation_settings_factory.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/scoped_overview_animation_settings_factory.h" - -#include "base/logging.h" - -namespace ash { - -// static -ScopedOverviewAnimationSettingsFactory* - ScopedOverviewAnimationSettingsFactory::instance_ = nullptr; - -// static -ScopedOverviewAnimationSettingsFactory* -ScopedOverviewAnimationSettingsFactory::Get() { - return instance_; -} - -ScopedOverviewAnimationSettingsFactory:: - ScopedOverviewAnimationSettingsFactory() { - DCHECK(!instance_); - instance_ = this; -} - -ScopedOverviewAnimationSettingsFactory:: - ~ScopedOverviewAnimationSettingsFactory() { - DCHECK_EQ(instance_, this); - instance_ = nullptr; -} - -} // namespace ash
diff --git a/ash/wm/overview/scoped_overview_animation_settings_factory.h b/ash/wm/overview/scoped_overview_animation_settings_factory.h deleted file mode 100644 index cb23ce3..0000000 --- a/ash/wm/overview/scoped_overview_animation_settings_factory.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_FACTORY_H_ -#define ASH_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_FACTORY_H_ - -#include <memory> - -#include "ash/wm/overview/overview_animation_type.h" - -namespace ash { - -class ScopedOverviewAnimationSettings; -class WmWindow; - -// Factory for creating ScopedOverviewAnimationSettings. -class ScopedOverviewAnimationSettingsFactory { - public: - static ScopedOverviewAnimationSettingsFactory* Get(); - - virtual std::unique_ptr<ScopedOverviewAnimationSettings> - CreateOverviewAnimationSettings(OverviewAnimationType animation_type, - WmWindow* window) = 0; - - protected: - ScopedOverviewAnimationSettingsFactory(); - virtual ~ScopedOverviewAnimationSettingsFactory(); - - private: - static ScopedOverviewAnimationSettingsFactory* instance_; -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_SCOPED_OVERVIEW_ANIMATION_SETTINGS_FACTORY_H_
diff --git a/ash/wm/overview/scoped_overview_animation_settings_factory_aura.h b/ash/wm/overview/scoped_overview_animation_settings_factory_aura.h index 41ce23c4..acad829 100644 --- a/ash/wm/overview/scoped_overview_animation_settings_factory_aura.h +++ b/ash/wm/overview/scoped_overview_animation_settings_factory_aura.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/wm/overview/scoped_overview_animation_settings_factory.h" +#include "ash/common/wm/overview/scoped_overview_animation_settings_factory.h" #include "base/macros.h" namespace ash {
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc deleted file mode 100644 index 99810eb..0000000 --- a/ash/wm/overview/scoped_transform_overview_window.cc +++ /dev/null
@@ -1,507 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/scoped_transform_overview_window.h" - -#include <algorithm> -#include <vector> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/wm/overview/scoped_overview_animation_settings.h" -#include "ash/wm/overview/scoped_overview_animation_settings_factory.h" -#include "ash/wm/overview/window_selector_item.h" -#include "ash/wm/window_state.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/compositor/layer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/safe_integer_conversions.h" -#include "ui/gfx/transform_util.h" -#include "ui/views/widget/widget.h" - -using WmWindows = std::vector<ash::WmWindow*>; - -namespace ash { - -namespace { - -// When set to true by tests makes closing the widget synchronous. -bool immediate_close_for_tests = false; - -// Delay closing window to allow it to shrink and fade out. -const int kCloseWindowDelayInMilliseconds = 150; - -WmWindow* GetTransientRoot(WmWindow* window) { - while (window && window->GetTransientParent()) - window = window->GetTransientParent(); - return window; -} - -std::unique_ptr<ScopedOverviewAnimationSettings> -CreateScopedOverviewAnimationSettings(OverviewAnimationType animation_type, - WmWindow* window) { - return ScopedOverviewAnimationSettingsFactory::Get() - ->CreateOverviewAnimationSettings(animation_type, window); -} - -// An iterator class that traverses a WmWindow and all of its transient -// descendants. -class TransientDescendantIterator { - public: - // Creates an empty iterator. - TransientDescendantIterator(); - - // Copy constructor required for iterator purposes. - TransientDescendantIterator(const TransientDescendantIterator& other) = - default; - - // Iterates over |root_window| and all of its transient descendants. - // Note |root_window| must not have a transient parent. - explicit TransientDescendantIterator(WmWindow* root_window); - - // Prefix increment operator. This assumes there are more items (i.e. - // *this != TransientDescendantIterator()). - const TransientDescendantIterator& operator++(); - - // Comparison for STL-based loops. - bool operator!=(const TransientDescendantIterator& other) const; - - // Dereference operator for STL-compatible iterators. - WmWindow* operator*() const; - - private: - // Explicit assignment operator defined because an explicit copy constructor - // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used. - TransientDescendantIterator& operator=( - const TransientDescendantIterator& other) = default; - - // The current window that |this| refers to. A null |current_window_| denotes - // an empty iterator and is used as the last possible value in the traversal. - WmWindow* current_window_; -}; - -// Provides a virtual container implementing begin() and end() for a sequence of -// TransientDescendantIterators. This can be used in range-based for loops. -class TransientDescendantIteratorRange { - public: - explicit TransientDescendantIteratorRange( - const TransientDescendantIterator& begin); - - // Copy constructor required for iterator purposes. - TransientDescendantIteratorRange( - const TransientDescendantIteratorRange& other) = default; - - const TransientDescendantIterator& begin() const { return begin_; } - const TransientDescendantIterator& end() const { return end_; } - - private: - // Explicit assignment operator defined because an explicit copy constructor - // is needed and therefore the DISALLOW_COPY_AND_ASSIGN macro cannot be used. - TransientDescendantIteratorRange& operator=( - const TransientDescendantIteratorRange& other) = default; - - TransientDescendantIterator begin_; - TransientDescendantIterator end_; -}; - -TransientDescendantIterator::TransientDescendantIterator() - : current_window_(nullptr) {} - -TransientDescendantIterator::TransientDescendantIterator(WmWindow* root_window) - : current_window_(root_window) { - DCHECK(!root_window->GetTransientParent()); -} - -// Performs a pre-order traversal of the transient descendants. -const TransientDescendantIterator& TransientDescendantIterator::operator++() { - DCHECK(current_window_); - - const WmWindows transient_children = current_window_->GetTransientChildren(); - - if (!transient_children.empty()) { - current_window_ = transient_children.front(); - } else { - while (current_window_) { - WmWindow* parent = current_window_->GetTransientParent(); - if (!parent) { - current_window_ = nullptr; - break; - } - const WmWindows transient_siblings = parent->GetTransientChildren(); - auto iter = std::find(transient_siblings.begin(), - transient_siblings.end(), current_window_); - ++iter; - if (iter != transient_siblings.end()) { - current_window_ = *iter; - break; - } - current_window_ = current_window_->GetTransientParent(); - } - } - return *this; -} - -bool TransientDescendantIterator::operator!=( - const TransientDescendantIterator& other) const { - return current_window_ != other.current_window_; -} - -WmWindow* TransientDescendantIterator::operator*() const { - return current_window_; -} - -TransientDescendantIteratorRange::TransientDescendantIteratorRange( - const TransientDescendantIterator& begin) - : begin_(begin) {} - -TransientDescendantIteratorRange GetTransientTreeIterator(WmWindow* window) { - return TransientDescendantIteratorRange( - TransientDescendantIterator(GetTransientRoot(window))); -} - -} // namespace - -ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(WmWindow* window) - : window_(window), - determined_original_window_shape_(false), - ignored_by_shelf_(window->GetWindowState()->ignored_by_shelf()), - overview_started_(false), - original_transform_(window->GetTargetTransform()), - original_opacity_(window->GetTargetOpacity()), - weak_ptr_factory_(this) {} - -ScopedTransformOverviewWindow::~ScopedTransformOverviewWindow() {} - -void ScopedTransformOverviewWindow::RestoreWindow() { - ShowHeader(); - if (minimized_widget_) { - // TODO(oshima): Use unminimize animation instead of hiding animation. - minimized_widget_->CloseNow(); - minimized_widget_.reset(); - return; - } - ScopedAnimationSettings animation_settings_list; - BeginScopedAnimation(OverviewAnimationType::OVERVIEW_ANIMATION_RESTORE_WINDOW, - &animation_settings_list); - SetTransform(window()->GetRootWindow(), original_transform_); - std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings = - CreateScopedOverviewAnimationSettings( - OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS, - window_); - window_->GetWindowState()->set_ignored_by_shelf(ignored_by_shelf_); - SetOpacity(original_opacity_); -} - -void ScopedTransformOverviewWindow::BeginScopedAnimation( - OverviewAnimationType animation_type, - ScopedAnimationSettings* animation_settings) { - for (auto* window : GetTransientTreeIterator(GetOverviewWindow())) { - animation_settings->push_back( - CreateScopedOverviewAnimationSettings(animation_type, window)); - } -} - -bool ScopedTransformOverviewWindow::Contains(const WmWindow* target) const { - for (auto* window : GetTransientTreeIterator(window_)) { - if (window->Contains(target)) - return true; - } - WmWindow* mirror = GetOverviewWindowForMinimizedState(); - return mirror && mirror->Contains(target); -} - -gfx::Rect ScopedTransformOverviewWindow::GetTargetBoundsInScreen() const { - gfx::Rect bounds; - WmWindow* overview_window = GetOverviewWindow(); - for (auto* window : GetTransientTreeIterator(overview_window)) { - // Ignore other window types when computing bounding box of window - // selector target item. - if (window != overview_window && - window->GetType() != ui::wm::WINDOW_TYPE_NORMAL && - window->GetType() != ui::wm::WINDOW_TYPE_PANEL) { - continue; - } - bounds.Union( - window->GetParent()->ConvertRectToScreen(window->GetTargetBounds())); - } - return bounds; -} - -gfx::Rect ScopedTransformOverviewWindow::GetTransformedBounds() const { - const int top_inset = GetTopInset(); - gfx::Rect bounds; - WmWindow* overview_window = GetOverviewWindow(); - for (auto* window : GetTransientTreeIterator(overview_window)) { - // Ignore other window types when computing bounding box of window - // selector target item. - if (window != overview_window && - (window->GetType() != ui::wm::WINDOW_TYPE_NORMAL && - window->GetType() != ui::wm::WINDOW_TYPE_PANEL)) { - continue; - } - gfx::RectF window_bounds(window->GetTargetBounds()); - gfx::Transform new_transform = - TransformAboutPivot(gfx::Point(window_bounds.x(), window_bounds.y()), - window->GetTargetTransform()); - new_transform.TransformRect(&window_bounds); - - // The preview title is shown above the preview window. Hide the window - // header for apps or browser windows with no tabs (web apps) to avoid - // showing both the window header and the preview title. - if (top_inset > 0) { - gfx::RectF header_bounds(window_bounds); - header_bounds.set_height(top_inset); - new_transform.TransformRect(&header_bounds); - window_bounds.Inset(0, gfx::ToCeiledInt(header_bounds.height()), 0, 0); - } - bounds.Union(window->GetParent()->ConvertRectToScreen( - ToEnclosingRect(window_bounds))); - } - return bounds; -} - -SkColor ScopedTransformOverviewWindow::GetTopColor() const { - for (auto* window : GetTransientTreeIterator(window_)) { - // If there are regular windows in the transient ancestor tree, all those - // windows are shown in the same overview item and the header is not masked. - if (window != window_ && (window->GetType() == ui::wm::WINDOW_TYPE_NORMAL || - window->GetType() == ui::wm::WINDOW_TYPE_PANEL)) { - return SK_ColorTRANSPARENT; - } - } - return window_->aura_window()->GetProperty(aura::client::kTopViewColor); -} - -int ScopedTransformOverviewWindow::GetTopInset() const { - // Mirror window doesn't have insets. - if (minimized_widget_) - return 0; - for (auto* window : GetTransientTreeIterator(window_)) { - // If there are regular windows in the transient ancestor tree, all those - // windows are shown in the same overview item and the header is not masked. - if (window != window_ && (window->GetType() == ui::wm::WINDOW_TYPE_NORMAL || - window->GetType() == ui::wm::WINDOW_TYPE_PANEL)) { - return 0; - } - } - return window_->aura_window()->GetProperty(aura::client::kTopViewInset); -} - -void ScopedTransformOverviewWindow::OnWindowDestroyed() { - window_ = nullptr; -} - -float ScopedTransformOverviewWindow::GetItemScale(const gfx::Size& source, - const gfx::Size& target, - int top_view_inset, - int title_height) { - return std::min(2.0f, static_cast<float>((target.height() - title_height)) / - (source.height() - top_view_inset)); -} - -gfx::Rect ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio( - const gfx::Rect& rect, - const gfx::Rect& bounds, - int top_view_inset, - int title_height) { - DCHECK(!rect.IsEmpty()); - DCHECK_LE(top_view_inset, rect.height()); - const float scale = - GetItemScale(rect.size(), bounds.size(), top_view_inset, title_height); - const int horizontal_offset = gfx::ToFlooredInt( - 0.5 * (bounds.width() - gfx::ToFlooredInt(scale * rect.width()))); - const int width = bounds.width() - 2 * horizontal_offset; - const int vertical_offset = - title_height - gfx::ToCeiledInt(scale * top_view_inset); - const int height = std::min(gfx::ToCeiledInt(scale * rect.height()), - bounds.height() - vertical_offset); - return gfx::Rect(bounds.x() + horizontal_offset, bounds.y() + vertical_offset, - width, height); -} - -gfx::Transform ScopedTransformOverviewWindow::GetTransformForRect( - const gfx::Rect& src_rect, - const gfx::Rect& dst_rect) { - DCHECK(!src_rect.IsEmpty()); - gfx::Transform transform; - transform.Translate(dst_rect.x() - src_rect.x(), dst_rect.y() - src_rect.y()); - transform.Scale(static_cast<float>(dst_rect.width()) / src_rect.width(), - static_cast<float>(dst_rect.height()) / src_rect.height()); - return transform; -} - -void ScopedTransformOverviewWindow::SetTransform( - WmWindow* root_window, - const gfx::Transform& transform) { - DCHECK(overview_started_); - - if (&transform != &original_transform_ && - !determined_original_window_shape_) { - determined_original_window_shape_ = true; - SkRegion* window_shape = window()->GetLayer()->alpha_shape(); - if (!original_window_shape_ && window_shape) - original_window_shape_.reset(new SkRegion(*window_shape)); - } - - gfx::Point target_origin(GetTargetBoundsInScreen().origin()); - for (auto* window : GetTransientTreeIterator(GetOverviewWindow())) { - WmWindow* parent_window = window->GetParent(); - gfx::Point original_origin = - parent_window->ConvertRectToScreen(window->GetTargetBounds()).origin(); - gfx::Transform new_transform = - TransformAboutPivot(gfx::Point(target_origin.x() - original_origin.x(), - target_origin.y() - original_origin.y()), - transform); - window->SetTransform(new_transform); - } -} - -void ScopedTransformOverviewWindow::SetOpacity(float opacity) { - for (auto* window : GetTransientTreeIterator(GetOverviewWindow())) { - window->SetOpacity(opacity); - } -} - -void ScopedTransformOverviewWindow::HideHeader() { - // Mirrored Window does not have a header. - if (minimized_widget_) - return; - gfx::Rect bounds(GetTargetBoundsInScreen().size()); - const int inset = GetTopInset(); - if (inset > 0) { - // Use alpha shape to hide the window header. - bounds.Inset(0, inset, 0, 0); - std::unique_ptr<SkRegion> region(new SkRegion); - region->setRect(RectToSkIRect(bounds)); - if (original_window_shape_) - region->op(*original_window_shape_, SkRegion::kIntersect_Op); - WmWindow* window = GetOverviewWindow(); - window->GetLayer()->SetAlphaShape(std::move(region)); - window->SetMasksToBounds(true); - } -} - -void ScopedTransformOverviewWindow::ShowHeader() { - ui::Layer* layer = window()->GetLayer(); - if (original_window_shape_) { - layer->SetAlphaShape( - base::MakeUnique<SkRegion>(*original_window_shape_.get())); - } else { - layer->SetAlphaShape(nullptr); - } - window()->SetMasksToBounds(false); -} - -void ScopedTransformOverviewWindow::UpdateMirrorWindowForMinimizedState() { - // TODO(oshima): Disable animation. - if (window_->GetShowState() == ui::SHOW_STATE_MINIMIZED) { - if (!minimized_widget_) - CreateMirrorWindowForMinimizedState(); - } else { - minimized_widget_->CloseNow(); - minimized_widget_.reset(); - } -} - -void ScopedTransformOverviewWindow::Close() { - if (immediate_close_for_tests) { - CloseWidget(); - return; - } - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&ScopedTransformOverviewWindow::CloseWidget, - weak_ptr_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(kCloseWindowDelayInMilliseconds)); -} - -void ScopedTransformOverviewWindow::PrepareForOverview() { - DCHECK(!overview_started_); - overview_started_ = true; - window_->GetWindowState()->set_ignored_by_shelf(true); - if (window_->GetShowState() == ui::SHOW_STATE_MINIMIZED) - CreateMirrorWindowForMinimizedState(); -} - -void ScopedTransformOverviewWindow::CloseWidget() { - WmWindow* parent_window = GetTransientRoot(window_); - if (parent_window) - parent_window->CloseWidget(); -} - -// static -void ScopedTransformOverviewWindow::SetImmediateCloseForTests() { - immediate_close_for_tests = true; -} - -WmWindow* ScopedTransformOverviewWindow::GetOverviewWindow() const { - if (minimized_widget_) - return GetOverviewWindowForMinimizedState(); - return window_; -} - -void ScopedTransformOverviewWindow::EnsureVisible() { - original_opacity_ = 1.f; -} - -void ScopedTransformOverviewWindow::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP) { - EnsureVisible(); - window_->Show(); - window_->Activate(); - } -} - -void ScopedTransformOverviewWindow::OnMouseEvent(ui::MouseEvent* event) { - if (event->type() == ui::ET_MOUSE_PRESSED && event->IsOnlyLeftMouseButton()) { - EnsureVisible(); - window_->Show(); - window_->Activate(); - } -} - -WmWindow* ScopedTransformOverviewWindow::GetOverviewWindowForMinimizedState() - const { - return minimized_widget_ ? WmWindow::Get(minimized_widget_->GetNativeWindow()) - : nullptr; -} - -void ScopedTransformOverviewWindow::CreateMirrorWindowForMinimizedState() { - DCHECK(!minimized_widget_.get()); - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.visible_on_all_workspaces = true; - params.name = "OverviewModeMinimized"; - params.activatable = views::Widget::InitParams::Activatable::ACTIVATABLE_NO; - params.accept_events = true; - minimized_widget_.reset(new views::Widget); - window_->GetRootWindow() - ->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - minimized_widget_.get(), window_->GetParent()->GetShellWindowId(), - ¶ms); - minimized_widget_->set_focus_on_creation(false); - minimized_widget_->Init(params); - - views::View* mirror_view = window_->CreateViewWithRecreatedLayers().release(); - mirror_view->SetVisible(true); - mirror_view->SetTargetHandler(this); - minimized_widget_->SetContentsView(mirror_view); - gfx::Rect bounds(window_->GetBoundsInScreen()); - gfx::Size preferred = mirror_view->GetPreferredSize(); - // In unit tests, the content view can have empty size. - if (!preferred.IsEmpty()) { - int inset = bounds.height() - preferred.height(); - bounds.Inset(0, 0, 0, inset); - } - minimized_widget_->SetBounds(bounds); - minimized_widget_->Show(); -} - -} // namespace ash
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h deleted file mode 100644 index f57a5cb..0000000 --- a/ash/wm/overview/scoped_transform_overview_window.h +++ /dev/null
@@ -1,198 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ -#define ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_ - -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/wm/overview/overview_animation_type.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/events/event_handler.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/transform.h" - -class SkRegion; - -namespace gfx { -class Rect; -} - -namespace views { -class Widget; -} - -namespace ash { - -class ScopedOverviewAnimationSettings; -class WmWindow; - -// Manages a window, and it's transient children, in the overview mode. This -// class allows transforming the windows with a helper to determine the best -// fit in certain bounds. The window's state is restored on destruction of this -// object. -class ASH_EXPORT ScopedTransformOverviewWindow : public ui::EventHandler { - public: - class OverviewContentMask; - using ScopedAnimationSettings = - std::vector<std::unique_ptr<ScopedOverviewAnimationSettings>>; - - // Calculates and returns an optimal scale ratio. With MD this is only - // taking into account |size.height()| as the width can vary. Without MD this - // returns the scale that allows the item to fully fit within |size|. - static float GetItemScale(const gfx::Size& source, - const gfx::Size& target, - int top_view_inset, - int title_height); - - // Returns |rect| having been shrunk to fit within |bounds| (preserving the - // aspect ratio). Takes into account a window header that is |top_view_inset| - // tall in the original window getting replaced by a window caption that is - // |title_height| tall in transformed window. - static gfx::Rect ShrinkRectToFitPreservingAspectRatio(const gfx::Rect& rect, - const gfx::Rect& bounds, - int top_view_inset, - int title_height); - - // Returns the transform turning |src_rect| into |dst_rect|. - static gfx::Transform GetTransformForRect(const gfx::Rect& src_rect, - const gfx::Rect& dst_rect); - - explicit ScopedTransformOverviewWindow(WmWindow* window); - ~ScopedTransformOverviewWindow() override; - - // Starts an animation sequence which will use animation settings specified by - // |animation_type|. The |animation_settings| container is populated with - // scoped entities and the container should be destroyed at the end of the - // animation sequence. - // - // Example: - // ScopedTransformOverviewWindow overview_window(window); - // ScopedTransformOverviewWindow::ScopedAnimationSettings scoped_settings; - // overview_window.BeginScopedAnimation( - // OverviewAnimationType::OVERVIEW_ANIMATION_SELECTOR_ITEM_SCROLL_CANCEL, - // &animation_settings); - // // Calls to SetTransform & SetOpacity will use the same animation settings - // // until scoped_settings is destroyed. - // overview_window.SetTransform(root_window, new_transform); - // overview_window.SetOpacity(1); - void BeginScopedAnimation(OverviewAnimationType animation_type, - ScopedAnimationSettings* animation_settings); - - // Returns true if this window selector window contains the |target|. - bool Contains(const WmWindow* target) const; - - // Returns the original target bounds of all transformed windows. - gfx::Rect GetTargetBoundsInScreen() const; - - // Calculates the bounds of a |window_| after being transformed to the - // selector's space. Those bounds are a union of all regular (normal and - // panel) windows in the |window_|'s transient hierarchy. The returned Rect is - // in virtual screen coordinates. The returned bounds are adjusted to allow - // the original |window_|'s header to be hidden. - gfx::Rect GetTransformedBounds() const; - - // Returns TOP_VIEW_COLOR property of |window_| unless there are transient - // ancestors in which case returns SK_ColorTRANSPARENT. - SkColor GetTopColor() const; - - // Returns TOP_VIEW_INSET property of |window_| unless there are transient - // ancestors in which case returns 0. - int GetTopInset() const; - - // Restores and animates the managed window to it's non overview mode state. - void RestoreWindow(); - - // Informs the ScopedTransformOverviewWindow that the window being watched was - // destroyed. This resets the internal window pointer. - void OnWindowDestroyed(); - - // Prepares for overview mode by doing any necessary actions before entering. - void PrepareForOverview(); - - // Applies the |transform| to the overview window and all of its transient - // children. - void SetTransform(WmWindow* root_window, const gfx::Transform& transform); - - // Set's the opacity of the managed windows. - void SetOpacity(float opacity); - - // Hides the window header whose size is given in |TOP_VIEW_INSET| - // window property. - void HideHeader(); - - // Shows the window header that is hidden by HideHeader(). - void ShowHeader(); - - // Creates/Deletes a mirror window for minimized windows. - void UpdateMirrorWindowForMinimizedState(); - - WmWindow* window() const { return window_; } - - // Closes the transient root of the window managed by |this|. - void Close(); - - // Returns the window used to show the content in overview mdoe. - // For minmiezd window, this will be a window that hosts mirrored layers. - WmWindow* GetOverviewWindow() const; - - // Ensures that a window is visible by setting its opacity to 1. - void EnsureVisible(); - - // Returns the window created for minimized window, or nullptr - // if it does not exit. - WmWindow* GetOverviewWindowForMinimizedState() const; - - // ui::EventHandler: - void OnGestureEvent(ui::GestureEvent* event) override; - void OnMouseEvent(ui::MouseEvent* event) override; - - private: - friend class WindowSelectorTest; - - // Closes the window managed by |this|. - void CloseWidget(); - - void CreateMirrorWindowForMinimizedState(); - - // Makes Close() execute synchronously when used in tests. - static void SetImmediateCloseForTests(); - - // A weak pointer to the real window in the overview. - WmWindow* window_; - - // Original window shape, if it was set on a window. - std::unique_ptr<SkRegion> original_window_shape_; - - // True after the |original_window_shape_| has been set or after it has - // been determined that window shape was not originally set on the |window_|. - bool determined_original_window_shape_; - - // Tracks if this window was ignored by the shelf. - bool ignored_by_shelf_; - - // True if the window has been transformed for overview mode. - bool overview_started_; - - // The original transform of the window before entering overview mode. - gfx::Transform original_transform_; - - // The original opacity of the window before entering overview mode. - float original_opacity_; - - // A window that holds the content for minimized window. - std::unique_ptr<views::Widget> minimized_widget_; - - base::WeakPtrFactory<ScopedTransformOverviewWindow> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTransformOverviewWindow); -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_SCOPED_TRANSFORM_OVERVIEW_WINDOW_H_
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc deleted file mode 100644 index 8b2a68d..0000000 --- a/ash/wm/overview/window_grid.cc +++ /dev/null
@@ -1,844 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/window_grid.h" - -#include <algorithm> -#include <functional> -#include <set> -#include <utility> -#include <vector> - -#include "ash/common/ash_switches.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shelf_types.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/overview/cleanup_animation_observer.h" -#include "ash/wm/overview/scoped_overview_animation_settings.h" -#include "ash/wm/overview/scoped_overview_animation_settings_factory.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "ash/wm/overview/window_selector_item.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_screen_util.h" -#include "base/command_line.h" -#include "base/i18n/string_search.h" -#include "base/memory/ptr_util.h" -#include "base/strings/string_number_conversions.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/pathops/SkPathOps.h" -#include "ui/compositor/layer_animation_observer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/animation/tween.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/safe_integer_conversions.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/gfx/scoped_canvas.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/painter.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/core/shadow.h" -#include "ui/wm/core/shadow_types.h" -#include "ui/wm/core/window_animations.h" - -namespace ash { -namespace { - -using Windows = std::vector<WmWindow*>; - -// A comparator for locating a given target window. -struct WindowSelectorItemComparator { - explicit WindowSelectorItemComparator(const WmWindow* target_window) - : target(target_window) {} - - bool operator()(std::unique_ptr<WindowSelectorItem>& window) const { - return window->GetWindow() == target; - } - - const WmWindow* target; -}; - -// Time it takes for the selector widget to move to the next target. The same -// time is used for fading out shield widget when the overview mode is opened -// or closed. -const int kOverviewSelectorTransitionMilliseconds = 250; - -// The color and opacity of the screen shield in overview. -const SkColor kShieldColor = SkColorSetARGB(255, 0, 0, 0); -const float kShieldOpacity = 0.7f; - -// The color and opacity of the overview selector. -const SkColor kWindowSelectionColor = SkColorSetARGB(51, 255, 255, 255); -const SkColor kWindowSelectionBorderColor = SkColorSetARGB(76, 255, 255, 255); - -// Border thickness of overview selector. -const int kWindowSelectionBorderThickness = 1; - -// Corner radius of the overview selector border. -const int kWindowSelectionRadius = 4; - -// In the conceptual overview table, the window margin is the space reserved -// around the window within the cell. This margin does not overlap so the -// closest distance between adjacent windows will be twice this amount. -const int kWindowMargin = 5; - -// Windows are not allowed to get taller than this. -const int kMaxHeight = 512; - -// Margins reserved in the overview mode. -const float kOverviewInsetRatio = 0.05f; - -// Additional vertical inset reserved for windows in overview mode. -const float kOverviewVerticalInset = 0.1f; - -// A View having rounded corners and a specified background color which is -// only painted within the bounds defined by the rounded corners. -// TODO(varkha): This duplicates code from RoundedImageView. Refactor these -// classes and move into ui/views. -class RoundedRectView : public views::View { - public: - RoundedRectView(int corner_radius, SkColor background) - : corner_radius_(corner_radius), background_(background) {} - - ~RoundedRectView() override {} - - void OnPaint(gfx::Canvas* canvas) override { - views::View::OnPaint(canvas); - - SkScalar radius = SkIntToScalar(corner_radius_); - const SkScalar kRadius[8] = {radius, radius, radius, radius, - radius, radius, radius, radius}; - SkPath path; - gfx::Rect bounds(size()); - bounds.set_height(bounds.height() + radius); - path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); - - canvas->ClipPath(path, true); - canvas->DrawColor(background_); - } - - private: - int corner_radius_; - SkColor background_; - - DISALLOW_COPY_AND_ASSIGN(RoundedRectView); -}; - -// BackgroundWith1PxBorder renders a solid background color, with a one pixel -// border with rounded corners. This accounts for the scaling of the canvas, so -// that the border is 1 pixel thick regardless of display scaling. -class BackgroundWith1PxBorder : public views::Background { - public: - BackgroundWith1PxBorder(SkColor background, - SkColor border_color, - int border_thickness, - int corner_radius); - - void Paint(gfx::Canvas* canvas, views::View* view) const override; - - private: - // Color for the one pixel border. - SkColor border_color_; - - // Thickness of border inset. - int border_thickness_; - - // Corner radius of the inside edge of the roundrect border stroke. - int corner_radius_; - - DISALLOW_COPY_AND_ASSIGN(BackgroundWith1PxBorder); -}; - -BackgroundWith1PxBorder::BackgroundWith1PxBorder(SkColor background, - SkColor border_color, - int border_thickness, - int corner_radius) - : border_color_(border_color), - border_thickness_(border_thickness), - corner_radius_(corner_radius) { - SetNativeControlColor(background); -} - -void BackgroundWith1PxBorder::Paint(gfx::Canvas* canvas, - views::View* view) const { - gfx::RectF border_rect_f(view->GetContentsBounds()); - - gfx::ScopedCanvas scoped_canvas(canvas); - const float scale = canvas->UndoDeviceScaleFactor(); - border_rect_f.Scale(scale); - const float inset = border_thickness_ * scale - 0.5f; - border_rect_f.Inset(inset, inset); - - SkPath path; - const SkScalar scaled_corner_radius = - SkFloatToScalar(corner_radius_ * scale + 0.5f); - path.addRoundRect(gfx::RectFToSkRect(border_rect_f), scaled_corner_radius, - scaled_corner_radius); - - cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kStroke_Style); - flags.setStrokeWidth(1); - flags.setAntiAlias(true); - - SkPath stroke_path; - flags.getFillPath(path, &stroke_path); - - SkPath fill_path; - Op(path, stroke_path, kDifference_SkPathOp, &fill_path); - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setColor(get_color()); - canvas->sk_canvas()->drawPath(fill_path, flags); - - if (border_thickness_ > 0) { - flags.setColor(border_color_); - canvas->sk_canvas()->drawPath(stroke_path, flags); - } -} - -// Returns the vector for the fade in animation. -gfx::Vector2d GetSlideVectorForFadeIn(WindowSelector::Direction direction, - const gfx::Rect& bounds) { - gfx::Vector2d vector; - switch (direction) { - case WindowSelector::UP: - case WindowSelector::LEFT: - vector.set_x(-bounds.width()); - break; - case WindowSelector::DOWN: - case WindowSelector::RIGHT: - vector.set_x(bounds.width()); - break; - } - return vector; -} - -// Creates and returns a background translucent widget parented in -// |root_window|'s default container and having |background_color|. -// When |border_thickness| is non-zero, a border is created having -// |border_color|, otherwise |border_color| parameter is ignored. -// The new background widget starts with |initial_opacity| and then fades in. -views::Widget* CreateBackgroundWidget(WmWindow* root_window, - ui::LayerType layer_type, - SkColor background_color, - int border_thickness, - int border_radius, - SkColor border_color, - float initial_opacity) { - views::Widget* widget = new views::Widget; - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_POPUP; - params.keep_on_top = false; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.layer_type = layer_type; - params.accept_events = false; - widget->set_focus_on_creation(false); - // Parenting in kShellWindowId_WallpaperContainer allows proper layering of - // the shield and selection widgets. Since that container is created with - // USE_LOCAL_COORDINATES BoundsInScreenBehavior local bounds in |root_window_| - // need to be provided. - root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - widget, kShellWindowId_WallpaperContainer, ¶ms); - widget->Init(params); - WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); - // Disable the "bounce in" animation when showing the window. - widget_window->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); - // The background widget should not activate the shelf when passing under it. - widget_window->GetWindowState()->set_ignored_by_shelf(true); - if (params.layer_type == ui::LAYER_SOLID_COLOR) { - widget_window->GetLayer()->SetColor(background_color); - } else { - views::View* content_view = - new RoundedRectView(border_radius, SK_ColorTRANSPARENT); - content_view->set_background(new BackgroundWith1PxBorder( - background_color, border_color, border_thickness, border_radius)); - widget->SetContentsView(content_view); - } - widget_window->GetParent()->StackChildAtTop(widget_window); - widget->Show(); - widget_window->SetOpacity(initial_opacity); - return widget; -} - -bool IsMinimizedStateType(wm::WindowStateType type) { - return type == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED || - type == wm::WINDOW_STATE_TYPE_MINIMIZED; -} - -} // namespace - -WindowGrid::WindowGrid(WmWindow* root_window, - const std::vector<WmWindow*>& windows, - WindowSelector* window_selector) - : root_window_(root_window), - window_selector_(window_selector), - window_observer_(this), - window_state_observer_(this), - selected_index_(0), - num_columns_(0), - prepared_for_overview_(false) { - std::vector<WmWindow*> windows_in_root; - for (auto* window : windows) { - if (window->GetRootWindow() == root_window) - windows_in_root.push_back(window); - } - - for (auto* window : windows_in_root) { - window_observer_.Add(window->aura_window()); - window_state_observer_.Add(window->GetWindowState()); - window_list_.push_back( - base::MakeUnique<WindowSelectorItem>(window, window_selector_)); - } -} - -WindowGrid::~WindowGrid() {} - -void WindowGrid::Shutdown() { - for (const auto& window : window_list_) - window->Shutdown(); - - if (shield_widget_) { - // Fade out the shield widget. This animation continues past the lifetime - // of |this|. - WmWindow* widget_window = WmWindow::Get(shield_widget_->GetNativeWindow()); - ui::ScopedLayerAnimationSettings animation_settings( - widget_window->GetLayer()->GetAnimator()); - animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( - kOverviewSelectorTransitionMilliseconds)); - animation_settings.SetTweenType(gfx::Tween::EASE_OUT); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - // CleanupAnimationObserver will delete itself (and the shield widget) when - // the opacity animation is complete. - // Ownership over the observer is passed to the window_selector_->delegate() - // which has longer lifetime so that animations can continue even after the - // overview mode is shut down. - views::Widget* shield_widget = shield_widget_.get(); - std::unique_ptr<CleanupAnimationObserver> observer( - new CleanupAnimationObserver(std::move(shield_widget_))); - animation_settings.AddObserver(observer.get()); - window_selector_->delegate()->AddDelayedAnimationObserver( - std::move(observer)); - shield_widget->SetOpacity(0.f); - } -} - -void WindowGrid::PrepareForOverview() { - InitShieldWidget(); - for (const auto& window : window_list_) - window->PrepareForOverview(); - prepared_for_overview_ = true; -} - -void WindowGrid::PositionWindows(bool animate) { - if (window_selector_->is_shut_down() || window_list_.empty()) - return; - DCHECK(shield_widget_.get()); - // Keep the background shield widget covering the whole screen. - WmWindow* widget_window = WmWindow::Get(shield_widget_->GetNativeWindow()); - const gfx::Rect bounds = widget_window->GetParent()->GetBounds(); - widget_window->SetBounds(bounds); - gfx::Rect total_bounds = - root_window_->ConvertRectToScreen(wm::GetDisplayWorkAreaBoundsInParent( - root_window_->GetChildByShellWindowId( - kShellWindowId_DefaultContainer))); - // Windows occupy vertically centered area with additional vertical insets. - int horizontal_inset = - gfx::ToFlooredInt(std::min(kOverviewInsetRatio * total_bounds.width(), - kOverviewInsetRatio * total_bounds.height())); - int vertical_inset = - horizontal_inset + - kOverviewVerticalInset * (total_bounds.height() - 2 * horizontal_inset); - total_bounds.Inset(std::max(0, horizontal_inset - kWindowMargin), - std::max(0, vertical_inset - kWindowMargin)); - std::vector<gfx::Rect> rects; - - // Keep track of the lowest coordinate. - int max_bottom = total_bounds.y(); - - // Right bound of the narrowest row. - int min_right = total_bounds.right(); - // Right bound of the widest row. - int max_right = total_bounds.x(); - - // Keep track of the difference between the narrowest and the widest row. - // Initially this is set to the worst it can ever be assuming the windows fit. - int width_diff = total_bounds.width(); - - // Initially allow the windows to occupy all available width. Shrink this - // available space horizontally to find the breakdown into rows that achieves - // the minimal |width_diff|. - int right_bound = total_bounds.right(); - - // Determine the optimal height bisecting between |low_height| and - // |high_height|. Once this optimal height is known, |height_fixed| is set to - // true and the rows are balanced by repeatedly squeezing the widest row to - // cause windows to overflow to the subsequent rows. - int low_height = 2 * kWindowMargin; - int high_height = - std::max(low_height, static_cast<int>(total_bounds.height() + 1)); - int height = 0.5 * (low_height + high_height); - bool height_fixed = false; - - // Repeatedly try to fit the windows |rects| within |right_bound|. - // If a maximum |height| is found such that all window |rects| fit, this - // fitting continues while shrinking the |right_bound| in order to balance the - // rows. If the windows fit the |right_bound| would have been decremented at - // least once so it needs to be incremented once before getting out of this - // loop and one additional pass made to actually fit the |rects|. - // If the |rects| cannot fit (e.g. there are too many windows) the bisection - // will still finish and we might increment the |right_bound| once pixel extra - // which is acceptable since there is an unused margin on the right. - bool make_last_adjustment = false; - while (true) { - gfx::Rect overview_bounds(total_bounds); - overview_bounds.set_width(right_bound - total_bounds.x()); - bool windows_fit = FitWindowRectsInBounds( - overview_bounds, std::min(kMaxHeight + 2 * kWindowMargin, height), - &rects, &max_bottom, &min_right, &max_right); - - if (height_fixed) { - if (!windows_fit) { - // Revert the previous change to |right_bound| and do one last pass. - right_bound++; - make_last_adjustment = true; - break; - } - // Break if all the windows are zero-width at the current scale. - if (max_right <= total_bounds.x()) - break; - } else { - // Find the optimal row height bisecting between |low_height| and - // |high_height|. - if (windows_fit) - low_height = height; - else - high_height = height; - height = 0.5 * (low_height + high_height); - // When height can no longer be improved, start balancing the rows. - if (height == low_height) - height_fixed = true; - } - - if (windows_fit && height_fixed) { - if (max_right - min_right <= width_diff) { - // Row alignment is getting better. Try to shrink the |right_bound| in - // order to squeeze the widest row. - right_bound = max_right - 1; - width_diff = max_right - min_right; - } else { - // Row alignment is getting worse. - // Revert the previous change to |right_bound| and do one last pass. - right_bound++; - make_last_adjustment = true; - break; - } - } - } - // Once the windows in |window_list_| no longer fit, the change to - // |right_bound| was reverted. Perform one last pass to position the |rects|. - if (make_last_adjustment) { - gfx::Rect overview_bounds(total_bounds); - overview_bounds.set_width(right_bound - total_bounds.x()); - FitWindowRectsInBounds(overview_bounds, - std::min(kMaxHeight + 2 * kWindowMargin, height), - &rects, &max_bottom, &min_right, &max_right); - } - // Position the windows centering the left-aligned rows vertically. - gfx::Vector2d offset(0, (total_bounds.bottom() - max_bottom) / 2); - for (size_t i = 0; i < window_list_.size(); ++i) { - window_list_[i]->SetBounds( - rects[i] + offset, - animate - ? OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS - : OverviewAnimationType::OVERVIEW_ANIMATION_NONE); - } - - // If the selection widget is active, reposition it without any animation. - if (selection_widget_) - MoveSelectionWidgetToTarget(animate); -} - -bool WindowGrid::Move(WindowSelector::Direction direction, bool animate) { - bool recreate_selection_widget = false; - bool out_of_bounds = false; - bool changed_selection_index = false; - gfx::Rect old_bounds; - if (SelectedWindow()) { - old_bounds = SelectedWindow()->target_bounds(); - // Make the old selected window header non-transparent first. - SelectedWindow()->SetSelected(false); - } - - // [up] key is equivalent to [left] key and [down] key is equivalent to - // [right] key. - if (!selection_widget_) { - switch (direction) { - case WindowSelector::UP: - case WindowSelector::LEFT: - selected_index_ = window_list_.size() - 1; - break; - case WindowSelector::DOWN: - case WindowSelector::RIGHT: - selected_index_ = 0; - break; - } - changed_selection_index = true; - } - while (!changed_selection_index || - (!out_of_bounds && window_list_[selected_index_]->dimmed())) { - switch (direction) { - case WindowSelector::UP: - case WindowSelector::LEFT: - if (selected_index_ == 0) - out_of_bounds = true; - selected_index_--; - break; - case WindowSelector::DOWN: - case WindowSelector::RIGHT: - if (selected_index_ >= window_list_.size() - 1) - out_of_bounds = true; - selected_index_++; - break; - } - if (!out_of_bounds && SelectedWindow()) { - if (SelectedWindow()->target_bounds().y() != old_bounds.y()) - recreate_selection_widget = true; - } - changed_selection_index = true; - } - MoveSelectionWidget(direction, recreate_selection_widget, out_of_bounds, - animate); - - // Make the new selected window header fully transparent. - if (SelectedWindow()) - SelectedWindow()->SetSelected(true); - return out_of_bounds; -} - -WindowSelectorItem* WindowGrid::SelectedWindow() const { - if (!selection_widget_) - return nullptr; - CHECK(selected_index_ < window_list_.size()); - return window_list_[selected_index_].get(); -} - -bool WindowGrid::Contains(const WmWindow* window) const { - for (const auto& window_item : window_list_) { - if (window_item->Contains(window)) - return true; - } - return false; -} - -void WindowGrid::FilterItems(const base::string16& pattern) { - base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents finder(pattern); - for (const auto& window : window_list_) { - if (finder.Search(window->GetWindow()->GetTitle(), nullptr, nullptr)) { - window->SetDimmed(false); - } else { - window->SetDimmed(true); - if (selection_widget_ && SelectedWindow() == window.get()) { - SelectedWindow()->SetSelected(false); - selection_widget_.reset(); - selector_shadow_.reset(); - } - } - } -} - -void WindowGrid::WindowClosing(WindowSelectorItem* window) { - if (!selection_widget_ || SelectedWindow() != window) - return; - WmWindow* selection_widget_window = - WmWindow::Get(selection_widget_->GetNativeWindow()); - std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings_label = - ScopedOverviewAnimationSettingsFactory::Get() - ->CreateOverviewAnimationSettings( - OverviewAnimationType::OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM, - selection_widget_window); - selection_widget_->SetOpacity(0.f); -} - -void WindowGrid::OnWindowDestroying(aura::Window* window) { - window_observer_.Remove(window); - window_state_observer_.Remove(wm::GetWindowState(window)); - auto iter = std::find_if(window_list_.begin(), window_list_.end(), - WindowSelectorItemComparator(WmWindow::Get(window))); - - DCHECK(iter != window_list_.end()); - - size_t removed_index = iter - window_list_.begin(); - window_list_.erase(iter); - - if (empty()) { - // If the grid is now empty, notify the window selector so that it erases us - // from its grid list. - window_selector_->OnGridEmpty(this); - return; - } - - // If selecting, update the selection index. - if (selection_widget_) { - bool send_focus_alert = selected_index_ == removed_index; - if (selected_index_ >= removed_index && selected_index_ != 0) - selected_index_--; - SelectedWindow()->SetSelected(true); - if (send_focus_alert) - SelectedWindow()->SendAccessibleSelectionEvent(); - } - - PositionWindows(true); -} - -void WindowGrid::OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - // During preparation, window bounds can change. Ignore bounds - // change notifications in this case; we'll reposition soon. - if (!prepared_for_overview_) - return; - - auto iter = std::find_if(window_list_.begin(), window_list_.end(), - WindowSelectorItemComparator(WmWindow::Get(window))); - DCHECK(iter != window_list_.end()); - - // Immediately finish any active bounds animation. - window->layer()->GetAnimator()->StopAnimatingProperty( - ui::LayerAnimationElement::BOUNDS); - PositionWindows(false); -} - -void WindowGrid::OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) { - // During preparation, window state can change, e.g. updating shelf - // visibility may show the temporarily hidden (minimized) panels. - if (!prepared_for_overview_) - return; - - wm::WindowStateType new_type = window_state->GetStateType(); - if (IsMinimizedStateType(old_type) == IsMinimizedStateType(new_type)) - return; - - auto iter = - std::find_if(window_list_.begin(), window_list_.end(), - [window_state](std::unique_ptr<WindowSelectorItem>& item) { - return item->Contains(window_state->window()); - }); - if (iter != window_list_.end()) { - (*iter)->OnMinimizedStateChanged(); - PositionWindows(false); - } -} - -void WindowGrid::InitShieldWidget() { - // TODO(varkha): The code assumes that SHELF_BACKGROUND_MAXIMIZED is - // synonymous with a black shelf background. Update this code if that - // assumption is no longer valid. - const float initial_opacity = - (WmShelf::ForWindow(root_window_)->GetBackgroundType() == - SHELF_BACKGROUND_MAXIMIZED) - ? 1.f - : 0.f; - shield_widget_.reset( - CreateBackgroundWidget(root_window_, ui::LAYER_SOLID_COLOR, kShieldColor, - 0, 0, SK_ColorTRANSPARENT, initial_opacity)); - WmWindow* widget_window = WmWindow::Get(shield_widget_->GetNativeWindow()); - const gfx::Rect bounds = widget_window->GetParent()->GetBounds(); - widget_window->SetBounds(bounds); - widget_window->SetName("OverviewModeShield"); - - ui::ScopedLayerAnimationSettings animation_settings( - widget_window->GetLayer()->GetAnimator()); - animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( - kOverviewSelectorTransitionMilliseconds)); - animation_settings.SetTweenType(gfx::Tween::EASE_OUT); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - shield_widget_->SetOpacity(kShieldOpacity); -} - -void WindowGrid::InitSelectionWidget(WindowSelector::Direction direction) { - selection_widget_.reset(CreateBackgroundWidget( - root_window_, ui::LAYER_TEXTURED, kWindowSelectionColor, - kWindowSelectionBorderThickness, kWindowSelectionRadius, - kWindowSelectionBorderColor, 0.f)); - WmWindow* widget_window = WmWindow::Get(selection_widget_->GetNativeWindow()); - const gfx::Rect target_bounds = - root_window_->ConvertRectFromScreen(SelectedWindow()->target_bounds()); - gfx::Vector2d fade_out_direction = - GetSlideVectorForFadeIn(direction, target_bounds); - widget_window->SetBounds(target_bounds - fade_out_direction); - widget_window->SetName("OverviewModeSelector"); - - selector_shadow_.reset(new ::wm::Shadow()); - selector_shadow_->Init(::wm::ShadowElevation::LARGE); - selector_shadow_->layer()->SetVisible(true); - selection_widget_->GetLayer()->SetMasksToBounds(false); - selection_widget_->GetLayer()->Add(selector_shadow_->layer()); - selector_shadow_->SetContentBounds(gfx::Rect(target_bounds.size())); -} - -void WindowGrid::MoveSelectionWidget(WindowSelector::Direction direction, - bool recreate_selection_widget, - bool out_of_bounds, - bool animate) { - // If the selection widget is already active, fade it out in the selection - // direction. - if (selection_widget_ && (recreate_selection_widget || out_of_bounds)) { - // Animate the old selection widget and then destroy it. - views::Widget* old_selection = selection_widget_.get(); - WmWindow* old_selection_window = - WmWindow::Get(old_selection->GetNativeWindow()); - gfx::Vector2d fade_out_direction = - GetSlideVectorForFadeIn(direction, old_selection_window->GetBounds()); - - ui::ScopedLayerAnimationSettings animation_settings( - old_selection_window->GetLayer()->GetAnimator()); - animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( - kOverviewSelectorTransitionMilliseconds)); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - animation_settings.SetTweenType(gfx::Tween::FAST_OUT_LINEAR_IN); - // CleanupAnimationObserver will delete itself (and the widget) when the - // motion animation is complete. - // Ownership over the observer is passed to the window_selector_->delegate() - // which has longer lifetime so that animations can continue even after the - // overview mode is shut down. - std::unique_ptr<CleanupAnimationObserver> observer( - new CleanupAnimationObserver(std::move(selection_widget_))); - animation_settings.AddObserver(observer.get()); - window_selector_->delegate()->AddDelayedAnimationObserver( - std::move(observer)); - old_selection->SetOpacity(0.f); - old_selection_window->SetBounds(old_selection_window->GetBounds() + - fade_out_direction); - old_selection->Hide(); - } - if (out_of_bounds) - return; - - if (!selection_widget_) - InitSelectionWidget(direction); - // Send an a11y alert so that if ChromeVox is enabled, the item label is - // read. - SelectedWindow()->SendAccessibleSelectionEvent(); - // The selection widget is moved to the newly selected item in the same - // grid. - MoveSelectionWidgetToTarget(animate); -} - -void WindowGrid::MoveSelectionWidgetToTarget(bool animate) { - gfx::Rect bounds = - root_window_->ConvertRectFromScreen(SelectedWindow()->target_bounds()); - if (animate) { - WmWindow* selection_widget_window = - WmWindow::Get(selection_widget_->GetNativeWindow()); - ui::ScopedLayerAnimationSettings animation_settings( - selection_widget_window->GetLayer()->GetAnimator()); - animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( - kOverviewSelectorTransitionMilliseconds)); - animation_settings.SetTweenType(gfx::Tween::EASE_IN_OUT); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - selection_widget_->SetBounds(bounds); - selection_widget_->SetOpacity(1.f); - - if (selector_shadow_) { - ui::ScopedLayerAnimationSettings animation_settings_shadow( - selector_shadow_->shadow_layer()->GetAnimator()); - animation_settings_shadow.SetTransitionDuration( - base::TimeDelta::FromMilliseconds( - kOverviewSelectorTransitionMilliseconds)); - animation_settings_shadow.SetTweenType(gfx::Tween::EASE_IN_OUT); - animation_settings_shadow.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - bounds.Inset(1, 1); - selector_shadow_->SetContentBounds( - gfx::Rect(gfx::Point(1, 1), bounds.size())); - } - return; - } - selection_widget_->SetBounds(bounds); - selection_widget_->SetOpacity(1.f); - if (selector_shadow_) { - bounds.Inset(1, 1); - selector_shadow_->SetContentBounds( - gfx::Rect(gfx::Point(1, 1), bounds.size())); - } -} - -bool WindowGrid::FitWindowRectsInBounds(const gfx::Rect& bounds, - int height, - std::vector<gfx::Rect>* rects, - int* max_bottom, - int* min_right, - int* max_right) { - rects->resize(window_list_.size()); - bool windows_fit = true; - - // Start in the top-left corner of |bounds|. - int left = bounds.x(); - int top = bounds.y(); - - // Keep track of the lowest coordinate. - *max_bottom = bounds.y(); - - // Right bound of the narrowest row. - *min_right = bounds.right(); - // Right bound of the widest row. - *max_right = bounds.x(); - - // All elements are of same height and only the height is necessary to - // determine each item's scale. - const gfx::Size item_size(0, height); - size_t i = 0; - for (const auto& window : window_list_) { - const gfx::Rect target_bounds = window->GetTargetBoundsInScreen(); - const int width = - std::max(1, gfx::ToFlooredInt(target_bounds.width() * - window->GetItemScale(item_size)) + - 2 * kWindowMargin); - if (left + width > bounds.right()) { - // Move to the next row if possible. - if (*min_right > left) - *min_right = left; - if (*max_right < left) - *max_right = left; - top += height; - - // Check if the new row reaches the bottom or if the first item in the new - // row does not fit within the available width. - if (top + height > bounds.bottom() || - bounds.x() + width > bounds.right()) { - windows_fit = false; - break; - } - left = bounds.x(); - } - - // Position the current rect. - (*rects)[i].SetRect(left, top, width, height); - - // Increment horizontal position using sanitized positive |width()|. - left += (*rects)[i].width(); - - if (++i == window_list_.size()) { - // Update the narrowest and widest row width for the last row. - if (*min_right > left) - *min_right = left; - if (*max_right < left) - *max_right = left; - } - *max_bottom = top + height; - } - return windows_fit; -} - -} // namespace ash
diff --git a/ash/wm/overview/window_grid.h b/ash/wm/overview/window_grid.h deleted file mode 100644 index e7d7115..0000000 --- a/ash/wm/overview/window_grid.h +++ /dev/null
@@ -1,198 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_WINDOW_GRID_H_ -#define ASH_WM_OVERVIEW_WINDOW_GRID_H_ - -#include <stddef.h> - -#include <memory> -#include <set> -#include <vector> - -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/window_state_observer.h" -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "ui/aura/window_observer.h" - -namespace views { -class Widget; -} - -namespace wm { -class Shadow; -} - -namespace ash { - -class WindowSelectorItem; - -// Represents a grid of windows in the Overview Mode in a particular root -// window, and manages a selection widget that can be moved with the arrow keys. -// The idea behind the movement strategy is that it should be possible to access -// any window pressing a given arrow key repeatedly. -// +-------+ +-------+ +-------+ -// | 0 | | 1 | | 2 | -// +-------+ +-------+ +-------+ -// +-------+ +-------+ +-------+ -// | 3 | | 4 | | 5 | -// +-------+ +-------+ +-------+ -// +-------+ -// | 6 | -// +-------+ -// Example sequences: -// - Going right to left -// 0, 1, 2, 3, 4, 5, 6 -// The selector is switched to the next window grid (if available) or wrapped if -// it reaches the end of its movement sequence. -class ASH_EXPORT WindowGrid : public aura::WindowObserver, - public wm::WindowStateObserver { - public: - WindowGrid(WmWindow* root_window, - const std::vector<WmWindow*>& window_list, - WindowSelector* window_selector); - ~WindowGrid() override; - - // Exits overview mode, fading out the |shield_widget_| if necessary. - void Shutdown(); - - // Prepares the windows in this grid for overview. This will restore all - // minimized windows and ensure they are visible. - void PrepareForOverview(); - - // Positions all the windows in rows of equal height scaling each window to - // fit that height. - // Layout is done in 2 stages maintaining fixed MRU ordering. - // 1. Optimal height is determined. In this stage |height| is bisected to find - // maximum height which still allows all the windows to fit. - // 2. Row widths are balanced. In this stage the available width is reduced - // until some windows are no longer fitting or until the difference between - // the narrowest and the widest rows starts growing. - // Overall this achieves the goals of maximum size for previews (or maximum - // row height which is equivalent assuming fixed height), balanced rows and - // minimal wasted space. - // Optionally animates the windows to their targets when |animate| is true. - void PositionWindows(bool animate); - - // Updates |selected_index_| according to the specified |direction| and calls - // MoveSelectionWidget(). Returns |true| if the new selection index is out of - // this window grid bounds. - bool Move(WindowSelector::Direction direction, bool animate); - - // Returns the target selected window, or NULL if there is none selected. - WindowSelectorItem* SelectedWindow() const; - - // Returns true if a window is contained in any of the WindowSelectorItems - // this grid owns. - bool Contains(const WmWindow* window) const; - - // Dims the items whose titles do not contain |pattern| and prevents their - // selection. The pattern has its accents removed and is converted to - // lowercase in a l10n sensitive context. - // If |pattern| is empty, no item is dimmed. - void FilterItems(const base::string16& pattern); - - // Called when |window| is about to get closed. If the |window| is currently - // selected the implementation fades out |selection_widget_| to transparent - // opacity, effectively hiding the selector widget. - void WindowClosing(WindowSelectorItem* window); - - // Returns true if the grid has no more windows. - bool empty() const { return window_list_.empty(); } - - // Returns how many window selector items are in the grid. - size_t size() const { return window_list_.size(); } - - // Returns true if the selection widget is active. - bool is_selecting() const { return selection_widget_ != nullptr; } - - // Returns the root window in which the grid displays the windows. - const WmWindow* root_window() const { return root_window_; } - - const std::vector<std::unique_ptr<WindowSelectorItem>>& window_list() const { - return window_list_; - } - - // aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - // TODO(flackr): Handle window bounds changed in WindowSelectorItem. - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override; - - // wm::WindowStateObserver: - void OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) override; - - private: - friend class WindowSelectorTest; - - // Initializes the screen shield widget. - void InitShieldWidget(); - - // Internal function to initialize the selection widget. - void InitSelectionWidget(WindowSelector::Direction direction); - - // Moves the selection widget to the specified |direction|. - void MoveSelectionWidget(WindowSelector::Direction direction, - bool recreate_selection_widget, - bool out_of_bounds, - bool animate); - - // Moves the selection widget to the targeted window. - void MoveSelectionWidgetToTarget(bool animate); - - // Attempts to fit all |rects| inside |bounds|. The method ensures that - // the |rects| vector has appropriate size and populates it with the values - // placing Rects next to each other left-to-right in rows of equal |height|. - // While fitting |rects| several metrics are collected that can be used by the - // caller. |max_bottom| specifies the bottom that the rects are extending to. - // |min_right| and |max_right| report the right bound of the narrowest and the - // widest rows respectively. In-values of the |max_bottom|, |min_right| and - // |max_right| parameters are ignored and their values are always initialized - // inside this method. Returns true on success and false otherwise. - bool FitWindowRectsInBounds(const gfx::Rect& bounds, - int height, - std::vector<gfx::Rect>* rects, - int* max_bottom, - int* min_right, - int* max_right); - - // Root window the grid is in. - WmWindow* root_window_; - - // Pointer to the window selector that spawned this grid. - WindowSelector* window_selector_; - - // Vector containing all the windows in this grid. - std::vector<std::unique_ptr<WindowSelectorItem>> window_list_; - - ScopedObserver<aura::Window, WindowGrid> window_observer_; - ScopedObserver<wm::WindowState, WindowGrid> window_state_observer_; - - // Widget that darkens the screen background. - std::unique_ptr<views::Widget> shield_widget_; - - // Widget that indicates to the user which is the selected window. - std::unique_ptr<views::Widget> selection_widget_; - - // Shadow around the selector. - std::unique_ptr<::wm::Shadow> selector_shadow_; - - // Current selected window position. - size_t selected_index_; - - // Number of columns in the grid. - size_t num_columns_; - - // True only after all windows have been prepared for overview. - bool prepared_for_overview_; - - DISALLOW_COPY_AND_ASSIGN(WindowGrid); -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_WINDOW_GRID_H_
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc deleted file mode 100644 index ac05f0a..0000000 --- a/ash/wm/overview/window_selector.cc +++ /dev/null
@@ -1,685 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/window_selector.h" - -#include <algorithm> -#include <functional> -#include <set> -#include <utility> -#include <vector> - -#include "ash/common/accessibility_delegate.h" -#include "ash/common/accessibility_types.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "ash/wm/overview/window_selector_item.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/switchable_windows.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_screen_util.h" -#include "base/auto_reset.h" -#include "base/command_line.h" -#include "base/metrics/histogram_macros.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/display/screen.h" -#include "ui/events/event.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/skia_util.h" -#include "ui/gfx/vector_icons_public.h" -#include "ui/views/border.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/controls/textfield/textfield.h" -#include "ui/views/layout/box_layout.h" - -namespace ash { - -namespace { - -// The amount of padding surrounding the text in the text filtering textbox. -const int kTextFilterHorizontalPadding = 10; - -// The height of the text filtering textbox. -const int kTextFilterHeight = 40; - -// The margin at the bottom to make sure the text filter layer is hidden. -// This is needed because positioning the text filter directly touching the top -// edge of the screen still allows the shadow to peek through. -const int kTextFieldBottomMargin = 2; - -// Distance from top of overview to the top of text filtering textbox as a -// proportion of the total overview area. -const float kTextFilterTopScreenProportion = 0.02f; - -// Width of the text filter area. -const int kTextFilterWidth = 280; - -// The font style used for text filtering textbox. -static const ui::ResourceBundle::FontStyle kTextFilterFontStyle = - ui::ResourceBundle::FontStyle::BaseFont; - -// The color of the text and its background in the text filtering textbox. -const SkColor kTextFilterTextColor = SkColorSetARGB(222, 0, 0, 0); -const SkColor kTextFilterBackgroundColor = SK_ColorWHITE; - -// The color or search icon. -const SkColor kTextFilterIconColor = SkColorSetARGB(138, 0, 0, 0); - -// The size of search icon. -const int kTextFilterIconSize = 20; - -// The radius used for the rounded corners on the text filtering textbox. -const int kTextFilterCornerRadius = 2; - -// A comparator for locating a selector item for a given root. -struct WindowSelectorItemForRoot { - explicit WindowSelectorItemForRoot(const WmWindow* root) - : root_window(root) {} - - bool operator()(WindowSelectorItem* item) const { - return item->root_window() == root_window; - } - - const WmWindow* root_window; -}; - -// A View having rounded corners and a specified background color which is -// only painted within the bounds defined by the rounded corners. -// TODO(tdanderson): This duplicates code from RoundedImageView. Refactor these -// classes and move into ui/views. -class RoundedContainerView : public views::View { - public: - RoundedContainerView(int corner_radius, SkColor background) - : corner_radius_(corner_radius), background_(background) {} - - ~RoundedContainerView() override {} - - void OnPaint(gfx::Canvas* canvas) override { - views::View::OnPaint(canvas); - - SkScalar radius = SkIntToScalar(corner_radius_); - const SkScalar kRadius[8] = {radius, radius, radius, radius, - radius, radius, radius, radius}; - SkPath path; - gfx::Rect bounds(size()); - path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); - - canvas->ClipPath(path, true); - canvas->DrawColor(background_); - } - - private: - int corner_radius_; - SkColor background_; - - DISALLOW_COPY_AND_ASSIGN(RoundedContainerView); -}; - -// Triggers a shelf visibility update on all root window controllers. -void UpdateShelfVisibility() { - for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) - WmShelf::ForWindow(root)->UpdateVisibilityState(); -} - -gfx::Rect GetTextFilterPosition(WmWindow* root_window) { - gfx::Rect total_bounds = root_window->ConvertRectToScreen( - wm::GetDisplayWorkAreaBoundsInParent(root_window->GetChildByShellWindowId( - kShellWindowId_DefaultContainer))); - return gfx::Rect( - 0.5 * (total_bounds.width() - - std::min(kTextFilterWidth, total_bounds.width())), - total_bounds.y() + total_bounds.height() * kTextFilterTopScreenProportion, - std::min(kTextFilterWidth, total_bounds.width()), kTextFilterHeight); -} - -// Initializes the text filter on the top of the main root window and requests -// focus on its textfield. Uses |image| to place an icon to the left of the text -// field. -views::Widget* CreateTextFilter(views::TextfieldController* controller, - WmWindow* root_window, - const gfx::ImageSkia& image, - int* text_filter_bottom) { - views::Widget* widget = new views::Widget; - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.accept_events = true; - params.bounds = GetTextFilterPosition(root_window); - params.name = "OverviewModeTextFilter"; - *text_filter_bottom = params.bounds.bottom() + kTextFieldBottomMargin; - root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - widget, kShellWindowId_StatusContainer, ¶ms); - widget->Init(params); - - // Use |container| to specify the padding surrounding the text and to give - // the textfield rounded corners. - views::View* container = new RoundedContainerView(kTextFilterCornerRadius, - kTextFilterBackgroundColor); - ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - const int text_height = - std::max(kTextFilterIconSize, - bundle.GetFontList(kTextFilterFontStyle).GetHeight()); - DCHECK(text_height); - const int vertical_padding = (params.bounds.height() - text_height) / 2; - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, kTextFilterHorizontalPadding, - vertical_padding, kTextFilterHorizontalPadding); - container->SetLayoutManager(layout); - - views::Textfield* textfield = new views::Textfield; - textfield->set_controller(controller); - textfield->SetBorder(views::NullBorder()); - textfield->SetBackgroundColor(kTextFilterBackgroundColor); - textfield->SetTextColor(kTextFilterTextColor); - views::ImageView* image_view = new views::ImageView; - image_view->SetImage(image); - container->AddChildView(image_view); - textfield->SetFontList(bundle.GetFontList(kTextFilterFontStyle)); - container->AddChildView(textfield); - layout->SetFlexForView(textfield, 1); - widget->SetContentsView(container); - - // The textfield initially contains no text, so shift its position to be - // outside the visible bounds of the screen. - gfx::Transform transform; - transform.Translate(0, -(*text_filter_bottom)); - WmWindow* text_filter_widget_window = - WmWindow::Get(widget->GetNativeWindow()); - text_filter_widget_window->SetOpacity(0); - text_filter_widget_window->SetTransform(transform); - widget->Show(); - textfield->RequestFocus(); - - return widget; -} - -} // namespace - -// static -bool WindowSelector::IsSelectable(WmWindow* window) { - wm::WindowState* state = window->GetWindowState(); - return state->IsUserPositionable(); -} - -WindowSelector::WindowSelector(WindowSelectorDelegate* delegate) - : delegate_(delegate), - restore_focus_window_(WmShell::Get()->GetFocusedWindow()), - ignore_activations_(false), - selected_grid_index_(0), - overview_start_time_(base::Time::Now()), - num_key_presses_(0), - num_items_(0), - showing_text_filter_(false), - text_filter_string_length_(0), - num_times_textfield_cleared_(0), - restoring_minimized_windows_(false), - text_filter_bottom_(0) { - DCHECK(delegate_); -} - -WindowSelector::~WindowSelector() { - RemoveAllObservers(); -} - -// NOTE: The work done in Init() is not done in the constructor because it may -// cause other, unrelated classes, (ie PanelLayoutManager) to make indirect -// calls to restoring_minimized_windows() on a partially constructed object. -void WindowSelector::Init(const WindowList& windows) { - if (restore_focus_window_) - restore_focus_window_->aura_window()->AddObserver(this); - - WmShell* shell = WmShell::Get(); - - std::vector<WmWindow*> root_windows = shell->GetAllRootWindows(); - std::sort(root_windows.begin(), root_windows.end(), - [](const WmWindow* a, const WmWindow* b) { - // Since we don't know if windows are vertically or horizontally - // oriented we use both x and y position. This may be confusing - // if you have 3 or more monitors which are not strictly - // horizontal or vertical but that case is not yet supported. - return (a->GetBoundsInScreen().x() + a->GetBoundsInScreen().y()) < - (b->GetBoundsInScreen().x() + b->GetBoundsInScreen().y()); - }); - - for (WmWindow* root : root_windows) { - // Observed switchable containers for newly created windows on all root - // windows. - for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) { - WmWindow* container = - root->GetChildByShellWindowId(wm::kSwitchableWindowContainerIds[i]); - container->aura_window()->AddObserver(this); - observed_windows_.insert(container); - } - - // Hide the callout widgets for panels. It is safe to call this for - // root windows that don't contain any panel windows. - PanelLayoutManager::Get(root)->SetShowCalloutWidgets(false); - - std::unique_ptr<WindowGrid> grid(new WindowGrid(root, windows, this)); - if (grid->empty()) - continue; - num_items_ += grid->size(); - grid_list_.push_back(std::move(grid)); - } - - { - // The calls to WindowGrid::PrepareForOverview() and CreateTextFilter(...) - // requires some LayoutManagers (ie PanelLayoutManager) to perform layouts - // so that windows are correctly visible and properly animated in overview - // mode. Otherwise these layouts should be suppressed during overview mode - // so they don't conflict with overview mode animations. The - // |restoring_minimized_windows_| flag enables the PanelLayoutManager to - // make this decision. - base::AutoReset<bool> auto_restoring_minimized_windows( - &restoring_minimized_windows_, true); - - // Do not call PrepareForOverview until all items are added to window_list_ - // as we don't want to cause any window updates until all windows in - // overview are observed. See http://crbug.com/384495. - for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { - window_grid->PrepareForOverview(); - window_grid->PositionWindows(true); - } - - search_image_ = - gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH, - kTextFilterIconSize, kTextFilterIconColor); - WmWindow* root_window = shell->GetPrimaryRootWindow(); - text_filter_widget_.reset(CreateTextFilter(this, root_window, search_image_, - &text_filter_bottom_)); - } - - DCHECK(!grid_list_.empty()); - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", num_items_); - - shell->AddActivationObserver(this); - - display::Screen::GetScreen()->AddObserver(this); - shell->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW); - // Send an a11y alert. - WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert( - A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED); - - UpdateShelfVisibility(); -} - -// NOTE: The work done in Shutdown() is not done in the destructor because it -// may cause other, unrelated classes, (ie PanelLayoutManager) to make indirect -// calls to restoring_minimized_windows() on a partially destructed object. -void WindowSelector::Shutdown() { - is_shut_down_ = true; - // Stop observing screen metrics changes first to avoid auto-positioning - // windows in response to work area changes from window activation. - display::Screen::GetScreen()->RemoveObserver(this); - - size_t remaining_items = 0; - for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) { - for (const auto& window_selector_item : window_grid->window_list()) - window_selector_item->RestoreWindow(); - remaining_items += window_grid->size(); - } - - // Setting focus after restoring windows' state avoids unnecessary animations. - ResetFocusRestoreWindow(true); - RemoveAllObservers(); - - std::vector<WmWindow*> root_windows = WmShell::Get()->GetAllRootWindows(); - for (WmWindow* window : root_windows) { - // Un-hide the callout widgets for panels. It is safe to call this for - // root_windows that don't contain any panel windows. - PanelLayoutManager::Get(window)->SetShowCalloutWidgets(true); - } - - for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) - window_grid->Shutdown(); - - DCHECK(num_items_ >= remaining_items); - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems", - num_items_ - remaining_items); - UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowSelector.TimeInOverview", - base::Time::Now() - overview_start_time_); - - // Record metrics related to text filtering. - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringStringLength", - text_filter_string_length_); - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringTextfieldCleared", - num_times_textfield_cleared_); - if (text_filter_string_length_) { - UMA_HISTOGRAM_MEDIUM_TIMES( - "Ash.WindowSelector.TimeInOverviewWithTextFiltering", - base::Time::Now() - overview_start_time_); - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ItemsWhenTextFilteringUsed", - remaining_items); - } - - // Clearing the window list resets the ignored_by_shelf flag on the windows. - grid_list_.clear(); - UpdateShelfVisibility(); -} - -void WindowSelector::RemoveAllObservers() { - for (WmWindow* window : observed_windows_) - window->aura_window()->RemoveObserver(this); - - WmShell::Get()->RemoveActivationObserver(this); - display::Screen::GetScreen()->RemoveObserver(this); - if (restore_focus_window_) - restore_focus_window_->aura_window()->RemoveObserver(this); -} - -void WindowSelector::CancelSelection() { - delegate_->OnSelectionEnded(); -} - -void WindowSelector::OnGridEmpty(WindowGrid* grid) { - size_t index = 0; - for (auto iter = grid_list_.begin(); iter != grid_list_.end(); ++iter) { - if (grid == (*iter).get()) { - index = iter - grid_list_.begin(); - grid_list_.erase(iter); - break; - } - } - if (index > 0 && selected_grid_index_ >= index) { - selected_grid_index_--; - // If the grid which became empty was the one with the selected window, we - // need to select a window on the newly selected grid. - if (selected_grid_index_ == index - 1) - Move(LEFT, true); - } - if (grid_list_.empty()) - CancelSelection(); -} - -void WindowSelector::IncrementSelection(int increment) { - const Direction direction = - increment > 0 ? WindowSelector::RIGHT : WindowSelector::LEFT; - for (int step = 0; step < abs(increment); ++step) - Move(direction, true); -} - -bool WindowSelector::AcceptSelection() { - if (!grid_list_[selected_grid_index_]->is_selecting()) - return false; - SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow()); - return true; -} - -void WindowSelector::SelectWindow(WindowSelectorItem* item) { - WmWindow* window = item->GetWindow(); - std::vector<WmWindow*> window_list = - WmShell::Get()->mru_window_tracker()->BuildMruWindowList(); - if (!window_list.empty()) { - // Record UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED if the user is selecting - // a window other than the window that was active prior to entering overview - // mode (i.e., the window at the front of the MRU list). - if (window_list[0] != window) { - WmShell::Get()->RecordUserMetricsAction( - UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED); - } - const auto it = std::find(window_list.begin(), window_list.end(), window); - if (it != window_list.end()) { - // Record 1-based index so that selecting a top MRU window will record 1. - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.SelectionDepth", - 1 + it - window_list.begin()); - } - } - item->EnsureVisible(); - window->GetWindowState()->Activate(); -} - -void WindowSelector::WindowClosing(WindowSelectorItem* window) { - grid_list_[selected_grid_index_]->WindowClosing(window); -} - -bool WindowSelector::HandleKeyEvent(views::Textfield* sender, - const ui::KeyEvent& key_event) { - if (key_event.type() != ui::ET_KEY_PRESSED) - return false; - - switch (key_event.key_code()) { - case ui::VKEY_ESCAPE: - CancelSelection(); - break; - case ui::VKEY_UP: - num_key_presses_++; - Move(WindowSelector::UP, true); - break; - case ui::VKEY_DOWN: - num_key_presses_++; - Move(WindowSelector::DOWN, true); - break; - case ui::VKEY_RIGHT: - case ui::VKEY_TAB: - if (key_event.key_code() == ui::VKEY_RIGHT || - !(key_event.flags() & ui::EF_SHIFT_DOWN)) { - num_key_presses_++; - Move(WindowSelector::RIGHT, true); - break; - } - case ui::VKEY_LEFT: - num_key_presses_++; - Move(WindowSelector::LEFT, true); - break; - case ui::VKEY_W: - if (!(key_event.flags() & ui::EF_CONTROL_DOWN) || - !grid_list_[selected_grid_index_]->is_selecting()) { - // Allow the textfield to handle 'W' key when not used with Ctrl. - return false; - } - WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_CLOSE_KEY); - grid_list_[selected_grid_index_]->SelectedWindow()->CloseWindow(); - break; - case ui::VKEY_RETURN: - // Ignore if no item is selected. - if (!grid_list_[selected_grid_index_]->is_selecting()) - return false; - UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ArrowKeyPresses", - num_key_presses_); - UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.WindowSelector.KeyPressesOverItemsRatio", - (num_key_presses_ * 100) / num_items_, 1, 300, - 30); - WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_ENTER_KEY); - SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow()); - break; - default: - // Not a key we are interested in, allow the textfield to handle it. - return false; - } - return true; -} - -void WindowSelector::OnDisplayAdded(const display::Display& display) {} - -void WindowSelector::OnDisplayRemoved(const display::Display& display) { - // TODO(flackr): Keep window selection active on remaining displays. - CancelSelection(); -} - -void WindowSelector::OnDisplayMetricsChanged(const display::Display& display, - uint32_t metrics) { - PositionWindows(/* animate */ false); - RepositionTextFilterOnDisplayMetricsChange(); -} - -void WindowSelector::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - // Only care about newly added children of |observed_windows_|. - if (!observed_windows_.count(WmWindow::Get(params.receiver)) || - !observed_windows_.count(WmWindow::Get(params.new_parent))) { - return; - } - - WmWindow* new_window = WmWindow::Get(params.target); - if (!IsSelectable(new_window)) - return; - - for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) { - if (new_window->GetParent()->GetShellWindowId() == - wm::kSwitchableWindowContainerIds[i] && - !new_window->GetTransientParent()) { - // The new window is in one of the switchable containers, abort overview. - CancelSelection(); - return; - } - } -} - -void WindowSelector::OnWindowDestroying(aura::Window* window) { - window->RemoveObserver(this); - observed_windows_.erase(WmWindow::Get(window)); - if (WmWindow::Get(window) == restore_focus_window_) - restore_focus_window_ = nullptr; -} - -void WindowSelector::OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) { - if (ignore_activations_ || !gained_active || - gained_active == GetTextFilterWidgetWindow()) { - return; - } - - WmWindow* root_window = gained_active->GetRootWindow(); - auto grid = - std::find_if(grid_list_.begin(), grid_list_.end(), - [root_window](const std::unique_ptr<WindowGrid>& grid) { - return grid->root_window() == root_window; - }); - if (grid == grid_list_.end()) - return; - const auto& windows = (*grid)->window_list(); - - auto iter = std::find_if( - windows.begin(), windows.end(), - [gained_active](const std::unique_ptr<WindowSelectorItem>& window) { - return window->Contains(gained_active); - }); - - if (iter == windows.end() && showing_text_filter_ && - lost_active == GetTextFilterWidgetWindow()) { - return; - } - - // Don't restore focus on exit if a window was just activated. - ResetFocusRestoreWindow(false); - CancelSelection(); -} - -void WindowSelector::OnAttemptToReactivateWindow(WmWindow* request_active, - WmWindow* actual_active) { - OnWindowActivated(request_active, actual_active); -} - -void WindowSelector::ContentsChanged(views::Textfield* sender, - const base::string16& new_contents) { - text_filter_string_length_ = new_contents.length(); - if (!text_filter_string_length_) - num_times_textfield_cleared_++; - - bool should_show_text_filter = !new_contents.empty(); - if (showing_text_filter_ != should_show_text_filter) { - WmWindow* text_filter_widget_window = GetTextFilterWidgetWindow(); - ui::ScopedLayerAnimationSettings animation_settings( - text_filter_widget_window->GetLayer()->GetAnimator()); - animation_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - animation_settings.SetTweenType(showing_text_filter_ - ? gfx::Tween::FAST_OUT_LINEAR_IN - : gfx::Tween::LINEAR_OUT_SLOW_IN); - - gfx::Transform transform; - if (should_show_text_filter) { - transform.Translate(0, 0); - text_filter_widget_window->SetOpacity(1); - } else { - transform.Translate(0, -text_filter_bottom_); - text_filter_widget_window->SetOpacity(0); - } - - text_filter_widget_window->SetTransform(transform); - showing_text_filter_ = should_show_text_filter; - } - for (auto iter = grid_list_.begin(); iter != grid_list_.end(); iter++) - (*iter)->FilterItems(new_contents); - - // If the selection widget is not active, execute a Move() command so that it - // shows up on the first undimmed item. - if (grid_list_[selected_grid_index_]->is_selecting()) - return; - Move(WindowSelector::RIGHT, false); -} - -WmWindow* WindowSelector::GetTextFilterWidgetWindow() { - return WmWindow::Get(text_filter_widget_->GetNativeWindow()); -} - -void WindowSelector::PositionWindows(bool animate) { - for (std::unique_ptr<WindowGrid>& grid : grid_list_) - grid->PositionWindows(animate); -} - -void WindowSelector::RepositionTextFilterOnDisplayMetricsChange() { - WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow(); - const gfx::Rect rect = GetTextFilterPosition(root_window); - text_filter_bottom_ = rect.bottom() + kTextFieldBottomMargin; - text_filter_widget_->SetBounds(rect); - - gfx::Transform transform; - transform.Translate( - 0, text_filter_string_length_ == 0 ? -text_filter_bottom_ : 0); - WmWindow* text_filter_window = GetTextFilterWidgetWindow(); - text_filter_window->SetOpacity(text_filter_string_length_ == 0 ? 0 : 1); - text_filter_window->SetTransform(transform); -} - -void WindowSelector::ResetFocusRestoreWindow(bool focus) { - if (!restore_focus_window_) - return; - if (focus) { - base::AutoReset<bool> restoring_focus(&ignore_activations_, true); - restore_focus_window_->Activate(); - } - // If the window is in the observed_windows_ list it needs to continue to be - // observed. - if (observed_windows_.find(restore_focus_window_) == - observed_windows_.end()) { - restore_focus_window_->aura_window()->RemoveObserver(this); - } - restore_focus_window_ = nullptr; -} - -void WindowSelector::Move(Direction direction, bool animate) { - // Direction to move if moving past the end of a display. - int display_direction = (direction == RIGHT || direction == DOWN) ? 1 : -1; - - // If this is the first move and it's going backwards, start on the last - // display. - if (display_direction == -1 && !grid_list_.empty() && - !grid_list_[selected_grid_index_]->is_selecting()) { - selected_grid_index_ = grid_list_.size() - 1; - } - - // Keep calling Move() on the grids until one of them reports no overflow or - // we made a full cycle on all the grids. - for (size_t i = 0; i <= grid_list_.size() && - grid_list_[selected_grid_index_]->Move(direction, animate); - i++) { - selected_grid_index_ = - (selected_grid_index_ + display_direction + grid_list_.size()) % - grid_list_.size(); - } -} - -} // namespace ash
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h deleted file mode 100644 index 31b980f..0000000 --- a/ash/wm/overview/window_selector.h +++ /dev/null
@@ -1,200 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_ - -#include <stddef.h> -#include <stdint.h> - -#include <memory> -#include <set> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/common/wm_activation_observer.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "ui/aura/window_observer.h" -#include "ui/display/display_observer.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/views/controls/textfield/textfield_controller.h" - -namespace views { -class Textfield; -class Widget; -} - -namespace ash { -class WindowSelectorDelegate; -class WindowSelectorItem; -class WindowSelectorTest; -class WindowGrid; - -// The WindowSelector shows a grid of all of your windows, allowing to select -// one by clicking or tapping on it. -class ASH_EXPORT WindowSelector : public display::DisplayObserver, - public aura::WindowObserver, - public WmActivationObserver, - public views::TextfieldController { - public: - // Returns true if the window can be selected in overview mode. - static bool IsSelectable(WmWindow* window); - - enum Direction { LEFT, UP, RIGHT, DOWN }; - - using WindowList = std::vector<WmWindow*>; - - explicit WindowSelector(WindowSelectorDelegate* delegate); - ~WindowSelector() override; - - // Initialize with the windows that can be selected. - void Init(const WindowList& windows); - - // Perform cleanup that cannot be done in the destructor. - void Shutdown(); - - // Cancels window selection. - void CancelSelection(); - - // Called when the last window selector item from a grid is deleted. - void OnGridEmpty(WindowGrid* grid); - - // Moves the current selection by |increment| items. Positive values of - // |increment| move the selection forward, negative values move it backward. - void IncrementSelection(int increment); - - // Accepts current selection if any. Returns true if a selection was made, - // false otherwise. - bool AcceptSelection(); - - // Activates |item's| window. - void SelectWindow(WindowSelectorItem* item); - - // Called when |window| is about to get closed. - void WindowClosing(WindowSelectorItem* window); - - WindowSelectorDelegate* delegate() { return delegate_; } - - bool restoring_minimized_windows() const { - return restoring_minimized_windows_; - } - - int text_filter_bottom() const { return text_filter_bottom_; } - - bool is_shut_down() const { return is_shut_down_; } - - // display::DisplayObserver: - void OnDisplayAdded(const display::Display& display) override; - void OnDisplayRemoved(const display::Display& display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t metrics) override; - - // aura::WindowObserver: - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; - void OnWindowDestroying(aura::Window* window) override; - - // WmActivationObserver - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override; - void OnAttemptToReactivateWindow(WmWindow* request_active, - WmWindow* actual_active) override; - - // views::TextfieldController: - void ContentsChanged(views::Textfield* sender, - const base::string16& new_contents) override; - bool HandleKeyEvent(views::Textfield* sender, - const ui::KeyEvent& key_event) override; - - private: - friend class WindowSelectorTest; - - // Returns the WmWindow for |text_filter_widget_|. - WmWindow* GetTextFilterWidgetWindow(); - - // Position all of the windows in the overview. - void PositionWindows(bool animate); - - // Repositions and resizes |text_filter_widget_| on - // DisplayMetricsChanged event. - void RepositionTextFilterOnDisplayMetricsChange(); - - // |focus|, restores focus to the stored window. - void ResetFocusRestoreWindow(bool focus); - - // Helper function that moves the selection widget to |direction| on the - // corresponding window grid. - void Move(Direction direction, bool animate); - - // Removes all observers that were registered during construction and/or - // initialization. - void RemoveAllObservers(); - - // Tracks observed windows. - std::set<WmWindow*> observed_windows_; - - // Weak pointer to the selector delegate which will be called when a - // selection is made. - WindowSelectorDelegate* delegate_; - - // A weak pointer to the window which was focused on beginning window - // selection. If window selection is canceled the focus should be restored to - // this window. - WmWindow* restore_focus_window_; - - // True when performing operations that may cause window activations. This is - // used to prevent handling the resulting expected activation. - bool ignore_activations_; - - // List of all the window overview grids, one for each root window. - std::vector<std::unique_ptr<WindowGrid>> grid_list_; - - // Tracks the index of the root window the selection widget is in. - size_t selected_grid_index_; - - // The following variables are used for metric collection purposes. All of - // them refer to this particular overview session and are not cumulative: - // The time when overview was started. - base::Time overview_start_time_; - - // The number of arrow key presses. - size_t num_key_presses_; - - // The number of items in the overview. - size_t num_items_; - - // Indicates if the text filter is shown on screen (rather than above it). - bool showing_text_filter_; - - // Window text filter widget. As the user writes on it, we filter the items - // in the overview. It is also responsible for handling overview key events, - // such as enter key to select. - std::unique_ptr<views::Widget> text_filter_widget_; - - // Image used for text filter textfield. - gfx::ImageSkia search_image_; - - // The current length of the string entered into the text filtering textfield. - size_t text_filter_string_length_; - - // The number of times the text filtering textfield has been cleared of text - // during this overview mode session. - size_t num_times_textfield_cleared_; - - // Tracks whether minimized windows are currently being restored for overview - // mode. - bool restoring_minimized_windows_; - - // The distance between the top edge of the screen and the bottom edge of - // the text filtering textfield. - int text_filter_bottom_; - - bool is_shut_down_ = false; - - DISALLOW_COPY_AND_ASSIGN(WindowSelector); -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc deleted file mode 100644 index f74771f..0000000 --- a/ash/wm/overview/window_selector_controller.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/window_selector_controller.h" - -#include <vector> - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/system/tray/system_tray_delegate.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/window_state.h" -#include "base/metrics/histogram_macros.h" - -namespace ash { - -WindowSelectorController::WindowSelectorController() {} - -WindowSelectorController::~WindowSelectorController() { - // Destroy widgets that may be still animating if shell shuts down soon after - // exiting overview mode. - for (std::unique_ptr<DelayedAnimationObserver>& animation_observer : - delayed_animations_) { - animation_observer->Shutdown(); - } -} - -// static -bool WindowSelectorController::CanSelect() { - // Don't allow a window overview if the screen is locked or a modal dialog is - // open or running in kiosk app session. - WmShell* wm_shell = WmShell::Get(); - SessionStateDelegate* session_state_delegate = - wm_shell->GetSessionStateDelegate(); - SystemTrayDelegate* system_tray_delegate = wm_shell->system_tray_delegate(); - return session_state_delegate->IsActiveUserSessionStarted() && - !session_state_delegate->IsScreenLocked() && - !wm_shell->IsSystemModalWindowOpen() && !wm_shell->IsPinned() && - system_tray_delegate->GetUserLoginStatus() != LoginStatus::KIOSK_APP && - system_tray_delegate->GetUserLoginStatus() != - LoginStatus::ARC_KIOSK_APP; -} - -bool WindowSelectorController::ToggleOverview() { - if (IsSelecting()) { - OnSelectionEnded(); - } else { - // Don't start overview if window selection is not allowed. - if (!CanSelect()) - return false; - - std::vector<WmWindow*> windows = - WmShell::Get()->mru_window_tracker()->BuildMruWindowList(); - auto end = - std::remove_if(windows.begin(), windows.end(), - std::not1(std::ptr_fun(&WindowSelector::IsSelectable))); - windows.resize(end - windows.begin()); - - // Don't enter overview mode with no windows. - if (windows.empty()) - return false; - - WmShell::Get()->OnOverviewModeStarting(); - window_selector_.reset(new WindowSelector(this)); - window_selector_->Init(windows); - OnSelectionStarted(); - } - return true; -} - -bool WindowSelectorController::IsSelecting() const { - return window_selector_.get() != NULL; -} - -void WindowSelectorController::IncrementSelection(int increment) { - DCHECK(IsSelecting()); - window_selector_->IncrementSelection(increment); -} - -bool WindowSelectorController::AcceptSelection() { - DCHECK(IsSelecting()); - return window_selector_->AcceptSelection(); -} - -bool WindowSelectorController::IsRestoringMinimizedWindows() const { - return window_selector_.get() != NULL && - window_selector_->restoring_minimized_windows(); -} - -// TODO(flackr): Make WindowSelectorController observe the activation of -// windows, so we can remove WindowSelectorDelegate. -void WindowSelectorController::OnSelectionEnded() { - window_selector_->Shutdown(); - window_selector_.reset(); - last_selection_time_ = base::Time::Now(); - WmShell::Get()->OnOverviewModeEnded(); -} - -void WindowSelectorController::AddDelayedAnimationObserver( - std::unique_ptr<DelayedAnimationObserver> animation_observer) { - animation_observer->SetOwner(this); - delayed_animations_.push_back(std::move(animation_observer)); -} - -void WindowSelectorController::RemoveAndDestroyAnimationObserver( - DelayedAnimationObserver* animation_observer) { - class IsEqual { - public: - explicit IsEqual(DelayedAnimationObserver* animation_observer) - : animation_observer_(animation_observer) {} - bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) { - return (other.get() == animation_observer_); - } - - private: - const DelayedAnimationObserver* animation_observer_; - }; - delayed_animations_.erase( - std::remove_if(delayed_animations_.begin(), delayed_animations_.end(), - IsEqual(animation_observer)), - delayed_animations_.end()); -} - -void WindowSelectorController::OnSelectionStarted() { - if (!last_selection_time_.is_null()) { - UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse", - base::Time::Now() - last_selection_time_); - } -} - -} // namespace ash
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h deleted file mode 100644 index 83dcdb3..0000000 --- a/ash/wm/overview/window_selector_controller.h +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_ - -#include <list> -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_delegate.h" -#include "base/macros.h" -#include "base/time/time.h" - -namespace ash { -class WindowSelector; -class WindowSelectorTest; - -// Manages a window selector which displays an overview of all windows and -// allows selecting a window to activate it. -class ASH_EXPORT WindowSelectorController : public WindowSelectorDelegate { - public: - WindowSelectorController(); - ~WindowSelectorController() override; - - // Returns true if selecting windows in an overview is enabled. This is false - // at certain times, such as when the lock screen is visible. - static bool CanSelect(); - - // Attempts to toggle overview mode and returns true if successful (showing - // overview would be unsuccessful if there are no windows to show). - bool ToggleOverview(); - - // Returns true if window selection mode is active. - bool IsSelecting() const; - - // Moves the current selection by |increment| items. Positive values of - // |increment| move the selection forward, negative values move it backward. - void IncrementSelection(int increment); - - // Accepts current selection if any. Returns true if a selection was made, - // false otherwise. - bool AcceptSelection(); - - // Returns true if overview mode is restoring minimized windows so that they - // are visible during overview mode. - bool IsRestoringMinimizedWindows() const; - - // WindowSelectorDelegate: - void OnSelectionEnded() override; - void AddDelayedAnimationObserver( - std::unique_ptr<DelayedAnimationObserver> animation) override; - void RemoveAndDestroyAnimationObserver( - DelayedAnimationObserver* animation) override; - - private: - friend class WindowSelectorTest; - - // Dispatched when window selection begins. - void OnSelectionStarted(); - - // Collection of DelayedAnimationObserver objects that own widgets that may be - // still animating after overview mode ends. If shell needs to shut down while - // those animations are in progress, the animations are shut down and the - // widgets destroyed. - std::vector<std::unique_ptr<DelayedAnimationObserver>> delayed_animations_; - std::unique_ptr<WindowSelector> window_selector_; - base::Time last_selection_time_; - - DISALLOW_COPY_AND_ASSIGN(WindowSelectorController); -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_
diff --git a/ash/wm/overview/window_selector_delegate.h b/ash/wm/overview/window_selector_delegate.h deleted file mode 100644 index 021cede..0000000 --- a/ash/wm/overview/window_selector_delegate.h +++ /dev/null
@@ -1,54 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_ - -#include "ash/ash_export.h" -#include "base/compiler_specific.h" - -namespace ash { - -class WindowSelectorDelegate; - -class ASH_EXPORT DelayedAnimationObserver { - public: - virtual ~DelayedAnimationObserver() {} - - // Sets an |owner| that can be notified when the animation that |this| - // observes completes. - virtual void SetOwner(WindowSelectorDelegate* owner) = 0; - - // Can be called by the |owner| to delete the owned widget. The |owner| is - // then responsible for deleting |this| instance of the - // DelayedAnimationObserver. - virtual void Shutdown() = 0; -}; - -// Implement this class to handle the selection event from WindowSelector. -class ASH_EXPORT WindowSelectorDelegate { - public: - // Invoked if selection is ended. - virtual void OnSelectionEnded() = 0; - - // Passes ownership of |animation_observer| to |this| delegate. - virtual void AddDelayedAnimationObserver( - std::unique_ptr<DelayedAnimationObserver> animation_observer) = 0; - - // Finds and erases |animation_observer| from the list deleting the widget - // owned by the |animation_observer|. - // This method should be called when a scheduled animation completes. - // If the animation completion callback is a result of a window getting - // destroyed then the DelayedAnimationObserver::Shutdown() should be called - // first before destroying the window. - virtual void RemoveAndDestroyAnimationObserver( - DelayedAnimationObserver* animation_observer) = 0; - - protected: - virtual ~WindowSelectorDelegate() {} -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc deleted file mode 100644 index 34dd1e5..0000000 --- a/ash/wm/overview/window_selector_item.cc +++ /dev/null
@@ -1,764 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/overview/window_selector_item.h" - -#include <algorithm> -#include <vector> - -#include "ash/common/material_design/material_design_controller.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/vector_icons/vector_icons.h" -#include "ash/root_window_controller.h" -#include "ash/strings/grit/ash_strings.h" -#include "ash/wm/overview/cleanup_animation_observer.h" -#include "ash/wm/overview/overview_animation_type.h" -#include "ash/wm/overview/scoped_overview_animation_settings.h" -#include "ash/wm/overview/scoped_overview_animation_settings_factory.h" -#include "ash/wm/overview/scoped_transform_overview_window.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/window_state.h" -#include "base/auto_reset.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/time/time.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/compositor/layer_animation_sequence.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/gfx/animation/slide_animation.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/color_utils.h" -#include "ui/gfx/geometry/safe_integer_conversions.h" -#include "ui/gfx/paint_vector_icon.h" -#include "ui/gfx/transform_util.h" -#include "ui/strings/grit/ui_strings.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/window/non_client_view.h" -#include "ui/wm/core/shadow.h" -#include "ui/wm/core/window_util.h" - -namespace ash { - -namespace { - -// In the conceptual overview table, the window margin is the space reserved -// around the window within the cell. This margin does not overlap so the -// closest distance between adjacent windows will be twice this amount. -static const int kWindowMargin = 5; - -// Cover the transformed window including the gaps between the windows with a -// transparent shield to block the input events from reaching the transformed -// window while in overview. -static const int kWindowSelectorMargin = kWindowMargin * 2; - -// Foreground label color. -static const SkColor kLabelColor = SK_ColorWHITE; - -// TODO(tdanderson): Move this to a central location. -static const SkColor kCloseButtonColor = SK_ColorWHITE; - -// Label background color once in overview mode. -static const SkColor kLabelBackgroundColor = SkColorSetARGB(25, 255, 255, 255); - -// Label background color when exiting overview mode. -static const SkColor kLabelExitColor = SkColorSetARGB(255, 90, 90, 90); - -// Corner radius for the selection tiles. -static int kLabelBackgroundRadius = 2; - -// Horizontal padding for the label, on both sides. -static const int kHorizontalLabelPadding = 8; - -// Height of an item header. -static const int kHeaderHeight = 32; - -// Opacity for dimmed items. -static const float kDimmedItemOpacity = 0.5f; - -// Opacity for fading out during closing a window. -static const float kClosingItemOpacity = 0.8f; - -// Opacity for the item header. -static const float kHeaderOpacity = - (SkColorGetA(kLabelBackgroundColor) / 255.f); - -// Duration it takes for the header to shift from opaque header color to -// |kLabelBackgroundColor|. -static const int kSelectorColorSlideMilliseconds = 240; - -// Duration of background opacity transition for the selected label. -static const int kSelectorFadeInMilliseconds = 350; - -// Duration of background opacity transition when exiting overview mode. -static const int kExitFadeInMilliseconds = 30; - -// Before closing a window animate both the window and the caption to shrink by -// this fraction of size. -static const float kPreCloseScale = 0.02f; - -// Convenience method to fade in a Window with predefined animation settings. -// Note: The fade in animation will occur after a delay where the delay is how -// long the lay out animations take. -void SetupFadeInAfterLayout(views::Widget* widget) { - WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); - window->SetOpacity(0.0f); - std::unique_ptr<ScopedOverviewAnimationSettings> - scoped_overview_animation_settings = - ScopedOverviewAnimationSettingsFactory::Get() - ->CreateOverviewAnimationSettings( - OverviewAnimationType:: - OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN, - window); - window->SetOpacity(1.0f); -} - -// A Button that has a listener and listens to mouse clicks on the visible part -// of an overview window. -class ShieldButton : public views::CustomButton { - public: - ShieldButton(views::ButtonListener* listener, const base::string16& name) - : views::CustomButton(listener) { - SetAccessibleName(name); - } - ~ShieldButton() override {} - - // When WindowSelectorItem (which is a ButtonListener) is destroyed, its - // |item_widget_| is allowed to stay around to complete any animations. - // Resetting the listener in all views that are targeted by events is - // necessary to prevent a crash when a user clicks on the fading out widget - // after the WindowSelectorItem has been destroyed. - void ResetListener() { listener_ = nullptr; } - - protected: - // views::View: - const char* GetClassName() const override { return "ShieldButton"; } - - private: - DISALLOW_COPY_AND_ASSIGN(ShieldButton); -}; - -} // namespace - -WindowSelectorItem::OverviewCloseButton::OverviewCloseButton( - views::ButtonListener* listener) - : views::ImageButton(listener) { - SetImage(views::CustomButton::STATE_NORMAL, - gfx::CreateVectorIcon(kWindowControlCloseIcon, kCloseButtonColor)); - SetImageAlignment(views::ImageButton::ALIGN_CENTER, - views::ImageButton::ALIGN_MIDDLE); - SetMinimumImageSize(gfx::Size(kHeaderHeight, kHeaderHeight)); -} - -WindowSelectorItem::OverviewCloseButton::~OverviewCloseButton() {} - -// A View having rounded top corners and a specified background color which is -// only painted within the bounds defined by the rounded corners. -// This class coordinates the transitions of the overview mode header when -// entering the overview mode. Those animations are: -// - Opacity animation. The header is initially same color as the original -// window's header. It starts as transparent and is faded in. When the full -// opacity is reached the original header is hidden (which is nearly -// imperceptable because this view obscures the original header) and a color -// animation starts. -// - Color animation is used to change the color from the opaque color of the -// original window's header to semi-transparent color of the overview mode -// header (on entry to overview). It is also used on exit from overview to -// quickly change the color to a close opaque color in parallel with an -// opacity transition to mask the original header reappearing. -class WindowSelectorItem::RoundedContainerView - : public views::View, - public gfx::AnimationDelegate, - public ui::LayerAnimationObserver { - public: - RoundedContainerView(WindowSelectorItem* item, - WmWindow* item_window, - int corner_radius, - SkColor background) - : item_(item), - item_window_(item_window), - corner_radius_(corner_radius), - initial_color_(background), - target_color_(background), - current_value_(0), - layer_(nullptr), - animation_(new gfx::SlideAnimation(this)) { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - } - - ~RoundedContainerView() override { StopObservingLayerAnimations(); } - - void OnItemRestored() { - item_ = nullptr; - item_window_ = nullptr; - } - - // Starts observing layer animations so that actions can be taken when - // particular animations (opacity) complete. It should only be called once - // when the initial fade in animation is started. - void ObserveLayerAnimations(ui::Layer* layer) { - DCHECK(!layer_); - layer_ = layer; - layer_->GetAnimator()->AddObserver(this); - } - - // Stops observing layer animations - void StopObservingLayerAnimations() { - if (!layer_) - return; - layer_->GetAnimator()->RemoveObserver(this); - layer_ = nullptr; - } - - // Used by tests to set animation state. - gfx::SlideAnimation* animation() { return animation_.get(); } - - void set_color(SkColor target_color) { target_color_ = target_color; } - - // Starts a color animation using |tween_type|. The animation will change the - // color from |initial_color_| to |target_color_| over |duration| specified - // in milliseconds. - // This animation can start once the implicit layer fade-in opacity animation - // is completed. It is used to transition color from the opaque original - // window header color to |kLabelBackgroundColor| on entry into overview mode - // and from |kLabelBackgroundColor| back to the original window header color - // on exit from the overview mode. - void AnimateColor(gfx::Tween::Type tween_type, int duration) { - DCHECK(!layer_); // layer animations should be completed. - animation_->SetSlideDuration(duration); - animation_->SetTweenType(tween_type); - animation_->Reset(0); - animation_->Show(); - - // Tests complete animations immediately. Emulate by invoking the callback. - if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() == - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION) { - AnimationEnded(animation_.get()); - } - } - - // Changes the view opacity by animating its background color. The animation - // will change the alpha value in |target_color_| from its current value to - // |opacity| * 255 but preserve the RGB values. - void AnimateBackgroundOpacity(float opacity) { - animation_->SetSlideDuration(kSelectorFadeInMilliseconds); - animation_->SetTweenType(gfx::Tween::EASE_OUT); - animation_->Reset(0); - animation_->Show(); - target_color_ = SkColorSetA(target_color_, opacity * 255); - } - - // views::View: - void OnPaint(gfx::Canvas* canvas) override { - views::View::OnPaint(canvas); - SkScalar radius = SkIntToScalar(corner_radius_); - const SkScalar kRadius[8] = {radius, radius, radius, radius, 0, 0, 0, 0}; - SkPath path; - gfx::Rect bounds(size()); - path.addRoundRect(gfx::RectToSkRect(bounds), kRadius); - - cc::PaintFlags flags; - flags.setAntiAlias(true); - canvas->ClipPath(path, true); - - SkColor target_color = initial_color_; - if (target_color_ != target_color) { - target_color = color_utils::AlphaBlend(target_color_, initial_color_, - current_value_); - } - canvas->DrawColor(target_color); - } - - const char* GetClassName() const override { return "RoundedContainerView"; } - - private: - // gfx::AnimationDelegate: - void AnimationEnded(const gfx::Animation* animation) override { - initial_color_ = target_color_; - // Tabbed browser windows show the overview mode header behind the window - // during the initial animation. Once the initial fade-in completes and the - // overview header is fully exposed update stacking to keep the label above - // the item which prevents input events from reaching the window. - WmWindow* widget_window = WmWindow::Get(GetWidget()->GetNativeWindow()); - if (widget_window && item_window_) - widget_window->GetParent()->StackChildAbove(widget_window, item_window_); - item_window_ = nullptr; - } - - void AnimationProgressed(const gfx::Animation* animation) override { - current_value_ = animation_->CurrentValueBetween(0, 255); - SchedulePaint(); - } - - void AnimationCanceled(const gfx::Animation* animation) override { - item_window_ = nullptr; - initial_color_ = target_color_; - current_value_ = 255; - SchedulePaint(); - } - - // ui::LayerAnimationObserver: - void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override { - if (0 != (sequence->properties() & - ui::LayerAnimationElement::AnimatableProperty::OPACITY)) { - if (item_) - item_->HideHeader(); - StopObservingLayerAnimations(); - AnimateColor(gfx::Tween::EASE_IN, kSelectorColorSlideMilliseconds); - } - } - - void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override { - if (0 != (sequence->properties() & - ui::LayerAnimationElement::AnimatableProperty::OPACITY)) { - StopObservingLayerAnimations(); - } - } - - void OnLayerAnimationScheduled( - ui::LayerAnimationSequence* sequence) override {} - - WindowSelectorItem* item_; - WmWindow* item_window_; - int corner_radius_; - SkColor initial_color_; - SkColor target_color_; - int current_value_; - ui::Layer* layer_; - std::unique_ptr<gfx::SlideAnimation> animation_; - - DISALLOW_COPY_AND_ASSIGN(RoundedContainerView); -}; - -// A Container View that has a ShieldButton to listen to events. The -// ShieldButton covers most of the View except for the transparent gap between -// the windows and is visually transparent. The ShieldButton owns a background -// non-transparent view positioned at the ShieldButton top. The background view -// in its turn owns an item text label and a close button. -// The text label does not receive events, however the close button is higher in -// Z-order than its parent and receives events forwarding them to the same -// |listener| (i.e. WindowSelectorItem::ButtonPressed()). -class WindowSelectorItem::CaptionContainerView : public views::View { - public: - CaptionContainerView(ButtonListener* listener, - views::Label* label, - views::ImageButton* close_button, - WindowSelectorItem::RoundedContainerView* background) - : listener_button_(new ShieldButton(listener, label->text())), - background_(background), - label_(label), - close_button_(close_button) { - background_->AddChildView(label_); - background_->AddChildView(close_button_); - listener_button_->AddChildView(background_); - AddChildView(listener_button_); - } - - ShieldButton* listener_button() { return listener_button_; } - - protected: - // views::View: - void Layout() override { - // Position close button in the top right corner sized to its icon size and - // the label in the top left corner as tall as the button and extending to - // the button's left edge. - // The rest of this container view serves as a shield to prevent input - // events from reaching the transformed window in overview. - gfx::Rect bounds(GetLocalBounds()); - bounds.Inset(kWindowSelectorMargin, kWindowSelectorMargin); - listener_button_->SetBoundsRect(bounds); - - const int visible_height = close_button_->GetPreferredSize().height(); - gfx::Rect background_bounds(gfx::Rect(bounds.size())); - background_bounds.set_height(visible_height); - background_->SetBoundsRect(background_bounds); - - bounds = background_bounds; - bounds.Inset(kHorizontalLabelPadding, 0, - kHorizontalLabelPadding + visible_height, 0); - label_->SetBoundsRect(bounds); - - bounds = background_bounds; - bounds.set_x(bounds.width() - visible_height); - bounds.set_width(visible_height); - close_button_->SetBoundsRect(bounds); - } - - const char* GetClassName() const override { return "CaptionContainerView"; } - - private: - ShieldButton* listener_button_; - WindowSelectorItem::RoundedContainerView* background_; - views::Label* label_; - views::ImageButton* close_button_; - - DISALLOW_COPY_AND_ASSIGN(CaptionContainerView); -}; - -WindowSelectorItem::WindowSelectorItem(WmWindow* window, - WindowSelector* window_selector) - : dimmed_(false), - root_window_(window->GetRootWindow()), - transform_window_(window), - in_bounds_update_(false), - selected_(false), - caption_container_view_(nullptr), - label_view_(nullptr), - close_button_(new OverviewCloseButton(this)), - window_selector_(window_selector), - background_view_(nullptr) { - CreateWindowLabel(window->GetTitle()); - GetWindow()->aura_window()->AddObserver(this); -} - -WindowSelectorItem::~WindowSelectorItem() { - GetWindow()->aura_window()->RemoveObserver(this); -} - -WmWindow* WindowSelectorItem::GetWindow() { - return transform_window_.window(); -} - -void WindowSelectorItem::RestoreWindow() { - caption_container_view_->listener_button()->ResetListener(); - close_button_->ResetListener(); - transform_window_.RestoreWindow(); - if (background_view_) { - background_view_->OnItemRestored(); - background_view_ = nullptr; - } - UpdateHeaderLayout( - HeaderFadeInMode::EXIT, - OverviewAnimationType::OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS); -} - -void WindowSelectorItem::EnsureVisible() { - transform_window_.EnsureVisible(); -} - -void WindowSelectorItem::Shutdown() { - if (transform_window_.GetTopInset()) { - // Activating a window (even when it is the window that was active before - // overview) results in stacking it at the top. Maintain the label window - // stacking position above the item to make the header transformation more - // gradual upon exiting the overview mode. - WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); - - // |widget_window| was originally created in the same container as the - // |transform_window_| but when closing overview the |transform_window_| - // could have been reparented if a drag was active. Only change stacking - // if the windows still belong to the same container. - if (widget_window->GetParent() == transform_window_.window()->GetParent()) { - widget_window->GetParent()->StackChildAbove(widget_window, - transform_window_.window()); - } - } - if (background_view_) { - background_view_->OnItemRestored(); - background_view_ = nullptr; - } - FadeOut(std::move(item_widget_)); -} - -void WindowSelectorItem::PrepareForOverview() { - transform_window_.PrepareForOverview(); - UpdateHeaderLayout(HeaderFadeInMode::ENTER, - OverviewAnimationType::OVERVIEW_ANIMATION_NONE); -} - -bool WindowSelectorItem::Contains(const WmWindow* target) const { - return transform_window_.Contains(target); -} - -void WindowSelectorItem::SetBounds(const gfx::Rect& target_bounds, - OverviewAnimationType animation_type) { - if (in_bounds_update_) - return; - base::AutoReset<bool> auto_reset_in_bounds_update(&in_bounds_update_, true); - target_bounds_ = target_bounds; - - gfx::Rect inset_bounds(target_bounds); - inset_bounds.Inset(kWindowMargin, kWindowMargin); - SetItemBounds(inset_bounds, animation_type); - - // SetItemBounds is called before UpdateHeaderLayout so the header can - // properly use the updated windows bounds. - UpdateHeaderLayout(HeaderFadeInMode::UPDATE, animation_type); -} - -void WindowSelectorItem::SetSelected(bool selected) { - selected_ = selected; - background_view_->AnimateBackgroundOpacity(selected ? 0.f : kHeaderOpacity); -} - -void WindowSelectorItem::SendAccessibleSelectionEvent() { - caption_container_view_->listener_button()->NotifyAccessibilityEvent( - ui::AX_EVENT_SELECTION, true); -} - -void WindowSelectorItem::CloseWindow() { - gfx::Rect inset_bounds(target_bounds_); - inset_bounds.Inset(target_bounds_.width() * kPreCloseScale, - target_bounds_.height() * kPreCloseScale); - OverviewAnimationType animation_type = - OverviewAnimationType::OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM; - // Scale down both the window and label. - SetBounds(inset_bounds, animation_type); - // First animate opacity to an intermediate value concurrently with the - // scaling animation. - AnimateOpacity(kClosingItemOpacity, animation_type); - - // Fade out the window and the label, effectively hiding them. - AnimateOpacity(0.0, - OverviewAnimationType::OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM); - transform_window_.Close(); -} - -void WindowSelectorItem::HideHeader() { - transform_window_.HideHeader(); -} - -void WindowSelectorItem::OnMinimizedStateChanged() { - transform_window_.UpdateMirrorWindowForMinimizedState(); -} - -void WindowSelectorItem::SetDimmed(bool dimmed) { - dimmed_ = dimmed; - SetOpacity(dimmed ? kDimmedItemOpacity : 1.0f); -} - -void WindowSelectorItem::ButtonPressed(views::Button* sender, - const ui::Event& event) { - if (sender == close_button_) { - WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_CLOSE_BUTTON); - CloseWindow(); - return; - } - CHECK(sender == caption_container_view_->listener_button()); - window_selector_->SelectWindow(this); -} - -void WindowSelectorItem::OnWindowDestroying(aura::Window* window) { - window->RemoveObserver(this); - transform_window_.OnWindowDestroyed(); -} - -void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) { - // TODO(flackr): Maybe add the new title to a vector of titles so that we can - // filter any of the titles the window had while in the overview session. - label_view_->SetText(window->GetTitle()); - UpdateAccessibilityName(); -} - -float WindowSelectorItem::GetItemScale(const gfx::Size& size) { - gfx::Size inset_size(size.width(), size.height() - 2 * kWindowMargin); - return ScopedTransformOverviewWindow::GetItemScale( - transform_window_.GetTargetBoundsInScreen().size(), inset_size, - transform_window_.GetTopInset(), - close_button_->GetPreferredSize().height()); -} - -gfx::Rect WindowSelectorItem::GetTargetBoundsInScreen() const { - return transform_window_.GetTargetBoundsInScreen(); -} - -void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds, - OverviewAnimationType animation_type) { - DCHECK(root_window_ == GetWindow()->GetRootWindow()); - gfx::Rect screen_rect = transform_window_.GetTargetBoundsInScreen(); - - // Avoid division by zero by ensuring screen bounds is not empty. - gfx::Size screen_size(screen_rect.size()); - screen_size.SetToMax(gfx::Size(1, 1)); - screen_rect.set_size(screen_size); - - const int top_view_inset = transform_window_.GetTopInset(); - const int title_height = close_button_->GetPreferredSize().height(); - gfx::Rect selector_item_bounds = - ScopedTransformOverviewWindow::ShrinkRectToFitPreservingAspectRatio( - screen_rect, target_bounds, top_view_inset, title_height); - gfx::Transform transform = ScopedTransformOverviewWindow::GetTransformForRect( - screen_rect, selector_item_bounds); - ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; - transform_window_.BeginScopedAnimation(animation_type, &animation_settings); - transform_window_.SetTransform(root_window_, transform); -} - -void WindowSelectorItem::SetOpacity(float opacity) { - item_widget_->SetOpacity(opacity); - if (background_view_) { - background_view_->AnimateBackgroundOpacity( - selected_ ? 0.f : kHeaderOpacity * opacity); - } - transform_window_.SetOpacity(opacity); -} - -void WindowSelectorItem::CreateWindowLabel(const base::string16& title) { - background_view_ = new RoundedContainerView(this, transform_window_.window(), - kLabelBackgroundRadius, - transform_window_.GetTopColor()); - // |background_view_| will get added as a child to CaptionContainerView. - views::Widget::InitParams params_label; - params_label.type = views::Widget::InitParams::TYPE_POPUP; - params_label.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params_label.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params_label.visible_on_all_workspaces = true; - params_label.layer_type = ui::LAYER_NOT_DRAWN; - params_label.name = "OverviewModeLabel"; - params_label.activatable = - views::Widget::InitParams::Activatable::ACTIVATABLE_DEFAULT; - params_label.accept_events = true; - item_widget_.reset(new views::Widget); - root_window_->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - item_widget_.get(), - transform_window_.window()->GetParent()->GetShellWindowId(), - ¶ms_label); - item_widget_->set_focus_on_creation(false); - item_widget_->Init(params_label); - WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); - if (transform_window_.GetTopInset()) { - // For windows with headers the overview header fades in above the - // original window header. - widget_window->GetParent()->StackChildAbove(widget_window, - transform_window_.window()); - } else { - // For tabbed windows the overview header slides from behind. The stacking - // is then corrected when the animation completes. - widget_window->GetParent()->StackChildBelow(widget_window, - transform_window_.window()); - } - label_view_ = new views::Label(title); - label_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - label_view_->SetAutoColorReadabilityEnabled(false); - label_view_->SetEnabledColor(kLabelColor); - // Tell the label what color it will be drawn onto. It will use whether the - // background color is opaque or transparent to decide whether to use - // subpixel rendering. Does not actually set the label's background color. - label_view_->SetBackgroundColor(kLabelBackgroundColor); - - caption_container_view_ = new CaptionContainerView( - this, label_view_, close_button_, background_view_); - item_widget_->SetContentsView(caption_container_view_); - label_view_->SetVisible(false); - item_widget_->SetOpacity(0); - item_widget_->Show(); - item_widget_->GetLayer()->SetMasksToBounds(false); -} - -void WindowSelectorItem::UpdateHeaderLayout( - HeaderFadeInMode mode, - OverviewAnimationType animation_type) { - gfx::Rect transformed_window_bounds = root_window_->ConvertRectFromScreen( - transform_window_.GetTransformedBounds()); - - gfx::Rect label_rect(close_button_->GetPreferredSize()); - label_rect.set_width(transformed_window_bounds.width()); - // For tabbed windows the initial bounds of the caption are set such that it - // appears to be "growing" up from the window content area. - label_rect.set_y( - (mode != HeaderFadeInMode::ENTER || transform_window_.GetTopInset()) - ? -label_rect.height() - : 0); - if (background_view_) { - if (mode == HeaderFadeInMode::ENTER) { - background_view_->ObserveLayerAnimations(item_widget_->GetLayer()); - background_view_->set_color(kLabelBackgroundColor); - // The color will be animated only once the label widget is faded in. - } else if (mode == HeaderFadeInMode::EXIT) { - // Normally the observer is disconnected when the fade-in animations - // complete but some tests invoke animations with |NON_ZERO_DURATION| - // without waiting for completion so do it here. - background_view_->StopObservingLayerAnimations(); - // Make the header visible above the window. It will be faded out when - // the Shutdown() is called. - background_view_->AnimateColor(gfx::Tween::EASE_OUT, - kExitFadeInMilliseconds); - background_view_->set_color(kLabelExitColor); - } - } - if (!label_view_->visible()) { - label_view_->SetVisible(true); - SetupFadeInAfterLayout(item_widget_.get()); - } - WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); - std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings = - ScopedOverviewAnimationSettingsFactory::Get() - ->CreateOverviewAnimationSettings(animation_type, widget_window); - // |widget_window| covers both the transformed window and the header - // as well as the gap between the windows to prevent events from reaching - // the window including its sizing borders. - if (mode != HeaderFadeInMode::ENTER) { - label_rect.set_height(close_button_->GetPreferredSize().height() + - transformed_window_bounds.height()); - } - label_rect.Inset(-kWindowSelectorMargin, -kWindowSelectorMargin); - widget_window->SetBounds(label_rect); - gfx::Transform label_transform; - label_transform.Translate(transformed_window_bounds.x(), - transformed_window_bounds.y()); - widget_window->SetTransform(label_transform); -} - -void WindowSelectorItem::AnimateOpacity(float opacity, - OverviewAnimationType animation_type) { - DCHECK_GE(opacity, 0.f); - DCHECK_LE(opacity, 1.f); - ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings; - transform_window_.BeginScopedAnimation(animation_type, &animation_settings); - transform_window_.SetOpacity(opacity); - - const float header_opacity = selected_ ? 0.f : kHeaderOpacity * opacity; - WmWindow* widget_window = WmWindow::Get(item_widget_->GetNativeWindow()); - std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings_label = - ScopedOverviewAnimationSettingsFactory::Get() - ->CreateOverviewAnimationSettings(animation_type, widget_window); - widget_window->SetOpacity(header_opacity); -} - -void WindowSelectorItem::UpdateAccessibilityName() { - caption_container_view_->listener_button()->SetAccessibleName( - GetWindow()->GetTitle()); -} - -void WindowSelectorItem::FadeOut(std::unique_ptr<views::Widget> widget) { - widget->SetOpacity(1.f); - - // Fade out the widget. This animation continues past the lifetime of |this|. - WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow()); - std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings = - ScopedOverviewAnimationSettingsFactory::Get() - ->CreateOverviewAnimationSettings( - OverviewAnimationType:: - OVERVIEW_ANIMATION_EXIT_OVERVIEW_MODE_FADE_OUT, - widget_window); - // CleanupAnimationObserver will delete itself (and the widget) when the - // opacity animation is complete. - // Ownership over the observer is passed to the window_selector_->delegate() - // which has longer lifetime so that animations can continue even after the - // overview mode is shut down. - views::Widget* widget_ptr = widget.get(); - std::unique_ptr<CleanupAnimationObserver> observer( - new CleanupAnimationObserver(std::move(widget))); - animation_settings->AddObserver(observer.get()); - window_selector_->delegate()->AddDelayedAnimationObserver( - std::move(observer)); - widget_ptr->SetOpacity(0.f); -} - -gfx::SlideAnimation* WindowSelectorItem::GetBackgroundViewAnimation() { - return background_view_ ? background_view_->animation() : nullptr; -} - -WmWindow* WindowSelectorItem::GetOverviewWindowForMinimizedStateForTest() { - return transform_window_.GetOverviewWindowForMinimizedState(); -} - -} // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h deleted file mode 100644 index 7d58e72..0000000 --- a/ash/wm/overview/window_selector_item.h +++ /dev/null
@@ -1,224 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ -#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/overview/scoped_transform_overview_window.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/image_button.h" -#include "ui/views/controls/label.h" -#include "ui/views/widget/widget.h" - -namespace gfx { -class SlideAnimation; -} - -namespace views { -class ImageButton; -} - -namespace ash { - -class WindowSelector; -class WmWindow; - -// This class represents an item in overview mode. -class ASH_EXPORT WindowSelectorItem : public views::ButtonListener, - public aura::WindowObserver { - public: - // An image button with a close window icon. - class OverviewCloseButton : public views::ImageButton { - public: - explicit OverviewCloseButton(views::ButtonListener* listener); - ~OverviewCloseButton() override; - - // Resets the listener so that the listener can go out of scope. - void ResetListener() { listener_ = nullptr; } - - private: - DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton); - }; - - WindowSelectorItem(WmWindow* window, WindowSelector* window_selector); - ~WindowSelectorItem() override; - - WmWindow* GetWindow(); - - // Returns the root window on which this item is shown. - WmWindow* root_window() { return root_window_; } - - // Returns true if |target| is contained in this WindowSelectorItem. - bool Contains(const WmWindow* target) const; - - // Restores and animates the managed window to its non overview mode state. - void RestoreWindow(); - - // Ensures that a possibly minimized window becomes visible after restore. - void EnsureVisible(); - - // Restores stacking of window captions above the windows, then fades out. - void Shutdown(); - - // Dispatched before beginning window overview. This will do any necessary - // one time actions such as restoring minimized windows. - void PrepareForOverview(); - - // Calculates and returns an optimal scale ratio. With MD this is only - // taking into account |size.height()| as the width can vary. Without MD this - // returns the scale that allows the item to fully fit within |size|. - float GetItemScale(const gfx::Size& size); - - // Returns the union of the original target bounds of all transformed windows - // managed by |this| item, i.e. all regular (normal or panel transient - // descendants of the window returned by GetWindow()). - gfx::Rect GetTargetBoundsInScreen() const; - - // Sets the bounds of this window selector item to |target_bounds| in the - // |root_window_| root window. The bounds change will be animated as specified - // by |animation_type|. - void SetBounds(const gfx::Rect& target_bounds, - OverviewAnimationType animation_type); - - // Activates or deactivates selection depending on |selected|. - // In selected state the item's caption is shown transparent and blends with - // the selection widget. - void SetSelected(bool selected); - - // Sends an accessibility event indicating that this window became selected - // so that it's highlighted and announced if accessibility features are - // enabled. - void SendAccessibleSelectionEvent(); - - // Closes |transform_window_|. - void CloseWindow(); - - // Hides the original window header. - void HideHeader(); - - // Called when the window is minimized or unminimized. - void OnMinimizedStateChanged(); - - // Sets if the item is dimmed in the overview. Changing the value will also - // change the visibility of the transform windows. - void SetDimmed(bool dimmed); - bool dimmed() const { return dimmed_; } - - const gfx::Rect& target_bounds() const { return target_bounds_; } - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - void OnWindowTitleChanged(aura::Window* window) override; - - private: - class CaptionContainerView; - class RoundedContainerView; - friend class WindowSelectorTest; - - enum class HeaderFadeInMode { - ENTER, - UPDATE, - EXIT, - }; - - // Sets the bounds of this selector's items to |target_bounds| in - // |root_window_|. The bounds change will be animated as specified - // by |animation_type|. - void SetItemBounds(const gfx::Rect& target_bounds, - OverviewAnimationType animation_type); - - // Changes the opacity of all the windows the item owns. - void SetOpacity(float opacity); - - // Creates the window label. - void CreateWindowLabel(const base::string16& title); - - // Updates the close button's and title label's bounds. Any change in bounds - // will be animated from the current bounds to the new bounds as per the - // |animation_type|. |mode| allows distinguishing the first time update which - // allows setting the initial bounds properly or exiting overview to fade out - // gradually. - void UpdateHeaderLayout(HeaderFadeInMode mode, - OverviewAnimationType animation_type); - - // Animates opacity of the |transform_window_| and its caption to |opacity| - // using |animation_type|. - void AnimateOpacity(float opacity, OverviewAnimationType animation_type); - - // Updates the accessibility name to match the window title. - void UpdateAccessibilityName(); - - // Fades out a window caption when exiting overview mode. - void FadeOut(std::unique_ptr<views::Widget> widget); - - // Allows a test to directly set animation state. - gfx::SlideAnimation* GetBackgroundViewAnimation(); - - WmWindow* GetOverviewWindowForMinimizedStateForTest(); - - // True if the item is being shown in the overview, false if it's being - // filtered. - bool dimmed_; - - // The root window this item is being displayed on. - WmWindow* root_window_; - - // The contained Window's wrapper. - ScopedTransformOverviewWindow transform_window_; - - // The target bounds this selector item is fit within. - gfx::Rect target_bounds_; - - // True if running SetItemBounds. This prevents recursive calls resulting from - // the bounds update when calling ::wm::RecreateWindowLayers to copy - // a window layer for display on another monitor. - bool in_bounds_update_; - - // True when |this| item is visually selected. Item header is made transparent - // when the item is selected. - bool selected_; - - // A widget that covers the |transform_window_|. The widget has - // |caption_container_view_| as its contents view. The widget is backed by a - // NOT_DRAWN layer since most of its surface is transparent. - std::unique_ptr<views::Widget> item_widget_; - - // Container view that owns a Button view covering the |transform_window_|. - // That button serves as an event shield to receive all events such as clicks - // targeting the |transform_window_| or the overview header above the window. - // The shield button owns |background_view_| which owns |label_view_| - // and |close_button_|. - CaptionContainerView* caption_container_view_; - - // A View for the text label above the window owned by the |background_view_|. - views::Label* label_view_; - - // A close button for the window in this item owned by the |background_view_|. - OverviewCloseButton* close_button_; - - // Pointer to the WindowSelector that owns the WindowGrid containing |this|. - // Guaranteed to be non-null for the lifetime of |this|. - WindowSelector* window_selector_; - - // Pointer to a view that covers the original header and has rounded top - // corners. This view can have its color and opacity animated. It has a layer - // which is the only textured layer used by the |item_widget_|. - RoundedContainerView* background_view_; - - DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem); -}; - -} // namespace ash - -#endif // ASH_WM_OVERVIEW_WINDOW_SELECTOR_ITEM_H_
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc index 682a10d..0629a5d 100644 --- a/ash/wm/overview/window_selector_unittest.cc +++ b/ash/wm/overview/window_selector_unittest.cc
@@ -8,34 +8,34 @@ #include "ash/common/accessibility_delegate.h" #include "ash/common/accessibility_types.h" #include "ash/common/ash_switches.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/dock/docked_window_layout_manager.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/overview/scoped_transform_overview_window.h" +#include "ash/common/wm/overview/window_grid.h" +#include "ash/common/wm/overview/window_selector.h" +#include "ash/common/wm/overview/window_selector_controller.h" +#include "ash/common/wm/overview/window_selector_item.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace/workspace_window_resizer.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/drag_drop/drag_drop_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "ash/test/ash_test_base.h" #include "ash/test/shelf_view_test_api.h" #include "ash/test/shell_test_api.h" #include "ash/test/test_app_list_view_presenter_impl.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/overview/scoped_transform_overview_window.h" -#include "ash/wm/overview/window_grid.h" -#include "ash/wm/overview/window_selector.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/overview/window_selector_item.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace/workspace_window_resizer.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/memory/ptr_util.h"
diff --git a/ash/wm/panels/attached_panel_window_targeter.cc b/ash/wm/panels/attached_panel_window_targeter.cc index d7f50a6c..6380b44 100644 --- a/ash/wm/panels/attached_panel_window_targeter.cc +++ b/ash/wm/panels/attached_panel_window_targeter.cc
@@ -4,10 +4,10 @@ #include "ash/wm/panels/attached_panel_window_targeter.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/panels/panel_layout_manager.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/panels/panel_layout_manager.h" #include "ui/aura/window.h" namespace ash {
diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc deleted file mode 100644 index 5f7fe58..0000000 --- a/ash/wm/panels/panel_frame_view.cc +++ /dev/null
@@ -1,160 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/panels/panel_frame_view.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/default_header_painter.h" -#include "ash/frame/frame_border_hit_test.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/window.h" -#include "ui/base/hit_test.h" -#include "ui/gfx/canvas.h" -#include "ui/views/controls/image_view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { - -// static -const char PanelFrameView::kViewClassName[] = "PanelFrameView"; - -PanelFrameView::PanelFrameView(views::Widget* frame, FrameType frame_type) - : frame_(frame), caption_button_container_(nullptr), window_icon_(nullptr) { - GetWidgetWindow()->InstallResizeHandleWindowTargeter(nullptr); - DCHECK(!frame_->widget_delegate()->CanMaximize()); - if (frame_type != FRAME_NONE) - InitHeaderPainter(); - WmShell::Get()->AddShellObserver(this); -} - -PanelFrameView::~PanelFrameView() { - WmShell::Get()->RemoveShellObserver(this); -} - -void PanelFrameView::SetFrameColors(SkColor active_frame_color, - SkColor inactive_frame_color) { - header_painter_->SetFrameColors(active_frame_color, inactive_frame_color); - GetWidgetWindow()->aura_window()->SetProperty( - aura::client::kTopViewColor, header_painter_->GetInactiveFrameColor()); -} - -const char* PanelFrameView::GetClassName() const { - return kViewClassName; -} - -void PanelFrameView::InitHeaderPainter() { - header_painter_.reset(new DefaultHeaderPainter); - GetWidgetWindow()->aura_window()->SetProperty( - aura::client::kTopViewColor, header_painter_->GetInactiveFrameColor()); - - caption_button_container_ = new FrameCaptionButtonContainerView(frame_); - AddChildView(caption_button_container_); - - header_painter_->Init(frame_, this, caption_button_container_); - - if (frame_->widget_delegate()->ShouldShowWindowIcon()) { - window_icon_ = new views::ImageView(); - AddChildView(window_icon_); - header_painter_->UpdateLeftHeaderView(window_icon_); - } -} - -WmWindow* PanelFrameView::GetWidgetWindow() { - return WmWindow::Get(frame_->GetNativeWindow()); -} - -int PanelFrameView::NonClientTopBorderHeight() const { - if (!header_painter_) - return 0; - return header_painter_->GetHeaderHeightForPainting(); -} - -gfx::Size PanelFrameView::GetMinimumSize() const { - if (!header_painter_) - return gfx::Size(); - gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize()); - return gfx::Size(std::max(header_painter_->GetMinimumHeaderWidth(), - min_client_view_size.width()), - NonClientTopBorderHeight() + min_client_view_size.height()); -} - -void PanelFrameView::Layout() { - if (!header_painter_) - return; - header_painter_->LayoutHeader(); - GetWidgetWindow()->aura_window()->SetProperty(aura::client::kTopViewInset, - NonClientTopBorderHeight()); -} - -void PanelFrameView::GetWindowMask(const gfx::Size&, gfx::Path*) { - // Nothing. -} - -void PanelFrameView::ResetWindowControls() { - NOTIMPLEMENTED(); -} - -void PanelFrameView::UpdateWindowIcon() { - if (!window_icon_) - return; - views::WidgetDelegate* delegate = frame_->widget_delegate(); - if (delegate) - window_icon_->SetImage(delegate->GetWindowIcon()); - window_icon_->SchedulePaint(); -} - -void PanelFrameView::UpdateWindowTitle() { - if (!header_painter_) - return; - header_painter_->SchedulePaintForTitle(); -} - -void PanelFrameView::SizeConstraintsChanged() {} - -gfx::Rect PanelFrameView::GetBoundsForClientView() const { - gfx::Rect client_bounds = bounds(); - client_bounds.Inset(0, NonClientTopBorderHeight(), 0, 0); - return client_bounds; -} - -gfx::Rect PanelFrameView::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const { - gfx::Rect window_bounds = client_bounds; - window_bounds.Inset(0, -NonClientTopBorderHeight(), 0, 0); - return window_bounds; -} - -int PanelFrameView::NonClientHitTest(const gfx::Point& point) { - if (!header_painter_) - return HTNOWHERE; - return FrameBorderNonClientHitTest(this, caption_button_container_, point); -} - -void PanelFrameView::OnPaint(gfx::Canvas* canvas) { - if (!header_painter_) - return; - bool paint_as_active = ShouldPaintAsActive(); - caption_button_container_->SetPaintAsActive(paint_as_active); - - HeaderPainter::Mode header_mode = paint_as_active - ? HeaderPainter::MODE_ACTIVE - : HeaderPainter::MODE_INACTIVE; - header_painter_->PaintHeader(canvas, header_mode); -} - -/////////////////////////////////////////////////////////////////////////////// -// PanelFrameView, ShellObserver overrides: - -void PanelFrameView::OnOverviewModeStarting() { - caption_button_container_->SetVisible(false); -} - -void PanelFrameView::OnOverviewModeEnded() { - caption_button_container_->SetVisible(true); -} - -} // namespace ash
diff --git a/ash/wm/panels/panel_frame_view.h b/ash/wm/panels/panel_frame_view.h deleted file mode 100644 index 37e4af3..0000000 --- a/ash/wm/panels/panel_frame_view.h +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_PANELS_PANEL_FRAME_VIEW_H_ -#define ASH_WM_PANELS_PANEL_FRAME_VIEW_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "base/macros.h" -#include "ui/views/window/non_client_view.h" - -namespace views { -class ImageView; -} - -namespace ash { -class DefaultHeaderPainter; -class FrameCaptionButtonContainerView; - -class ASH_EXPORT PanelFrameView : public views::NonClientFrameView, - public ShellObserver { - public: - // Internal class name. - static const char kViewClassName[]; - - enum FrameType { FRAME_NONE, FRAME_ASH }; - - PanelFrameView(views::Widget* frame, FrameType frame_type); - ~PanelFrameView() override; - - // Sets the active and inactive frame colors. Note the inactive frame color - // will have some transparency added when the frame is drawn. - void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); - - // views::View: - const char* GetClassName() const override; - - private: - void InitHeaderPainter(); - - WmWindow* GetWidgetWindow(); - - // Height from top of window to top of client area. - int NonClientTopBorderHeight() const; - - // views::NonClientFrameView: - gfx::Rect GetBoundsForClientView() const override; - gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const override; - int NonClientHitTest(const gfx::Point& point) override; - void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override; - void ResetWindowControls() override; - void UpdateWindowIcon() override; - void UpdateWindowTitle() override; - void SizeConstraintsChanged() override; - - // views::View: - gfx::Size GetMinimumSize() const override; - void Layout() override; - void OnPaint(gfx::Canvas* canvas) override; - - // ShellObserver: - void OnOverviewModeStarting() override; - void OnOverviewModeEnded() override; - - // Child View class describing the panel's title bar behavior - // and buttons, owned by the view hierarchy - views::Widget* frame_; - FrameCaptionButtonContainerView* caption_button_container_; - views::ImageView* window_icon_; - gfx::Rect client_view_bounds_; - - // Helper class for painting the header. - std::unique_ptr<DefaultHeaderPainter> header_painter_; - - DISALLOW_COPY_AND_ASSIGN(PanelFrameView); -}; -} - -#endif // ASH_WM_PANELS_PANEL_FRAME_VIEW_H_
diff --git a/ash/wm/panels/panel_layout_manager.cc b/ash/wm/panels/panel_layout_manager.cc deleted file mode 100644 index 0ab5e965..0000000 --- a/ash/wm/panels/panel_layout_manager.cc +++ /dev/null
@@ -1,929 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/panels/panel_layout_manager.h" - -#include <algorithm> -#include <map> -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shelf/wm_shelf_util.h" -#include "ash/wm/overview/window_selector_controller.h" -#include "ash/wm/window_animation_types.h" -#include "ash/wm/window_parenting_utils.h" -#include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" -#include "base/auto_reset.h" -#include "third_party/skia/include/core/SkColor.h" -#include "third_party/skia/include/core/SkPath.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/views/background.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -const int kPanelIdealSpacing = 4; - -const float kMaxHeightFactor = .80f; -const float kMaxWidthFactor = .50f; - -// Duration for panel animations. -const int kPanelSlideDurationMilliseconds = 50; -const int kCalloutFadeDurationMilliseconds = 50; - -// Offset used when sliding panel in/out of the shelf. Used for minimizing, -// restoring and the initial showing of a panel. -const int kPanelSlideInOffset = 20; - -// Callout arrow dimensions. -const int kArrowWidth = 18; -const int kArrowHeight = 9; - -class CalloutWidgetBackground : public views::Background { - public: - CalloutWidgetBackground() : alignment_(SHELF_ALIGNMENT_BOTTOM) {} - - void Paint(gfx::Canvas* canvas, views::View* view) const override { - SkPath path; - switch (alignment_) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - path.moveTo(SkIntToScalar(0), SkIntToScalar(0)); - path.lineTo(SkIntToScalar(kArrowWidth / 2), - SkIntToScalar(kArrowHeight)); - path.lineTo(SkIntToScalar(kArrowWidth), SkIntToScalar(0)); - break; - case SHELF_ALIGNMENT_LEFT: - path.moveTo(SkIntToScalar(kArrowHeight), SkIntToScalar(kArrowWidth)); - path.lineTo(SkIntToScalar(0), SkIntToScalar(kArrowWidth / 2)); - path.lineTo(SkIntToScalar(kArrowHeight), SkIntToScalar(0)); - break; - case SHELF_ALIGNMENT_RIGHT: - path.moveTo(SkIntToScalar(0), SkIntToScalar(0)); - path.lineTo(SkIntToScalar(kArrowHeight), - SkIntToScalar(kArrowWidth / 2)); - path.lineTo(SkIntToScalar(0), SkIntToScalar(kArrowWidth)); - break; - } - // Hard code the arrow color for now. - cc::PaintFlags flags; - flags.setStyle(cc::PaintFlags::kFill_Style); - flags.setColor(SkColorSetARGB(0xff, 0xe5, 0xe5, 0xe5)); - canvas->DrawPath(path, flags); - } - - ShelfAlignment alignment() { return alignment_; } - - void set_alignment(ShelfAlignment alignment) { alignment_ = alignment; } - - private: - ShelfAlignment alignment_; - - DISALLOW_COPY_AND_ASSIGN(CalloutWidgetBackground); -}; - -struct VisiblePanelPositionInfo { - VisiblePanelPositionInfo() - : min_major(0), - max_major(0), - major_pos(0), - major_length(0), - window(NULL), - slide_in(false) {} - - int min_major; - int max_major; - int major_pos; - int major_length; - WmWindow* window; - bool slide_in; -}; - -bool CompareWindowMajor(const VisiblePanelPositionInfo& win1, - const VisiblePanelPositionInfo& win2) { - return win1.major_pos < win2.major_pos; -} - -void FanOutPanels(std::vector<VisiblePanelPositionInfo>::iterator first, - std::vector<VisiblePanelPositionInfo>::iterator last) { - int num_panels = last - first; - if (num_panels == 1) { - (*first).major_pos = std::max( - (*first).min_major, std::min((*first).max_major, (*first).major_pos)); - } - if (num_panels <= 1) - return; - - if (num_panels == 2) { - // If there are two adjacent overlapping windows, separate them by the - // minimum major_length necessary. - std::vector<VisiblePanelPositionInfo>::iterator second = first + 1; - int separation = (*first).major_length / 2 + (*second).major_length / 2 + - kPanelIdealSpacing; - int overlap = (*first).major_pos + separation - (*second).major_pos; - (*first).major_pos = - std::max((*first).min_major, (*first).major_pos - overlap / 2); - (*second).major_pos = - std::min((*second).max_major, (*first).major_pos + separation); - // Recalculate the first panel position in case the second one was - // constrained on the right. - (*first).major_pos = - std::max((*first).min_major, (*second).major_pos - separation); - return; - } - - // If there are more than two overlapping windows, fan them out from minimum - // position to maximum position equally spaced. - int delta = ((*(last - 1)).max_major - (*first).min_major) / (num_panels - 1); - int major_pos = (*first).min_major; - for (std::vector<VisiblePanelPositionInfo>::iterator iter = first; - iter != last; ++iter) { - (*iter).major_pos = - std::max((*iter).min_major, std::min((*iter).max_major, major_pos)); - major_pos += delta; - } -} - -bool BoundsAdjacent(const gfx::Rect& bounds1, const gfx::Rect& bounds2) { - return bounds1.x() == bounds2.right() || bounds1.y() == bounds2.bottom() || - bounds1.right() == bounds2.x() || bounds1.bottom() == bounds2.y(); -} - -gfx::Vector2d GetSlideInAnimationOffset(ShelfAlignment alignment) { - gfx::Vector2d offset; - if (alignment == SHELF_ALIGNMENT_LEFT) - offset.set_x(-kPanelSlideInOffset); - else if (alignment == SHELF_ALIGNMENT_RIGHT) - offset.set_x(kPanelSlideInOffset); - else - offset.set_y(kPanelSlideInOffset); - return offset; -} - -} // namespace - -class PanelCalloutWidget : public views::Widget { - public: - explicit PanelCalloutWidget(WmWindow* container) : background_(nullptr) { - InitWidget(container); - } - - void SetAlignment(ShelfAlignment alignment) { - WmWindow* window = WmWindow::Get(this->GetNativeWindow()); - gfx::Rect callout_bounds = window->GetBounds(); - if (IsHorizontalAlignment(alignment)) { - callout_bounds.set_width(kArrowWidth); - callout_bounds.set_height(kArrowHeight); - } else { - callout_bounds.set_width(kArrowHeight); - callout_bounds.set_height(kArrowWidth); - } - WmWindow* parent = window->GetParent(); - // It's important this go through WmWindow and not Widget. Going through - // Widget means it may move do a different screen, we don't want that. - window->SetBounds(callout_bounds); - // Setting the bounds should not trigger changing the parent. - DCHECK_EQ(parent, window->GetParent()); - if (background_->alignment() != alignment) { - background_->set_alignment(alignment); - SchedulePaintInRect(gfx::Rect(callout_bounds.size())); - } - } - - private: - void InitWidget(WmWindow* parent) { - views::Widget::InitParams params; - params.type = views::Widget::InitParams::TYPE_POPUP; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.keep_on_top = true; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = parent->ConvertRectToScreen(gfx::Rect()); - params.bounds.set_width(kArrowWidth); - params.bounds.set_height(kArrowHeight); - params.accept_events = false; - parent->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - this, parent->GetShellWindowId(), ¶ms); - set_focus_on_creation(false); - Init(params); - WmWindow* widget_window = WmWindow::Get(this->GetNativeWindow()); - DCHECK_EQ(widget_window->GetRootWindow(), parent->GetRootWindow()); - views::View* content_view = new views::View; - background_ = new CalloutWidgetBackground; - content_view->set_background(background_); - SetContentsView(content_view); - widget_window->GetLayer()->SetOpacity(0); - } - - // Weak pointer owned by this widget's content view. - CalloutWidgetBackground* background_; - - DISALLOW_COPY_AND_ASSIGN(PanelCalloutWidget); -}; - -views::Widget* PanelLayoutManager::PanelInfo::CalloutWidget() { - return callout_widget; -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager public implementation: -PanelLayoutManager::PanelLayoutManager(WmWindow* panel_container) - : panel_container_(panel_container), - root_window_controller_(panel_container->GetRootWindowController()), - in_add_window_(false), - in_layout_(false), - show_callout_widgets_(true), - dragged_panel_(NULL), - shelf_(nullptr), - last_active_panel_(NULL), - weak_factory_(this) { - DCHECK(panel_container); - WmShell* shell = panel_container->GetShell(); - shell->AddActivationObserver(this); - shell->AddDisplayObserver(this); - shell->AddShellObserver(this); -} - -PanelLayoutManager::~PanelLayoutManager() { - Shutdown(); -} - -// static -PanelLayoutManager* PanelLayoutManager::Get(WmWindow* window) { - if (!window) - return nullptr; - - return static_cast<PanelLayoutManager*>( - window->GetRootWindow() - ->GetChildByShellWindowId(kShellWindowId_PanelContainer) - ->GetLayoutManager()); -} - -void PanelLayoutManager::Shutdown() { - if (shelf_) { - shelf_->RemoveObserver(this); - shelf_ = nullptr; - } - for (PanelList::iterator iter = panel_windows_.begin(); - iter != panel_windows_.end(); ++iter) { - delete iter->callout_widget; - } - panel_windows_.clear(); - WmShell* shell = panel_container_->GetShell(); - shell->RemoveActivationObserver(this); - shell->RemoveDisplayObserver(this); - shell->RemoveShellObserver(this); -} - -void PanelLayoutManager::StartDragging(WmWindow* panel) { - DCHECK(!dragged_panel_); - dragged_panel_ = panel; - Relayout(); -} - -void PanelLayoutManager::FinishDragging() { - dragged_panel_ = NULL; - Relayout(); -} - -void PanelLayoutManager::SetShelf(WmShelf* shelf) { - DCHECK(!shelf_); - shelf_ = shelf; - shelf_->AddObserver(this); - WillChangeVisibilityState(shelf_->GetVisibilityState()); -} - -void PanelLayoutManager::ToggleMinimize(WmWindow* panel) { - DCHECK(panel->GetParent() == panel_container_); - wm::WindowState* window_state = panel->GetWindowState(); - if (window_state->IsMinimized()) - window_state->Restore(); - else - window_state->Minimize(); -} - -void PanelLayoutManager::SetShowCalloutWidgets(bool show) { - if (show_callout_widgets_ == show) - return; - show_callout_widgets_ = show; - UpdateCallouts(); -} - -views::Widget* PanelLayoutManager::GetCalloutWidgetForPanel(WmWindow* panel) { - DCHECK(panel->GetParent() == panel_container_); - PanelList::iterator found = - std::find(panel_windows_.begin(), panel_windows_.end(), panel); - DCHECK(found != panel_windows_.end()); - return found->callout_widget; -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, WmLayoutManager implementation: -void PanelLayoutManager::OnWindowResized() { - Relayout(); -} - -void PanelLayoutManager::OnWindowAddedToLayout(WmWindow* child) { - if (child->GetType() == ui::wm::WINDOW_TYPE_POPUP) - return; - if (in_add_window_) - return; - base::AutoReset<bool> auto_reset_in_add_window(&in_add_window_, true); - if (!child->aura_window()->GetProperty(kPanelAttachedKey)) { - // This should only happen when a window is added to panel container as a - // result of bounds change from within the application during a drag. - // If so we have already stopped the drag and should reparent the panel - // back to appropriate container and ignore it. - // TODO(varkha): Updating bounds during a drag can cause problems and a more - // general solution is needed. See http://crbug.com/251813 . - WmWindow* old_parent = child->GetParent(); - child->SetParentUsingContext(child, - child->GetRootWindow()->GetBoundsInScreen()); - wm::ReparentTransientChildrenOfChild(child, old_parent, child->GetParent()); - DCHECK(child->GetParent()->GetShellWindowId() != - kShellWindowId_PanelContainer); - return; - } - PanelInfo panel_info; - panel_info.window = child; - panel_info.callout_widget = new PanelCalloutWidget(panel_container_); - panel_info.slide_in = child != dragged_panel_; - panel_windows_.push_back(panel_info); - child->aura_window()->AddObserver(this); - child->GetWindowState()->AddObserver(this); - Relayout(); -} - -void PanelLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) {} - -void PanelLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) { - if (child->GetType() == ui::wm::WINDOW_TYPE_POPUP) - return; - - PanelList::iterator found = - std::find(panel_windows_.begin(), panel_windows_.end(), child); - if (found != panel_windows_.end()) { - delete found->callout_widget; - panel_windows_.erase(found); - } - if (restore_windows_on_shelf_visible_) - restore_windows_on_shelf_visible_->Remove(child->aura_window()); - child->aura_window()->RemoveObserver(this); - child->GetWindowState()->RemoveObserver(this); - - if (dragged_panel_ == child) - dragged_panel_ = NULL; - - if (last_active_panel_ == child) - last_active_panel_ = NULL; - - Relayout(); -} - -void PanelLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) { - if (visible) - child->GetWindowState()->Restore(); - Relayout(); -} - -void PanelLayoutManager::SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) { - gfx::Rect bounds(requested_bounds); - const gfx::Rect& max_bounds = panel_container_->GetRootWindow()->GetBounds(); - const int max_width = max_bounds.width() * kMaxWidthFactor; - const int max_height = max_bounds.height() * kMaxHeightFactor; - if (bounds.width() > max_width) - bounds.set_width(max_width); - if (bounds.height() > max_height) - bounds.set_height(max_height); - - // Reposition dragged panel in the panel order. - if (dragged_panel_ == child) { - PanelList::iterator dragged_panel_iter = - std::find(panel_windows_.begin(), panel_windows_.end(), dragged_panel_); - DCHECK(dragged_panel_iter != panel_windows_.end()); - PanelList::iterator new_position; - for (new_position = panel_windows_.begin(); - new_position != panel_windows_.end(); ++new_position) { - const gfx::Rect& bounds = (*new_position).window->GetBounds(); - if (bounds.x() + bounds.width() / 2 <= requested_bounds.x()) - break; - } - if (new_position != dragged_panel_iter) { - PanelInfo dragged_panel_info = *dragged_panel_iter; - panel_windows_.erase(dragged_panel_iter); - panel_windows_.insert(new_position, dragged_panel_info); - } - } - // Respect the minimum size of the window. - if (child->HasNonClientArea()) { - const gfx::Size min_size = child->GetMinimumSize(); - bounds.set_width(std::max(min_size.width(), bounds.width())); - bounds.set_height(std::max(min_size.height(), bounds.height())); - } - - child->SetBoundsDirect(bounds); - Relayout(); -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, ShellObserver implementation: - -void PanelLayoutManager::OnOverviewModeEnded() { - Relayout(); -} - -void PanelLayoutManager::OnShelfAlignmentChanged(WmWindow* root_window) { - if (root_window_controller_->GetWindow() == root_window) - Relayout(); -} - -///////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, WindowObserver implementation: - -void PanelLayoutManager::OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) { - // Trigger a relayout to position the panels whenever the panel icon is set - // or changes. - if (key == kShelfIDKey) - Relayout(); -} - -///////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, WindowStateObserver implementation: - -void PanelLayoutManager::OnPostWindowStateTypeChange( - wm::WindowState* window_state, - wm::WindowStateType old_type) { - // If the shelf is currently hidden then windows will not actually be shown - // but the set to restore when the shelf becomes visible is updated. - if (restore_windows_on_shelf_visible_) { - if (window_state->IsMinimized()) { - MinimizePanel(window_state->window()); - restore_windows_on_shelf_visible_->Remove( - window_state->window()->aura_window()); - } else { - restore_windows_on_shelf_visible_->Add( - window_state->window()->aura_window()); - } - return; - } - - if (window_state->IsMinimized()) - MinimizePanel(window_state->window()); - else - RestorePanel(window_state->window()); -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, WmActivationObserver implementation: - -void PanelLayoutManager::OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) { - // Ignore if the panel that is not managed by this was activated. - if (gained_active && gained_active->GetType() == ui::wm::WINDOW_TYPE_PANEL && - gained_active->GetParent() == panel_container_) { - UpdateStacking(gained_active); - UpdateCallouts(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, WmDisplayObserver::Observer implementation: - -void PanelLayoutManager::OnDisplayConfigurationChanged() { - Relayout(); -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager, ShelfLayoutManagerObserver implementation: - -void PanelLayoutManager::WillChangeVisibilityState( - ShelfVisibilityState new_state) { - // On entering / leaving full screen mode the shelf visibility state is - // changed to / from SHELF_HIDDEN. In this state, panel windows should hide - // to allow the full-screen application to use the full screen. - bool shelf_hidden = new_state == ash::SHELF_HIDDEN; - if (!shelf_hidden) { - if (restore_windows_on_shelf_visible_) { - std::unique_ptr<aura::WindowTracker> restore_windows( - std::move(restore_windows_on_shelf_visible_)); - for (aura::Window* window : restore_windows->windows()) - RestorePanel(WmWindow::Get(window)); - } - return; - } - - if (restore_windows_on_shelf_visible_) - return; - std::unique_ptr<aura::WindowTracker> minimized_windows( - new aura::WindowTracker); - for (PanelList::iterator iter = panel_windows_.begin(); - iter != panel_windows_.end();) { - WmWindow* window = iter->window; - // Minimizing a panel window may remove it from the panel_windows_ list. - // Advance the iterator before minimizing it: http://crbug.com/393047. - ++iter; - if (window != dragged_panel_ && window->IsVisible()) { - minimized_windows->Add(window->aura_window()); - window->GetWindowState()->Minimize(); - } - } - restore_windows_on_shelf_visible_ = std::move(minimized_windows); -} - -void PanelLayoutManager::OnShelfIconPositionsChanged() { - // TODO: As this is called for every animation step now. Relayout needs to be - // updated to use current icon position instead of use the ideal bounds so - // that the panels slide with their icons instead of jumping. - Relayout(); -} - -//////////////////////////////////////////////////////////////////////////////// -// PanelLayoutManager private implementation: - -void PanelLayoutManager::MinimizePanel(WmWindow* panel) { - // Clusterfuzz can trigger panel accelerators before the shelf is created. - // TODO(jamescook): Revert this after http://crbug.com/648964 is fixed. - if (!shelf_) - return; - - panel->SetVisibilityAnimationType( - wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE); - ui::Layer* layer = panel->GetLayer(); - ui::ScopedLayerAnimationSettings panel_slide_settings(layer->GetAnimator()); - panel_slide_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - panel_slide_settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kPanelSlideDurationMilliseconds)); - gfx::Rect bounds(panel->GetBounds()); - bounds.Offset(GetSlideInAnimationOffset(shelf_->GetAlignment())); - panel->SetBoundsDirect(bounds); - panel->Hide(); - layer->SetOpacity(0); - if (panel->IsActive()) - panel->Deactivate(); - Relayout(); -} - -void PanelLayoutManager::RestorePanel(WmWindow* panel) { - PanelList::iterator found = - std::find(panel_windows_.begin(), panel_windows_.end(), panel); - DCHECK(found != panel_windows_.end()); - found->slide_in = true; - Relayout(); -} - -void PanelLayoutManager::Relayout() { - if (!shelf_ || !shelf_->GetWindow()) - return; - - // Suppress layouts during overview mode because changing window bounds - // interfered with overview mode animations. However, layouts need to be done - // when the WindowSelectorController is restoring minimized windows so that - // they actually become visible. - WindowSelectorController* window_selector_controller = - WmShell::Get()->window_selector_controller(); - if (in_layout_ || - (window_selector_controller->IsSelecting() && - !window_selector_controller->IsRestoringMinimizedWindows())) { - return; - } - - base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true); - - const ShelfAlignment alignment = shelf_->GetAlignment(); - const bool horizontal = shelf_->IsHorizontalAlignment(); - gfx::Rect shelf_bounds = panel_container_->ConvertRectFromScreen( - shelf_->GetWindow()->GetBoundsInScreen()); - int panel_start_bounds = kPanelIdealSpacing; - int panel_end_bounds = - horizontal ? panel_container_->GetBounds().width() - kPanelIdealSpacing - : panel_container_->GetBounds().height() - kPanelIdealSpacing; - WmWindow* active_panel = nullptr; - std::vector<VisiblePanelPositionInfo> visible_panels; - for (PanelList::iterator iter = panel_windows_.begin(); - iter != panel_windows_.end(); ++iter) { - WmWindow* panel = iter->window; - iter->callout_widget->SetAlignment(alignment); - - // Consider the dragged panel as part of the layout as long as it is - // touching the shelf. - if ((!panel->IsVisible() && !iter->slide_in) || - (panel == dragged_panel_ && - !BoundsAdjacent(panel->GetBounds(), shelf_bounds))) { - continue; - } - - // If the shelf is currently hidden (full-screen mode), minimize panel until - // full-screen mode is exited. When a panel is dragged from another display - // the shelf state does not update before the panel is added so we exclude - // the dragged panel. - if (panel != dragged_panel_ && restore_windows_on_shelf_visible_) { - panel->GetWindowState()->Minimize(); - restore_windows_on_shelf_visible_->Add(panel->aura_window()); - continue; - } - - gfx::Rect icon_bounds = shelf_->GetScreenBoundsOfItemIconForWindow(panel); - - // If both the icon width and height are 0 then there is no icon in the - // shelf. If the shelf is hidden, one of the height or width will be - // 0 but the position in the shelf and major dimension is still reported - // correctly and the panel can be aligned above where the hidden icon is. - if (icon_bounds.width() == 0 && icon_bounds.height() == 0) - continue; - - if (panel->IsFocused() || - panel->Contains(panel->GetShell()->GetFocusedWindow())) { - DCHECK(!active_panel); - active_panel = panel; - } - icon_bounds = panel_container_->ConvertRectFromScreen(icon_bounds); - gfx::Point icon_origin = icon_bounds.origin(); - VisiblePanelPositionInfo position_info; - int icon_start = horizontal ? icon_origin.x() : icon_origin.y(); - int icon_end = - icon_start + (horizontal ? icon_bounds.width() : icon_bounds.height()); - position_info.major_length = - horizontal ? panel->GetBounds().width() : panel->GetBounds().height(); - position_info.min_major = - std::max(panel_start_bounds + position_info.major_length / 2, - icon_end - position_info.major_length / 2); - position_info.max_major = - std::min(icon_start + position_info.major_length / 2, - panel_end_bounds - position_info.major_length / 2); - position_info.major_pos = (icon_start + icon_end) / 2; - position_info.window = panel; - position_info.slide_in = iter->slide_in; - iter->slide_in = false; - visible_panels.push_back(position_info); - } - - // Sort panels by their X positions and fan out groups of overlapping panels. - // The fan out method may result in new overlapping panels however given that - // the panels start at least a full panel width apart this overlap will - // never completely obscure a panel. - // TODO(flackr): Rearrange panels if new overlaps are introduced. - std::sort(visible_panels.begin(), visible_panels.end(), CompareWindowMajor); - size_t first_overlapping_panel = 0; - for (size_t i = 1; i < visible_panels.size(); ++i) { - if (visible_panels[i - 1].major_pos + - visible_panels[i - 1].major_length / 2 < - visible_panels[i].major_pos - visible_panels[i].major_length / 2) { - FanOutPanels(visible_panels.begin() + first_overlapping_panel, - visible_panels.begin() + i); - first_overlapping_panel = i; - } - } - FanOutPanels(visible_panels.begin() + first_overlapping_panel, - visible_panels.end()); - - for (size_t i = 0; i < visible_panels.size(); ++i) { - if (visible_panels[i].window == dragged_panel_) - continue; - bool slide_in = visible_panels[i].slide_in; - gfx::Rect bounds = visible_panels[i].window->GetTargetBounds(); - if (alignment == SHELF_ALIGNMENT_LEFT) - bounds.set_x(shelf_bounds.right()); - else if (alignment == SHELF_ALIGNMENT_RIGHT) - bounds.set_x(shelf_bounds.x() - bounds.width()); - else - bounds.set_y(shelf_bounds.y() - bounds.height()); - bool on_shelf = visible_panels[i].window->GetTargetBounds() == bounds; - - if (horizontal) { - bounds.set_x(visible_panels[i].major_pos - - visible_panels[i].major_length / 2); - } else { - bounds.set_y(visible_panels[i].major_pos - - visible_panels[i].major_length / 2); - } - - ui::Layer* layer = visible_panels[i].window->GetLayer(); - if (slide_in) { - // New windows shift up from the shelf into position and fade in. - layer->SetOpacity(0); - gfx::Rect initial_bounds(bounds); - initial_bounds.Offset(GetSlideInAnimationOffset(alignment)); - visible_panels[i].window->SetBoundsDirect(initial_bounds); - // Set on shelf so that the panel animates into its target position. - on_shelf = true; - } - - if (on_shelf) { - ui::ScopedLayerAnimationSettings panel_slide_settings( - layer->GetAnimator()); - panel_slide_settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - panel_slide_settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kPanelSlideDurationMilliseconds)); - visible_panels[i].window->SetBoundsDirect(bounds); - if (slide_in) { - layer->SetOpacity(1); - visible_panels[i].window->Show(); - } - } else { - // If the shelf moved don't animate, move immediately to the new - // target location. - visible_panels[i].window->SetBoundsDirect(bounds); - } - } - - UpdateStacking(active_panel); - UpdateCallouts(); -} - -void PanelLayoutManager::UpdateStacking(WmWindow* active_panel) { - // Clusterfuzz can trigger panel accelerators before the shelf is created. - // TODO(jamescook): Revert this after http://crbug.com/648964 is fixed. - if (!shelf_) - return; - - if (!active_panel) { - if (!last_active_panel_) - return; - active_panel = last_active_panel_; - } - - // We want to to stack the panels like a deck of cards: - // ,--,--,--,-------.--.--. - // | | | | | | | - // | | | | | | | - // - // We use the middle of each panel to figure out how to stack the panels. This - // allows us to update the stacking when a panel is being dragged around by - // the titlebar--even though it doesn't update the shelf icon positions, we - // still want the visual effect. - std::map<int, WmWindow*> window_ordering; - const bool horizontal = shelf_->IsHorizontalAlignment(); - for (PanelList::const_iterator it = panel_windows_.begin(); - it != panel_windows_.end(); ++it) { - gfx::Rect bounds = it->window->GetBounds(); - window_ordering.insert( - std::make_pair(horizontal ? bounds.x() + bounds.width() / 2 - : bounds.y() + bounds.height() / 2, - it->window)); - } - - WmWindow* previous_panel = nullptr; - for (std::map<int, WmWindow*>::const_iterator it = window_ordering.begin(); - it != window_ordering.end() && it->second != active_panel; ++it) { - if (previous_panel) - panel_container_->StackChildAbove(it->second, previous_panel); - previous_panel = it->second; - } - - previous_panel = NULL; - for (std::map<int, WmWindow*>::const_reverse_iterator it = - window_ordering.rbegin(); - it != window_ordering.rend() && it->second != active_panel; ++it) { - if (previous_panel) - panel_container_->StackChildAbove(it->second, previous_panel); - previous_panel = it->second; - } - - panel_container_->StackChildAtTop(active_panel); - if (dragged_panel_ && dragged_panel_->GetParent() == panel_container_) - panel_container_->StackChildAtTop(dragged_panel_); - last_active_panel_ = active_panel; -} - -void PanelLayoutManager::UpdateCallouts() { - // Clusterfuzz can trigger panel accelerators before the shelf is created. - // TODO(jamescook): Revert this after http://crbug.com/648964 is fixed. - if (!shelf_) - return; - - const bool horizontal = shelf_->IsHorizontalAlignment(); - for (PanelList::iterator iter = panel_windows_.begin(); - iter != panel_windows_.end(); ++iter) { - WmWindow* panel = iter->window; - views::Widget* callout_widget = iter->callout_widget; - WmWindow* callout_widget_window = - WmWindow::Get(callout_widget->GetNativeWindow()); - - gfx::Rect current_bounds = panel->GetBoundsInScreen(); - gfx::Rect bounds = - panel->GetParent()->ConvertRectToScreen(panel->GetTargetBounds()); - gfx::Rect icon_bounds = shelf_->GetScreenBoundsOfItemIconForWindow(panel); - if (icon_bounds.IsEmpty() || !panel->GetLayer()->GetTargetVisibility() || - panel == dragged_panel_ || !show_callout_widgets_) { - callout_widget->Hide(); - callout_widget_window->GetLayer()->SetOpacity(0); - continue; - } - - gfx::Rect callout_bounds = callout_widget->GetWindowBoundsInScreen(); - gfx::Vector2d slide_vector = bounds.origin() - current_bounds.origin(); - int slide_distance = horizontal ? slide_vector.x() : slide_vector.y(); - int distance_until_over_panel = 0; - if (horizontal) { - callout_bounds.set_x(icon_bounds.x() + - (icon_bounds.width() - callout_bounds.width()) / 2); - distance_until_over_panel = - std::max(current_bounds.x() - callout_bounds.x(), - callout_bounds.right() - current_bounds.right()); - } else { - callout_bounds.set_y(icon_bounds.y() + - (icon_bounds.height() - callout_bounds.height()) / - 2); - distance_until_over_panel = - std::max(current_bounds.y() - callout_bounds.y(), - callout_bounds.bottom() - current_bounds.bottom()); - } - if (shelf_->GetAlignment() == SHELF_ALIGNMENT_LEFT) - callout_bounds.set_x(bounds.x() - callout_bounds.width()); - else if (shelf_->GetAlignment() == SHELF_ALIGNMENT_RIGHT) - callout_bounds.set_x(bounds.right()); - else - callout_bounds.set_y(bounds.bottom()); - callout_bounds = callout_widget_window->GetParent()->ConvertRectFromScreen( - callout_bounds); - - callout_widget_window->SetBoundsDirect(callout_bounds); - DCHECK_EQ(panel_container_, callout_widget_window->GetParent()); - DCHECK_EQ(panel_container_, panel->GetParent()); - panel_container_->StackChildAbove(callout_widget_window, panel); - - ui::Layer* layer = callout_widget_window->GetLayer(); - // If the panel is not over the callout position or has just become visible - // then fade in the callout. - if ((distance_until_over_panel > 0 || layer->GetTargetOpacity() < 1)) { - if (distance_until_over_panel > 0 && - slide_distance >= distance_until_over_panel) { - // If the panel is not yet over the callout, then delay fading in - // the callout until after the panel should be over it. - int delay = kPanelSlideDurationMilliseconds * - distance_until_over_panel / slide_distance; - layer->SetOpacity(0); - layer->GetAnimator()->StopAnimating(); - layer->GetAnimator()->SchedulePauseForProperties( - base::TimeDelta::FromMilliseconds(delay), - ui::LayerAnimationElement::OPACITY); - } - ui::ScopedLayerAnimationSettings callout_settings(layer->GetAnimator()); - callout_settings.SetPreemptionStrategy( - ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); - callout_settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kCalloutFadeDurationMilliseconds)); - layer->SetOpacity(1); - } - - // Show after changing the opacity animation. This way we don't have a - // state where the widget is visible but the opacity is 0. - callout_widget->Show(); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// keyboard::KeyboardControllerObserver implementation: - -void PanelLayoutManager::OnKeyboardBoundsChanging( - const gfx::Rect& keyboard_bounds) { - gfx::Rect parent_bounds = panel_container_->GetBounds(); - int available_space = parent_bounds.height() - keyboard_bounds.height(); - for (PanelList::iterator iter = panel_windows_.begin(); - iter != panel_windows_.end(); ++iter) { - WmWindow* panel = iter->window; - wm::WindowState* panel_state = panel->GetWindowState(); - if (keyboard_bounds.height() > 0) { - // Save existing bounds, so that we can restore them when the keyboard - // hides. - panel_state->SaveCurrentBoundsForRestore(); - - gfx::Rect panel_bounds = - panel->GetParent()->ConvertRectToScreen(panel->GetTargetBounds()); - int delta = panel_bounds.height() - available_space; - // Ensure panels are not pushed above the parent boundaries, shrink any - // panels that violate this constraint. - if (delta > 0) { - panel->SetBoundsDirect( - gfx::Rect(panel_bounds.x(), panel_bounds.y() + delta, - panel_bounds.width(), panel_bounds.height() - delta)); - } - } else if (panel_state->HasRestoreBounds()) { - // Keyboard hidden, restore original bounds if they exist. - panel->SetBoundsDirect(panel_state->GetRestoreBoundsInScreen()); - } - } - // This bounds change will have caused a change to the Shelf which does not - // propogate automatically to this class, so manually recalculate bounds. - OnWindowResized(); -} - -void PanelLayoutManager::OnKeyboardClosed() {} - -} // namespace ash
diff --git a/ash/wm/panels/panel_layout_manager.h b/ash/wm/panels/panel_layout_manager.h deleted file mode 100644 index 7a435bb..0000000 --- a/ash/wm/panels/panel_layout_manager.h +++ /dev/null
@@ -1,205 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_PANELS_PANEL_LAYOUT_MANAGER_H_ -#define ASH_WM_PANELS_PANEL_LAYOUT_MANAGER_H_ - -#include <list> -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_activation_observer.h" -#include "ash/common/wm_display_observer.h" -#include "ash/common/wm_layout_manager.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf_observer.h" -#include "ash/wm/window_state_observer.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "ui/aura/window_observer.h" -#include "ui/aura/window_tracker.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace gfx { -class Rect; -} - -namespace views { -class Widget; -} - -namespace ash { -class PanelCalloutWidget; -class WmShelf; - -namespace wm { -class RootWindowController; -} - -// PanelLayoutManager is responsible for organizing panels within the -// workspace. It is associated with a specific container window (i.e. -// kShellWindowId_PanelContainer) and controls the layout of any windows -// added to that container. -// -// The constructor takes a |panel_container| argument which is expected to set -// its layout manager to this instance, e.g.: -// panel_container->SetLayoutManager(new PanelLayoutManager(panel_container)); - -class ASH_EXPORT PanelLayoutManager - : public WmLayoutManager, - public wm::WindowStateObserver, - public WmActivationObserver, - public WmDisplayObserver, - public ShellObserver, - public aura::WindowObserver, - public keyboard::KeyboardControllerObserver, - public WmShelfObserver { - public: - explicit PanelLayoutManager(WmWindow* panel_container); - ~PanelLayoutManager() override; - - // Returns the PanelLayoutManager in the specified hierarchy. This searches - // from the root of |window|. - static PanelLayoutManager* Get(WmWindow* window); - - // Call Shutdown() before deleting children of panel_container. - void Shutdown(); - - void StartDragging(WmWindow* panel); - void FinishDragging(); - - void ToggleMinimize(WmWindow* panel); - - // Hide / Show the panel callout widgets. - void SetShowCalloutWidgets(bool show); - - // Returns the callout widget (arrow) for |panel|. - views::Widget* GetCalloutWidgetForPanel(WmWindow* panel); - - WmShelf* shelf() { return shelf_; } - void SetShelf(WmShelf* shelf); - - // Overridden from WmLayoutManager - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override; - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - // Overridden from ShellObserver: - void OnOverviewModeEnded() override; - void OnShelfAlignmentChanged(WmWindow* root_window) override; - - // Overridden from aura::WindowObserver - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; - - // Overridden from wm::WindowStateObserver - void OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) override; - - // Overridden from WmActivationObserver - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override; - - // Overridden from WindowTreeHostManager::Observer - void OnDisplayConfigurationChanged() override; - - // Overridden from WmShelfObserver - void WillChangeVisibilityState(ShelfVisibilityState new_state) override; - void OnShelfIconPositionsChanged() override; - - private: - friend class PanelLayoutManagerTest; - friend class PanelWindowResizerTest; - friend class DockedWindowResizerTest; - friend class DockedWindowLayoutManagerTest; - friend class WorkspaceControllerTest; - friend class AcceleratorControllerTest; - - views::Widget* CreateCalloutWidget(); - - struct ASH_EXPORT PanelInfo { - PanelInfo() : window(NULL), callout_widget(NULL), slide_in(false) {} - - bool operator==(const WmWindow* other_window) const { - return window == other_window; - } - - // Returns |callout_widget| as a widget. Used by tests. - views::Widget* CalloutWidget(); - - // A weak pointer to the panel window. - WmWindow* window; - - // The callout widget for this panel. This pointer must be managed - // manually as this structure is used in a std::list. See - // http://www.chromium.org/developers/smart-pointer-guidelines - PanelCalloutWidget* callout_widget; - - // True on new and restored panel windows until the panel has been - // positioned. The first time Relayout is called the panel will be shown, - // and slide into position and this will be set to false. - bool slide_in; - }; - - typedef std::list<PanelInfo> PanelList; - - void MinimizePanel(WmWindow* panel); - void RestorePanel(WmWindow* panel); - - // Called whenever the panel layout might change. - void Relayout(); - - // Called whenever the panel stacking order needs to be updated (e.g. focus - // changes or a panel is moved). - void UpdateStacking(WmWindow* active_panel); - - // Update the callout arrows for all managed panels. - void UpdateCallouts(); - - // Overridden from keyboard::KeyboardControllerObserver: - void OnKeyboardBoundsChanging(const gfx::Rect& keyboard_bounds) override; - void OnKeyboardClosed() override; - - // Parent window associated with this layout manager. - WmWindow* panel_container_; - - RootWindowController* root_window_controller_; - - // Protect against recursive calls to OnWindowAddedToLayout(). - bool in_add_window_; - // Protect against recursive calls to Relayout(). - bool in_layout_; - // Indicates if the panel callout widget should be created. - bool show_callout_widgets_; - // Ordered list of unowned pointers to panel windows. - PanelList panel_windows_; - // The panel being dragged. - WmWindow* dragged_panel_; - // The shelf we are observing for shelf icon changes. - WmShelf* shelf_; - - // When not NULL, the shelf is hidden (i.e. full screen) and this tracks the - // set of panel windows which have been temporarily hidden and need to be - // restored when the shelf becomes visible again. - std::unique_ptr<aura::WindowTracker> restore_windows_on_shelf_visible_; - - // The last active panel. Used to maintain stacking order even if no panels - // are currently focused. - WmWindow* last_active_panel_; - base::WeakPtrFactory<PanelLayoutManager> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PanelLayoutManager); -}; - -} // namespace ash - -#endif // ASH_WM_PANELS_PANEL_LAYOUT_MANAGER_H_
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc index f5c66c3..3b11ebba 100644 --- a/ash/wm/panels/panel_layout_manager_unittest.cc +++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -2,27 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/shelf/shelf_button.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/web_notification/web_notification_tray.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/web_notification/web_notification_tray.h" #include "ash/test/ash_test_base.h" #include "ash/test/shelf_view_test_api.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/wm/mru_window_tracker.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/command_line.h"
diff --git a/ash/wm/panels/panel_window_event_handler.cc b/ash/wm/panels/panel_window_event_handler.cc index 7736eac..8cb9301 100644 --- a/ash/wm/panels/panel_window_event_handler.cc +++ b/ash/wm/panels/panel_window_event_handler.cc
@@ -4,8 +4,8 @@ #include "ash/wm/panels/panel_window_event_handler.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h"
diff --git a/ash/wm/panels/panel_window_resizer.cc b/ash/wm/panels/panel_window_resizer.cc deleted file mode 100644 index b7a051d8..0000000 --- a/ash/wm/panels/panel_window_resizer.cc +++ /dev/null
@@ -1,207 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/panels/panel_window_resizer.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/public/cpp/window_properties.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/shell.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/window_parenting_utils.h" -#include "ash/wm/window_state.h" -#include "ui/base/hit_test.h" -#include "ui/base/ui_base_types.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" - -namespace ash { - -namespace { - -const int kPanelSnapToLauncherDistance = 30; - -} // namespace - -PanelWindowResizer::~PanelWindowResizer() {} - -// static -PanelWindowResizer* PanelWindowResizer::Create( - WindowResizer* next_window_resizer, - wm::WindowState* window_state) { - return new PanelWindowResizer(next_window_resizer, window_state); -} - -void PanelWindowResizer::Drag(const gfx::Point& location, int event_flags) { - last_location_ = GetTarget()->GetParent()->ConvertPointToScreen(location); - if (!did_move_or_resize_) { - did_move_or_resize_ = true; - StartedDragging(); - } - - // Check if the destination has changed displays. - display::Screen* screen = display::Screen::GetScreen(); - const display::Display dst_display = - screen->GetDisplayNearestPoint(last_location_); - if (dst_display.id() != - panel_container_->GetRootWindow()->GetDisplayNearestWindow().id()) { - // The panel is being dragged to a new display. If the previous container is - // the current parent of the panel it will be informed of the end of drag - // when the panel is reparented, otherwise let the previous container know - // the drag is complete. If we told the panel's parent that the drag was - // complete it would begin positioning the panel. - if (GetTarget()->GetParent() != panel_container_) - PanelLayoutManager::Get(panel_container_)->FinishDragging(); - WmWindow* dst_root = - Shell::GetRootWindowControllerWithDisplayId(dst_display.id()) - ->GetWindow(); - panel_container_ = - dst_root->GetChildByShellWindowId(kShellWindowId_PanelContainer); - - // The panel's parent already knows that the drag is in progress for this - // panel. - if (panel_container_ && GetTarget()->GetParent() != panel_container_) - PanelLayoutManager::Get(panel_container_)->StartDragging(GetTarget()); - } - gfx::Point offset; - gfx::Rect bounds(CalculateBoundsForDrag(location)); - if (!(details().bounds_change & WindowResizer::kBoundsChange_Resizes)) { - window_state_->drag_details()->should_attach_to_shelf = - AttachToLauncher(bounds, &offset); - } - gfx::Point modified_location(location.x() + offset.x(), - location.y() + offset.y()); - - base::WeakPtr<PanelWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr()); - next_window_resizer_->Drag(modified_location, event_flags); - if (!resizer) - return; - - if (details().should_attach_to_shelf && - !(details().bounds_change & WindowResizer::kBoundsChange_Resizes)) { - UpdateLauncherPosition(); - } -} - -void PanelWindowResizer::CompleteDrag() { - // The root window can change when dragging into a different screen. - next_window_resizer_->CompleteDrag(); - FinishDragging(); -} - -void PanelWindowResizer::RevertDrag() { - next_window_resizer_->RevertDrag(); - window_state_->drag_details()->should_attach_to_shelf = was_attached_; - FinishDragging(); -} - -PanelWindowResizer::PanelWindowResizer(WindowResizer* next_window_resizer, - wm::WindowState* window_state) - : WindowResizer(window_state), - next_window_resizer_(next_window_resizer), - panel_container_(NULL), - initial_panel_container_(NULL), - did_move_or_resize_(false), - was_attached_(GetTarget()->aura_window()->GetProperty(kPanelAttachedKey)), - weak_ptr_factory_(this) { - DCHECK(details().is_resizable); - panel_container_ = GetTarget()->GetRootWindow()->GetChildByShellWindowId( - kShellWindowId_PanelContainer); - initial_panel_container_ = panel_container_; -} - -bool PanelWindowResizer::AttachToLauncher(const gfx::Rect& bounds, - gfx::Point* offset) { - bool should_attach = false; - if (panel_container_) { - PanelLayoutManager* panel_layout_manager = - PanelLayoutManager::Get(panel_container_); - gfx::Rect launcher_bounds = GetTarget()->GetParent()->ConvertRectFromScreen( - panel_layout_manager->shelf()->GetWindow()->GetBoundsInScreen()); - switch (panel_layout_manager->shelf()->GetAlignment()) { - case SHELF_ALIGNMENT_BOTTOM: - case SHELF_ALIGNMENT_BOTTOM_LOCKED: - if (bounds.bottom() >= - (launcher_bounds.y() - kPanelSnapToLauncherDistance)) { - should_attach = true; - offset->set_y(launcher_bounds.y() - bounds.height() - bounds.y()); - } - break; - case SHELF_ALIGNMENT_LEFT: - if (bounds.x() <= - (launcher_bounds.right() + kPanelSnapToLauncherDistance)) { - should_attach = true; - offset->set_x(launcher_bounds.right() - bounds.x()); - } - break; - case SHELF_ALIGNMENT_RIGHT: - if (bounds.right() >= - (launcher_bounds.x() - kPanelSnapToLauncherDistance)) { - should_attach = true; - offset->set_x(launcher_bounds.x() - bounds.width() - bounds.x()); - } - break; - } - } - return should_attach; -} - -void PanelWindowResizer::StartedDragging() { - // Tell the panel layout manager that we are dragging this panel before - // attaching it so that it does not get repositioned. - if (panel_container_) - PanelLayoutManager::Get(panel_container_)->StartDragging(GetTarget()); - if (!was_attached_) { - // Attach the panel while dragging, placing it in front of other panels. - WmWindow* target = GetTarget(); - target->aura_window()->SetProperty(kPanelAttachedKey, true); - // We use root window coordinates to ensure that during the drag the panel - // is reparented to a container in the root window that has that window. - WmWindow* target_root = target->GetRootWindow(); - WmWindow* old_parent = target->GetParent(); - target->SetParentUsingContext(target_root, - target_root->GetBoundsInScreen()); - wm::ReparentTransientChildrenOfChild(target, old_parent, - target->GetParent()); - } -} - -void PanelWindowResizer::FinishDragging() { - if (!did_move_or_resize_) - return; - if (GetTarget()->aura_window()->GetProperty(kPanelAttachedKey) != - details().should_attach_to_shelf) { - GetTarget()->aura_window()->SetProperty(kPanelAttachedKey, - details().should_attach_to_shelf); - // We use last known location to ensure that after the drag the panel - // is reparented to a container in the root window that has that location. - WmWindow* target = GetTarget(); - WmWindow* target_root = target->GetRootWindow(); - WmWindow* old_parent = target->GetParent(); - target->SetParentUsingContext(target_root, - gfx::Rect(last_location_, gfx::Size())); - wm::ReparentTransientChildrenOfChild(target, old_parent, - target->GetParent()); - } - - // If we started the drag in one root window and moved into another root - // but then canceled the drag we may need to inform the original layout - // manager that the drag is finished. - if (initial_panel_container_ != panel_container_) - PanelLayoutManager::Get(initial_panel_container_)->FinishDragging(); - if (panel_container_) - PanelLayoutManager::Get(panel_container_)->FinishDragging(); -} - -void PanelWindowResizer::UpdateLauncherPosition() { - if (panel_container_) { - PanelLayoutManager::Get(panel_container_) - ->shelf() - ->UpdateIconPositionForPanel(GetTarget()); - } -} - -} // namespace ash
diff --git a/ash/wm/panels/panel_window_resizer.h b/ash/wm/panels/panel_window_resizer.h deleted file mode 100644 index 09aef19..0000000 --- a/ash/wm/panels/panel_window_resizer.h +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_PANELS_PANEL_WINDOW_RESIZER_H_ -#define ASH_WM_PANELS_PANEL_WINDOW_RESIZER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/window_resizer.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" - -namespace gfx { -class Rect; -class Point; -} - -namespace ash { - -// PanelWindowResizer is used by ToplevelWindowEventFilter to handle dragging, -// moving or resizing panel window. These can be attached and detached from the -// launcher. -class ASH_EXPORT PanelWindowResizer : public WindowResizer { - public: - ~PanelWindowResizer() override; - - // Creates a new PanelWindowResizer. The caller takes ownership of the - // returned object. The ownership of |next_window_resizer| is taken by the - // returned object. Returns NULL if not resizable. - static PanelWindowResizer* Create(WindowResizer* next_window_resizer, - wm::WindowState* window_state); - - // WindowResizer: - void Drag(const gfx::Point& location, int event_flags) override; - void CompleteDrag() override; - void RevertDrag() override; - - private: - // Creates PanelWindowResizer that adds the ability to attach / detach panel - // windows as well as reparenting them to the panel layer while dragging to - // |next_window_resizer|. This object takes ownership of - // |next_window_resizer|. - PanelWindowResizer(WindowResizer* next_window_resizer, - wm::WindowState* window_state); - - // Checks if the provided window bounds should attach to the launcher. If true - // the offset gives the necessary adjustment to snap to the launcher. - bool AttachToLauncher(const gfx::Rect& bounds, gfx::Point* offset); - - // Tracks the panel's initial position and attachment at the start of a drag - // and informs the PanelLayoutManager that a drag has started if necessary. - void StartedDragging(); - - // Informs the PanelLayoutManager that the drag is complete if it was informed - // of the drag start. - void FinishDragging(); - - // Updates the dragged panel's index in the launcher. - void UpdateLauncherPosition(); - - // Last pointer location in screen coordinates. - gfx::Point last_location_; - - // Wraps a window resizer and adds panel detaching / reattaching and snapping - // to launcher behavior during drags. - std::unique_ptr<WindowResizer> next_window_resizer_; - - // Panel container window. - WmWindow* panel_container_; - WmWindow* initial_panel_container_; - - // Set to true once Drag() is invoked and the bounds of the window change. - bool did_move_or_resize_; - - // True if the window started attached to the launcher. - const bool was_attached_; - - base::WeakPtrFactory<PanelWindowResizer> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PanelWindowResizer); -}; - -} // namespace ash - -#endif // ASH_WM_PANELS_PANEL_WINDOW_RESIZER_H_
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc index 5242a1a..f81bd502 100644 --- a/ash/wm/panels/panel_window_resizer_unittest.cc +++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -2,27 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/panels/panel_window_resizer.h" +#include "ash/common/wm/panels/panel_window_resizer.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/cursor_manager_test_api.h" -#include "ash/test/test_shelf_delegate.h" #include "ash/wm/drag_window_resizer.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" #include "base/i18n/rtl.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/wm/power_button_controller.cc b/ash/wm/power_button_controller.cc index 0f88c8dc..104d612 100644 --- a/ash/wm/power_button_controller.cc +++ b/ash/wm/power_button_controller.cc
@@ -4,17 +4,17 @@ #include "ash/wm/power_button_controller.h" -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/ash_switches.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/system/chromeos/audio/tray_audio.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/system/audio/tray_audio.h" -#include "ash/system/power/tablet_power_button_controller.h" -#include "ash/system/tray/system_tray.h" +#include "ash/system/chromeos/power/tablet_power_button_controller.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/session_state_animator.h" #include "base/command_line.h" #include "chromeos/audio/cras_audio_handler.h"
diff --git a/ash/wm/resize_handle_window_targeter.cc b/ash/wm/resize_handle_window_targeter.cc index 2ee505e1..3f81c73 100644 --- a/ash/wm/resize_handle_window_targeter.cc +++ b/ash/wm/resize_handle_window_targeter.cc
@@ -5,8 +5,8 @@ #include "ash/wm/resize_handle_window_targeter.h" #include "ash/common/ash_constants.h" +#include "ash/common/wm/window_state.h" #include "ash/shared/immersive_fullscreen_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/window.h" #include "ui/events/event.h"
diff --git a/ash/wm/resize_handle_window_targeter.h b/ash/wm/resize_handle_window_targeter.h index eec69308..33478c3 100644 --- a/ash/wm/resize_handle_window_targeter.h +++ b/ash/wm/resize_handle_window_targeter.h
@@ -5,7 +5,7 @@ #ifndef ASH_WM_RESIZE_HANDLE_WINDOW_TARGETER_H_ #define ASH_WM_RESIZE_HANDLE_WINDOW_TARGETER_H_ -#include "ash/wm/window_state_observer.h" +#include "ash/common/wm/window_state_observer.h" #include "base/macros.h" #include "ui/aura/window_observer.h" #include "ui/aura/window_targeter.h"
diff --git a/ash/wm/resize_shadow_and_cursor_unittest.cc b/ash/wm/resize_shadow_and_cursor_unittest.cc index 8c951e2..44de897 100644 --- a/ash/wm/resize_shadow_and_cursor_unittest.cc +++ b/ash/wm/resize_shadow_and_cursor_unittest.cc
@@ -3,13 +3,13 @@ // found in the LICENSE file. #include "ash/common/ash_constants.h" -#include "ash/frame/custom_frame_view_ash.h" +#include "ash/common/frame/custom_frame_view_ash.h" +#include "ash/common/wm/window_state.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/cursor_manager_test_api.h" #include "ash/wm/resize_shadow.h" #include "ash/wm/resize_shadow_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/bind.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/wm/root_window_finder.cc b/ash/wm/root_window_finder.cc deleted file mode 100644 index ae1224b..0000000 --- a/ash/wm/root_window_finder.cc +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/root_window_finder.h" - -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shell.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { -namespace wm { - -WmWindow* GetRootWindowAt(const gfx::Point& point) { - const display::Display& display = - display::Screen::GetScreen()->GetDisplayNearestPoint(point); - DCHECK(display.is_valid()); - RootWindowController* root_window_controller = - Shell::GetRootWindowControllerWithDisplayId(display.id()); - return root_window_controller ? root_window_controller->GetWindow() : nullptr; -} - -WmWindow* GetRootWindowMatching(const gfx::Rect& rect) { - const display::Display& display = - display::Screen::GetScreen()->GetDisplayMatching(rect); - RootWindowController* root_window_controller = - Shell::GetRootWindowControllerWithDisplayId(display.id()); - return root_window_controller ? root_window_controller->GetWindow() : nullptr; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/root_window_finder.h b/ash/wm/root_window_finder.h deleted file mode 100644 index ce568bf..0000000 --- a/ash/wm/root_window_finder.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_ROOT_WINDOW_FINDER_H_ -#define ASH_WM_ROOT_WINDOW_FINDER_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Point; -class Rect; -} // namespace gfx - -namespace ash { - -class WmWindow; - -namespace wm { - -// Returns the RootWindow at |point| in the virtual screen coordinates. -// Returns NULL if the root window does not exist at the given -// point. -ASH_EXPORT WmWindow* GetRootWindowAt(const gfx::Point& point); - -// Returns the RootWindow that shares the most area with |rect| in -// the virtual scren coordinates. -ASH_EXPORT WmWindow* GetRootWindowMatching(const gfx::Rect& rect); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_ROOT_WINDOW_FINDER_H_
diff --git a/ash/wm/root_window_layout_manager.cc b/ash/wm/root_window_layout_manager.cc deleted file mode 100644 index 240f153a..0000000 --- a/ash/wm/root_window_layout_manager.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/root_window_layout_manager.h" - -#include "ash/common/wm_window.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tracker.h" - -namespace ash { -namespace wm { - -//////////////////////////////////////////////////////////////////////////////// -// RootWindowLayoutManager, public: - -RootWindowLayoutManager::RootWindowLayoutManager(WmWindow* owner) - : owner_(owner) {} - -RootWindowLayoutManager::~RootWindowLayoutManager() {} - -//////////////////////////////////////////////////////////////////////////////// -// RootWindowLayoutManager, aura::LayoutManager implementation: - -void RootWindowLayoutManager::OnWindowResized() { - const gfx::Rect fullscreen_bounds = gfx::Rect(owner_->GetBounds().size()); - - // Resize both our immediate children (the containers-of-containers animated - // by PowerButtonController) and their children (the actual containers). - aura::WindowTracker children_tracker(owner_->aura_window()->children()); - while (!children_tracker.windows().empty()) { - aura::Window* child = children_tracker.Pop(); - // Skip descendants of top-level windows, i.e. only resize containers and - // other windows without a delegate, such as ScreenDimmer windows. - if (child->GetToplevelWindow()) - continue; - - child->SetBounds(fullscreen_bounds); - aura::WindowTracker grandchildren_tracker(child->children()); - while (!grandchildren_tracker.windows().empty()) { - child = grandchildren_tracker.Pop(); - if (!child->GetToplevelWindow()) - child->SetBounds(fullscreen_bounds); - } - } -} - -void RootWindowLayoutManager::OnWindowAddedToLayout(WmWindow* child) {} - -void RootWindowLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) {} - -void RootWindowLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {} - -void RootWindowLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) {} - -void RootWindowLayoutManager::SetChildBounds( - WmWindow* child, - const gfx::Rect& requested_bounds) { - child->SetBoundsDirect(requested_bounds); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/root_window_layout_manager.h b/ash/wm/root_window_layout_manager.h deleted file mode 100644 index 3f93c0b..0000000 --- a/ash/wm/root_window_layout_manager.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_ROOT_WINDOW_LAYOUT_MANAGER_H_ -#define ASH_WM_ROOT_WINDOW_LAYOUT_MANAGER_H_ - -#include "ash/common/wm_layout_manager.h" -#include "base/macros.h" - -namespace ash { -namespace wm { - -// A layout manager for the root window. -// Resizes all of its immediate children and their descendants to fill the -// bounds of the associated window. -class RootWindowLayoutManager : public WmLayoutManager { - public: - explicit RootWindowLayoutManager(WmWindow* owner); - ~RootWindowLayoutManager() override; - - // Overridden from aura::LayoutManager: - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override; - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - private: - WmWindow* owner_; - - DISALLOW_COPY_AND_ASSIGN(RootWindowLayoutManager); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_ROOT_WINDOW_LAYOUT_MANAGER_H_
diff --git a/ash/wm/screen_dimmer.cc b/ash/wm/screen_dimmer.cc deleted file mode 100644 index abc0eea..0000000 --- a/ash/wm/screen_dimmer.cc +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/screen_dimmer.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/common/wm_window_user_data.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/container_finder.h" -#include "ash/wm/window_dimmer.h" -#include "base/memory/ptr_util.h" - -namespace ash { -namespace { - -// Opacity when it's dimming the entire screen. -const float kDimmingLayerOpacityForRoot = 0.4f; - -// Opacity for lock screen. -const float kDimmingLayerOpacityForLockScreen = 0.5f; - -} // namespace - -ScreenDimmer::ScreenDimmer(Container container) - : container_(container), - is_dimming_(false), - at_bottom_(false), - window_dimmers_(base::MakeUnique<WmWindowUserData<WindowDimmer>>()) { - WmShell::Get()->AddShellObserver(this); -} - -ScreenDimmer::~ScreenDimmer() { - // Usage in chrome results in ScreenDimmer outliving the shell. - if (WmShell::HasInstance()) - WmShell::Get()->RemoveShellObserver(this); -} - -void ScreenDimmer::SetDimming(bool should_dim) { - if (should_dim == is_dimming_) - return; - is_dimming_ = should_dim; - - Update(should_dim); -} - -std::vector<WmWindow*> ScreenDimmer::GetAllContainers() { - return container_ == Container::ROOT - ? WmShell::Get()->GetAllRootWindows() - : wm::GetContainersFromAllRootWindows( - ash::kShellWindowId_LockScreenContainersContainer); -} - -void ScreenDimmer::OnRootWindowAdded(WmWindow* root_window) { - Update(is_dimming_); -} - -void ScreenDimmer::Update(bool should_dim) { - for (WmWindow* container : GetAllContainers()) { - WindowDimmer* window_dimmer = window_dimmers_->Get(container); - if (should_dim) { - if (!window_dimmer) { - window_dimmers_->Set(container, - base::MakeUnique<WindowDimmer>(container)); - window_dimmer = window_dimmers_->Get(container); - window_dimmer->SetDimOpacity(container_ == Container::ROOT - ? kDimmingLayerOpacityForRoot - : kDimmingLayerOpacityForLockScreen); - } - if (at_bottom_) - container->StackChildAtBottom(window_dimmer->window()); - else - container->StackChildAtTop(window_dimmer->window()); - window_dimmer->window()->Show(); - } else if (window_dimmer) { - window_dimmers_->Set(container, nullptr); - } - } -} - -} // namespace ash
diff --git a/ash/wm/screen_dimmer.h b/ash/wm/screen_dimmer.h deleted file mode 100644 index 90064bfe..0000000 --- a/ash/wm/screen_dimmer.h +++ /dev/null
@@ -1,80 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_SCREEN_DIMMER_H_ -#define ASH_WM_SCREEN_DIMMER_H_ - -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "base/macros.h" - -namespace ash { -namespace test { -class ScreenDimmerTest; -} - -class WindowDimmer; - -template <typename UserData> -class WmWindowUserData; - -// ScreenDimmer displays a partially-opaque layer above everything -// else in the given container window to darken the display. It shouldn't be -// used for long-term brightness adjustments due to performance -// considerations -- it's only intended for cases where we want to -// briefly dim the screen (e.g. to indicate to the user that we're -// about to suspend a machine that lacks an internal backlight that -// can be adjusted). -class ASH_EXPORT ScreenDimmer : public ShellObserver { - public: - // Indicates the container ScreenDimmer operates on. - enum class Container { - ROOT, - LOCK_SCREEN, - }; - - explicit ScreenDimmer(Container container); - ~ScreenDimmer() override; - - // Dim or undim the layers. - void SetDimming(bool should_dim); - - void set_at_bottom(bool at_bottom) { at_bottom_ = at_bottom; } - - bool is_dimming() const { return is_dimming_; } - - // Find a ScreenDimmer in the container, or nullptr if it does not exist. - static ScreenDimmer* FindForTest(int container_id); - - private: - friend class test::ScreenDimmerTest; - - // Returns the WmWindows (one per display) that correspond to |container_|. - std::vector<WmWindow*> GetAllContainers(); - - // ShellObserver: - void OnRootWindowAdded(WmWindow* root_window) override; - - // Update the dimming state. This will also create a new DimWindow - // if necessary. (Used when a new display is connected) - void Update(bool should_dim); - - const Container container_; - - // Are we currently dimming the screen? - bool is_dimming_; - bool at_bottom_; - - // Owns the WindowDimmers. - std::unique_ptr<WmWindowUserData<WindowDimmer>> window_dimmers_; - - DISALLOW_COPY_AND_ASSIGN(ScreenDimmer); -}; - -} // namespace ash - -#endif // ASH_WM_SCREEN_DIMMER_H_
diff --git a/ash/wm/screen_dimmer_unittest.cc b/ash/wm/screen_dimmer_unittest.cc index 3591a17..709886f 100644 --- a/ash/wm/screen_dimmer_unittest.cc +++ b/ash/wm/screen_dimmer_unittest.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/screen_dimmer.h" +#include "ash/common/wm/screen_dimmer.h" #include <memory> +#include "ash/common/wm/window_dimmer.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/common/wm_window_user_data.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_dimmer.h" #include "base/memory/ptr_util.h" #include "ui/aura/test/test_windows.h" #include "ui/compositor/layer.h"
diff --git a/ash/wm/screen_pinning_controller.cc b/ash/wm/screen_pinning_controller.cc index 3573c809..72147115 100644 --- a/ash/wm/screen_pinning_controller.cc +++ b/ash/wm/screen_pinning_controller.cc
@@ -7,14 +7,14 @@ #include <algorithm> #include <vector> +#include "ash/common/wm/container_finder.h" +#include "ash/common/wm/window_dimmer.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/common/wm_window_user_data.h" #include "ash/display/window_tree_host_manager.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/container_finder.h" -#include "ash/wm/window_dimmer.h" -#include "ash/wm/window_state.h" #include "base/auto_reset.h" #include "base/logging.h" #include "base/memory/ptr_util.h"
diff --git a/ash/wm/screen_pinning_controller_unittest.cc b/ash/wm/screen_pinning_controller_unittest.cc index 5e8019e..590f4941 100644 --- a/ash/wm/screen_pinning_controller_unittest.cc +++ b/ash/wm/screen_pinning_controller_unittest.cc
@@ -6,13 +6,13 @@ #include <vector> -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/stl_util.h" #include "ui/aura/window.h"
diff --git a/ash/wm/session_state_animator_impl.cc b/ash/wm/session_state_animator_impl.cc index d205155..c0be930 100644 --- a/ash/wm/session_state_animator_impl.cc +++ b/ash/wm/session_state_animator_impl.cc
@@ -6,9 +6,9 @@ #include <vector> +#include "ash/common/wm/wm_window_animations.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/wm_window_animations.h" #include "base/memory/ptr_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/wm/stacking_controller.cc b/ash/wm/stacking_controller.cc index fdb63c9..723265d 100644 --- a/ash/wm/stacking_controller.cc +++ b/ash/wm/stacking_controller.cc
@@ -4,8 +4,8 @@ #include "ash/wm/stacking_controller.h" +#include "ash/common/wm/container_finder.h" #include "ash/common/wm_window.h" -#include "ash/wm/container_finder.h" namespace ash {
diff --git a/ash/wm/switchable_windows.cc b/ash/wm/switchable_windows.cc deleted file mode 100644 index 7eb572d4..0000000 --- a/ash/wm/switchable_windows.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/switchable_windows.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" - -namespace ash { -namespace wm { - -const int kSwitchableWindowContainerIds[] = { - kShellWindowId_DefaultContainer, kShellWindowId_AlwaysOnTopContainer, - kShellWindowId_DockedContainer, kShellWindowId_PanelContainer, - kShellWindowId_AppListContainer}; - -const size_t kSwitchableWindowContainerIdsLength = - arraysize(kSwitchableWindowContainerIds); - -bool IsSwitchableContainer(const WmWindow* window) { - if (!window) - return false; - const int shell_window_id = window->GetShellWindowId(); - for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { - if (shell_window_id == kSwitchableWindowContainerIds[i]) - return true; - } - return false; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/switchable_windows.h b/ash/wm/switchable_windows.h deleted file mode 100644 index 4fc868a2..0000000 --- a/ash/wm/switchable_windows.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_SWITCHABLE_WINDOWS_H_ -#define ASH_WM_SWITCHABLE_WINDOWS_H_ - -#include <stddef.h> - -#include "ash/ash_export.h" -#include "base/macros.h" - -namespace ash { - -class WmWindow; - -namespace wm { - -// List of containers which contain windows that can be switched via Alt+Tab to. -ASH_EXPORT extern const int kSwitchableWindowContainerIds[]; - -// The number of elements in kSwitchableWindowContainerIds. -ASH_EXPORT extern const size_t kSwitchableWindowContainerIdsLength; - -// Returns true if |window| is a container for windows which can be switched to. -ASH_EXPORT bool IsSwitchableContainer(const WmWindow* window); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_SWITCHABLE_WINDOWS_H_
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc index 99944364..063cec1d 100644 --- a/ash/wm/system_gesture_event_filter_unittest.cc +++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -6,15 +6,15 @@ #include <vector> -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/system/tray/system_tray_delegate.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" #include "ash/test/shell_test_api.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/time/time.h" #include "base/timer/timer.h"
diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc deleted file mode 100644 index 46226cec..0000000 --- a/ash/wm/system_modal_container_layout_manager.cc +++ /dev/null
@@ -1,280 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/system_modal_container_layout_manager.h" - -#include <cmath> - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/window_dimmer.h" -#include "base/memory/ptr_util.h" -#include "base/stl_util.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/aura/window.h" -#include "ui/keyboard/keyboard_controller.h" - -namespace ash { -namespace { - -// The center point of the window can diverge this much from the center point -// of the container to be kept centered upon resizing operations. -const int kCenterPixelDelta = 32; - -ui::ModalType GetModalType(WmWindow* window) { - return static_cast<ui::ModalType>( - window->aura_window()->GetProperty(aura::client::kModalKey)); -} - -bool HasTransientAncestor(const WmWindow* window, const WmWindow* ancestor) { - const WmWindow* transient_parent = window->GetTransientParent(); - if (transient_parent == ancestor) - return true; - return transient_parent ? HasTransientAncestor(transient_parent, ancestor) - : false; -} -} - -//////////////////////////////////////////////////////////////////////////////// -// SystemModalContainerLayoutManager, public: - -SystemModalContainerLayoutManager::SystemModalContainerLayoutManager( - WmWindow* container) - : container_(container) {} - -SystemModalContainerLayoutManager::~SystemModalContainerLayoutManager() { - if (keyboard::KeyboardController::GetInstance()) - keyboard::KeyboardController::GetInstance()->RemoveObserver(this); -} - -//////////////////////////////////////////////////////////////////////////////// -// SystemModalContainerLayoutManager, WmLayoutManager implementation: - -void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged( - WmWindow* window, - bool visible) { - if (GetModalType(window) != ui::MODAL_TYPE_SYSTEM) - return; - - if (window->IsVisible()) { - DCHECK(!base::ContainsValue(modal_windows_, window)); - AddModalWindow(window); - } else { - if (RemoveModalWindow(window)) - WmShell::Get()->OnModalWindowRemoved(window); - } -} - -void SystemModalContainerLayoutManager::OnWindowResized() { - PositionDialogsAfterWorkAreaResize(); -} - -void SystemModalContainerLayoutManager::OnWindowAddedToLayout(WmWindow* child) { - DCHECK(child->GetType() == ui::wm::WINDOW_TYPE_NORMAL || - child->GetType() == ui::wm::WINDOW_TYPE_POPUP); - // TODO(mash): IsUserSessionBlocked() depends on knowing the login state. We - // need a non-stub version of SessionStateDelegate. crbug.com/648964 - if (!WmShell::Get()->IsRunningInMash()) { - DCHECK(container_->GetShellWindowId() != - kShellWindowId_LockSystemModalContainer || - WmShell::Get()->GetSessionStateDelegate()->IsUserSessionBlocked()); - } - // Since this is for SystemModal, there is no good reason to add windows - // other than MODAL_TYPE_NONE or MODAL_TYPE_SYSTEM. DCHECK to avoid simple - // mistake. - DCHECK_NE(GetModalType(child), ui::MODAL_TYPE_CHILD); - DCHECK_NE(GetModalType(child), ui::MODAL_TYPE_WINDOW); - - child->aura_window()->AddObserver(this); - if (GetModalType(child) == ui::MODAL_TYPE_SYSTEM && child->IsVisible()) - AddModalWindow(child); -} - -void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout( - WmWindow* child) { - child->aura_window()->RemoveObserver(this); - windows_to_center_.erase(child); - if (GetModalType(child) == ui::MODAL_TYPE_SYSTEM) - RemoveModalWindow(child); -} - -void SystemModalContainerLayoutManager::SetChildBounds( - WmWindow* child, - const gfx::Rect& requested_bounds) { - WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds); - if (IsBoundsCentered(requested_bounds)) - windows_to_center_.insert(child); - else - windows_to_center_.erase(child); -} - -//////////////////////////////////////////////////////////////////////////////// -// SystemModalContainerLayoutManager, aura::WindowObserver implementation: - -void SystemModalContainerLayoutManager::OnWindowPropertyChanged( - aura::Window* window, - const void* key, - intptr_t old) { - if (key != aura::client::kModalKey || !window->IsVisible()) - return; - - WmWindow* wm_window = WmWindow::Get(window); - if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM) { - if (base::ContainsValue(modal_windows_, wm_window)) - return; - AddModalWindow(wm_window); - } else { - if (RemoveModalWindow(wm_window)) - WmShell::Get()->OnModalWindowRemoved(wm_window); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver -// implementation: - -void SystemModalContainerLayoutManager::OnKeyboardBoundsChanging( - const gfx::Rect& new_bounds) { - PositionDialogsAfterWorkAreaResize(); -} - -void SystemModalContainerLayoutManager::OnKeyboardClosed() {} - -bool SystemModalContainerLayoutManager::IsPartOfActiveModalWindow( - WmWindow* window) { - return modal_window() && - (modal_window()->Contains(window) || - HasTransientAncestor(window->GetToplevelWindowForFocus(), - modal_window())); -} - -bool SystemModalContainerLayoutManager::ActivateNextModalWindow() { - if (modal_windows_.empty()) - return false; - modal_window()->Activate(); - return true; -} - -void SystemModalContainerLayoutManager::CreateModalBackground() { - if (!window_dimmer_) { - window_dimmer_ = base::MakeUnique<WindowDimmer>(container_); - window_dimmer_->window()->SetName( - "SystemModalContainerLayoutManager.ModalBackground"); - // There isn't always a keyboard controller. - if (keyboard::KeyboardController::GetInstance()) - keyboard::KeyboardController::GetInstance()->AddObserver(this); - } - window_dimmer_->window()->Show(); -} - -void SystemModalContainerLayoutManager::DestroyModalBackground() { - if (!window_dimmer_) - return; - - if (keyboard::KeyboardController::GetInstance()) - keyboard::KeyboardController::GetInstance()->RemoveObserver(this); - window_dimmer_.reset(); -} - -// static -bool SystemModalContainerLayoutManager::IsModalBackground(WmWindow* window) { - int id = window->GetParent()->GetShellWindowId(); - if (id != kShellWindowId_SystemModalContainer && - id != kShellWindowId_LockSystemModalContainer) - return false; - SystemModalContainerLayoutManager* layout_manager = - static_cast<SystemModalContainerLayoutManager*>( - window->GetParent()->GetLayoutManager()); - return layout_manager->window_dimmer_ && - layout_manager->window_dimmer_->window() == window; -} - -//////////////////////////////////////////////////////////////////////////////// -// SystemModalContainerLayoutManager, private: - -void SystemModalContainerLayoutManager::AddModalWindow(WmWindow* window) { - if (modal_windows_.empty()) { - WmWindow* capture_window = WmShell::Get()->GetCaptureWindow(); - if (capture_window) - capture_window->ReleaseCapture(); - } - DCHECK(window->IsVisible()); - DCHECK(!base::ContainsValue(modal_windows_, window)); - - modal_windows_.push_back(window); - WmShell::Get()->CreateModalBackground(window); - window->GetParent()->StackChildAtTop(window); - - gfx::Rect target_bounds = window->GetBounds(); - target_bounds.AdjustToFit(GetUsableDialogArea()); - window->SetBounds(target_bounds); -} - -bool SystemModalContainerLayoutManager::RemoveModalWindow(WmWindow* window) { - auto it = std::find(modal_windows_.begin(), modal_windows_.end(), window); - if (it == modal_windows_.end()) - return false; - modal_windows_.erase(it); - return true; -} - -void SystemModalContainerLayoutManager::PositionDialogsAfterWorkAreaResize() { - if (modal_windows_.empty()) - return; - - for (WmWindow* window : modal_windows_) - window->SetBounds(GetCenteredAndOrFittedBounds(window)); -} - -gfx::Rect SystemModalContainerLayoutManager::GetUsableDialogArea() const { - // Instead of resizing the system modal container, we move only the modal - // windows. This way we avoid flashing lines upon resize animation and if the - // keyboard will not fill left to right, the background is still covered. - gfx::Rect valid_bounds = container_->GetBounds(); - keyboard::KeyboardController* keyboard_controller = - keyboard::KeyboardController::GetInstance(); - if (keyboard_controller) { - gfx::Rect bounds = keyboard_controller->current_keyboard_bounds(); - if (!bounds.IsEmpty()) { - valid_bounds.set_height( - std::max(0, valid_bounds.height() - bounds.height())); - } - } - return valid_bounds; -} - -gfx::Rect SystemModalContainerLayoutManager::GetCenteredAndOrFittedBounds( - const WmWindow* window) { - gfx::Rect target_bounds; - gfx::Rect usable_area = GetUsableDialogArea(); - if (windows_to_center_.count(window) > 0) { - // Keep the dialog centered if it was centered before. - target_bounds = usable_area; - target_bounds.ClampToCenteredSize(window->GetBounds().size()); - } else { - // Keep the dialog within the usable area. - target_bounds = window->GetBounds(); - target_bounds.AdjustToFit(usable_area); - } - if (usable_area != container_->GetBounds()) { - // Don't clamp the dialog for the keyboard. Keep the size as it is but make - // sure that the top remains visible. - // TODO(skuhne): M37 should add over scroll functionality to address this. - target_bounds.set_size(window->GetBounds().size()); - } - return target_bounds; -} - -bool SystemModalContainerLayoutManager::IsBoundsCentered( - const gfx::Rect& bounds) const { - gfx::Point window_center = bounds.CenterPoint(); - gfx::Point container_center = GetUsableDialogArea().CenterPoint(); - return std::abs(window_center.x() - container_center.x()) < - kCenterPixelDelta && - std::abs(window_center.y() - container_center.y()) < kCenterPixelDelta; -} - -} // namespace ash
diff --git a/ash/wm/system_modal_container_layout_manager.h b/ash/wm/system_modal_container_layout_manager.h deleted file mode 100644 index 3e9a4230..0000000 --- a/ash/wm/system_modal_container_layout_manager.h +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_SYSTEM_MODAL_CONTAINER_LAYOUT_MANAGER_H_ -#define ASH_WM_SYSTEM_MODAL_CONTAINER_LAYOUT_MANAGER_H_ - -#include <memory> -#include <set> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/wm/wm_snap_to_pixel_layout_manager.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace gfx { -class Rect; -} - -namespace ash { -class WindowDimmer; - -// LayoutManager for the modal window container. -// System modal windows which are centered on the screen will be kept centered -// when the container size changes. -class ASH_EXPORT SystemModalContainerLayoutManager - : public wm::WmSnapToPixelLayoutManager, - public aura::WindowObserver, - public keyboard::KeyboardControllerObserver { - public: - explicit SystemModalContainerLayoutManager(WmWindow* container); - ~SystemModalContainerLayoutManager() override; - - bool has_window_dimmer() const { return window_dimmer_ != nullptr; } - - // Overridden from WmSnapToPixelLayoutManager: - void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override; - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - // Overridden from aura::WindowObserver: - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; - - // Overridden from keyboard::KeyboardControllerObserver: - void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; - void OnKeyboardClosed() override; - - // True if the window is either contained by the top most modal window, - // or contained by its transient children. - bool IsPartOfActiveModalWindow(WmWindow* window); - - // Activates next modal window if any. Returns false if there - // are no more modal windows in this layout manager. - bool ActivateNextModalWindow(); - - // Creates modal background window, which is a partially-opaque - // fullscreen window. If there is already a modal background window, - // it will bring it the top. - void CreateModalBackground(); - - void DestroyModalBackground(); - - // Is the |window| modal background? - static bool IsModalBackground(WmWindow* window); - - private: - void AddModalWindow(WmWindow* window); - - // Removes |window| from |modal_windows_|. Returns true if |window| was in - // |modal_windows_|. - bool RemoveModalWindow(WmWindow* window); - - // Reposition the dialogs to become visible after the work area changes. - void PositionDialogsAfterWorkAreaResize(); - - // Get the usable bounds rectangle for enclosed dialogs. - gfx::Rect GetUsableDialogArea() const; - - // Gets the new bounds for a |window| to use which are either centered (if the - // window was previously centered) or fitted to the screen. - gfx::Rect GetCenteredAndOrFittedBounds(const WmWindow* window); - - // Returns true if |bounds| is considered centered. - bool IsBoundsCentered(const gfx::Rect& window_bounds) const; - - WmWindow* modal_window() { - return !modal_windows_.empty() ? modal_windows_.back() : nullptr; - } - - // The container that owns the layout manager. - WmWindow* container_; - - // WindowDimmer used to dim windows behind the modal window(s) being shown in - // |container_|. - std::unique_ptr<WindowDimmer> window_dimmer_; - - // A stack of modal windows. Only the topmost can receive events. - std::vector<WmWindow*> modal_windows_; - - // Windows contained in this set are centered. Windows are automatically - // added to this based on IsBoundsCentered(). - std::set<const WmWindow*> windows_to_center_; - - DISALLOW_COPY_AND_ASSIGN(SystemModalContainerLayoutManager); -}; - -} // namespace ash - -#endif // ASH_WM_SYSTEM_MODAL_CONTAINER_LAYOUT_MANAGER_H_
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc index 3669016d..ede38a7 100644 --- a/ash/wm/system_modal_container_layout_manager_unittest.cc +++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -2,18 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/system_modal_container_layout_manager.h" +#include "ash/common/wm/system_modal_container_layout_manager.h" #include <memory> #include "ash/common/session/session_state_delegate.h" +#include "ash/common/wm/container_finder.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/container_finder.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/compiler_specific.h"
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc index 04584c3f..fee1c16 100644 --- a/ash/wm/toplevel_window_event_handler.cc +++ b/ash/wm/toplevel_window_event_handler.cc
@@ -4,9 +4,9 @@ #include "ash/wm/toplevel_window_event_handler.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h"
diff --git a/ash/wm/toplevel_window_event_handler.h b/ash/wm/toplevel_window_event_handler.h index 7a2bf45..171b174f 100644 --- a/ash/wm/toplevel_window_event_handler.h +++ b/ash/wm/toplevel_window_event_handler.h
@@ -6,8 +6,8 @@ #define ASH_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_ #include "ash/ash_export.h" -#include "ash/wm/wm_toplevel_window_event_handler.h" -#include "ash/wm/wm_types.h" +#include "ash/common/wm/wm_toplevel_window_event_handler.h" +#include "ash/common/wm/wm_types.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "ui/events/event_handler.h"
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc index f2d3655..3581f69 100644 --- a/ash/wm/toplevel_window_event_handler_unittest.cc +++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -4,6 +4,9 @@ #include "ash/wm/toplevel_window_event_handler.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" @@ -11,11 +14,8 @@ #include "ash/test/ash_test_base.h" #include "ash/wm/resize_shadow.h" #include "ash/wm/resize_shadow_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace_controller.h" #include "base/compiler_specific.h" #include "base/threading/thread_task_runner_handle.h" #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
diff --git a/ash/wm/video_detector.cc b/ash/wm/video_detector.cc index 8cac55f..18d9704 100644 --- a/ash/wm/video_detector.cc +++ b/ash/wm/video_detector.cc
@@ -4,11 +4,11 @@ #include "ash/wm/video_detector.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/env.h" #include "ui/aura/window.h"
diff --git a/ash/wm/video_detector_unittest.cc b/ash/wm/video_detector_unittest.cc index 5894269..33a5c95 100644 --- a/ash/wm/video_detector_unittest.cc +++ b/ash/wm/video_detector_unittest.cc
@@ -7,11 +7,11 @@ #include <deque> #include <memory> +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" #include "base/compiler_specific.h" #include "base/time/time.h" #include "third_party/skia/include/core/SkColor.h"
diff --git a/ash/wm/window_animation_types.h b/ash/wm/window_animation_types.h deleted file mode 100644 index eb30c35..0000000 --- a/ash/wm/window_animation_types.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_ANIMATION_TYPES_H_ -#define ASH_WM_WINDOW_ANIMATION_TYPES_H_ - -#include "ui/wm/core/window_animations.h" - -namespace ash { -namespace wm { - -// An extension of the window animations provided by CoreWm. These are -// Ash-specific only. -enum WindowVisibilityAnimationType { - // Window scale/rotates down to its launcher icon. - WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE = - ::wm::WINDOW_VISIBILITY_ANIMATION_MAX, - // Fade in/out using brightness and grayscale web filters. - WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_ANIMATION_TYPES_H_
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index 048aa95..c36a0c6 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc
@@ -9,11 +9,11 @@ #include <utility> #include <vector> +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/common/wm_window.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_util.h" -#include "ash/wm/workspace_controller.h" #include "base/i18n/rtl.h" #include "base/logging.h" #include "base/memory/ptr_util.h"
diff --git a/ash/wm/window_animations_unittest.cc b/ash/wm/window_animations_unittest.cc index a95d5f9e..69df3bf 100644 --- a/ash/wm/window_animations_unittest.cc +++ b/ash/wm/window_animations_unittest.cc
@@ -4,12 +4,12 @@ #include "ash/wm/window_animations.h" +#include "ash/common/wm/window_animation_types.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_animation_types.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/workspace_controller.h" #include "base/time/time.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h"
diff --git a/ash/wm/window_cycle_controller.cc b/ash/wm/window_cycle_controller.cc deleted file mode 100644 index f00183c..0000000 --- a/ash/wm/window_cycle_controller.cc +++ /dev/null
@@ -1,126 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_cycle_controller.h" - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/metrics/task_switch_source.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_cycle_event_filter.h" -#include "ash/wm/window_cycle_list.h" -#include "ash/wm/window_state.h" -#include "base/metrics/histogram_macros.h" - -namespace ash { - -namespace { - -// Returns the most recently active window from the |window_list| or nullptr -// if the list is empty. -WmWindow* GetActiveWindow(const MruWindowTracker::WindowList& window_list) { - return window_list.empty() ? nullptr : window_list[0]; -} - -} // namespace - -////////////////////////////////////////////////////////////////////////////// -// WindowCycleController, public: - -WindowCycleController::WindowCycleController() {} - -WindowCycleController::~WindowCycleController() {} - -// static -bool WindowCycleController::CanCycle() { - // Prevent window cycling if the screen is locked or a modal dialog is open. - WmShell* wm_shell = WmShell::Get(); - return !wm_shell->GetSessionStateDelegate()->IsScreenLocked() && - !wm_shell->IsSystemModalWindowOpen() && !wm_shell->IsPinned(); -} - -void WindowCycleController::HandleCycleWindow(Direction direction) { - if (!CanCycle()) - return; - - if (!IsCycling()) - StartCycling(); - - Step(direction); -} - -void WindowCycleController::StartCycling() { - MruWindowTracker::WindowList window_list = - WmShell::Get()->mru_window_tracker()->BuildMruWindowList(); - // Exclude windows: - // - non user positionable windows, such as extension popups. - // - windows being dragged - // - the AppList window, which will hide as soon as cycling starts - // anyway. It doesn't make sense to count it as a "switchable" window, yet - // a lot of code relies on the MRU list returning the app window. If we - // don't manually remove it, the window cycling UI won't crash or misbehave, - // but there will be a flicker as the target window changes. Also exclude - // unselectable windows such as extension popups. - auto window_is_ineligible = [](WmWindow* window) { - wm::WindowState* state = window->GetWindowState(); - return !state->IsUserPositionable() || state->is_dragged() || - window->GetRootWindow() - ->GetChildByShellWindowId(kShellWindowId_AppListContainer) - ->Contains(window); - }; - window_list.erase(std::remove_if(window_list.begin(), window_list.end(), - window_is_ineligible), - window_list.end()); - - active_window_before_window_cycle_ = GetActiveWindow(window_list); - - window_cycle_list_.reset(new WindowCycleList(window_list)); - event_filter_ = WmShell::Get()->CreateWindowCycleEventFilter(); - cycle_start_time_ = base::Time::Now(); - WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_CYCLE); - UMA_HISTOGRAM_COUNTS_100("Ash.WindowCycleController.Items", - window_list.size()); -} - -void WindowCycleController::CompleteCycling() { - window_cycle_list_->set_user_did_accept(true); - StopCycling(); -} - -void WindowCycleController::CancelCycling() { - StopCycling(); -} - -////////////////////////////////////////////////////////////////////////////// -// WindowCycleController, private: - -void WindowCycleController::Step(Direction direction) { - DCHECK(window_cycle_list_.get()); - window_cycle_list_->Step(direction); -} - -void WindowCycleController::StopCycling() { - UMA_HISTOGRAM_COUNTS_100("Ash.WindowCycleController.SelectionDepth", - window_cycle_list_->current_index() + 1); - window_cycle_list_.reset(); - - WmWindow* active_window_after_window_cycle = GetActiveWindow( - WmShell::Get()->mru_window_tracker()->BuildMruWindowList()); - - // Remove our key event filter. - event_filter_.reset(); - UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowCycleController.CycleTime", - base::Time::Now() - cycle_start_time_); - - if (active_window_after_window_cycle != nullptr && - active_window_before_window_cycle_ != active_window_after_window_cycle) { - WmShell::Get()->RecordTaskSwitchMetric( - TaskSwitchSource::WINDOW_CYCLE_CONTROLLER); - } - active_window_before_window_cycle_ = nullptr; -} - -} // namespace ash
diff --git a/ash/wm/window_cycle_controller.h b/ash/wm/window_cycle_controller.h deleted file mode 100644 index 65b354ce..0000000 --- a/ash/wm/window_cycle_controller.h +++ /dev/null
@@ -1,82 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_CYCLE_CONTROLLER_H_ -#define ASH_WM_WINDOW_CYCLE_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/time/time.h" - -namespace ash { - -class WindowCycleEventFilter; -class WindowCycleList; -class WmWindow; - -// Controls cycling through windows with the keyboard via alt-tab. -// Windows are sorted primarily by most recently used, and then by screen order. -// We activate windows as you cycle through them, so the order on the screen -// may change during the gesture, but the most recently used list isn't updated -// until the cycling ends. Thus we maintain the state of the windows -// at the beginning of the gesture so you can cycle through in a consistent -// order. -class ASH_EXPORT WindowCycleController { - public: - enum Direction { FORWARD, BACKWARD }; - - WindowCycleController(); - virtual ~WindowCycleController(); - - // Returns true if cycling through windows is enabled. This is false at - // certain times, such as when the lock screen is visible. - static bool CanCycle(); - - // Cycles between windows in the given |direction|. - void HandleCycleWindow(Direction direction); - - // Returns true if we are in the middle of a window cycling gesture. - bool IsCycling() const { return window_cycle_list_.get() != NULL; } - - // Call to start cycling windows. This funtion adds a pre-target handler to - // listen to the alt key release. - void StartCycling(); - - // Both of these functions stop the current window cycle and removes the event - // filter. The former indicates success (i.e. the new window should be - // activated) and the latter indicates that the interaction was cancelled (and - // the originally active window should remain active). - void CompleteCycling(); - void CancelCycling(); - - // Returns the WindowCycleList. - const WindowCycleList* window_cycle_list() const { - return window_cycle_list_.get(); - } - - private: - // Cycles to the next or previous window based on |direction|. - void Step(Direction direction); - - void StopCycling(); - - std::unique_ptr<WindowCycleList> window_cycle_list_; - - // Tracks what Window was active when starting to cycle and used to determine - // if the active Window changed in when ending cycling. - WmWindow* active_window_before_window_cycle_ = nullptr; - - // Non-null while actively cycling. - std::unique_ptr<WindowCycleEventFilter> event_filter_; - - base::Time cycle_start_time_; - - DISALLOW_COPY_AND_ASSIGN(WindowCycleController); -}; - -} // namespace ash - -#endif // ASH_WM_WINDOW_CYCLE_CONTROLLER_H_
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc index 7e8546376..8504f88 100644 --- a/ash/wm/window_cycle_controller_unittest.cc +++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/window_cycle_controller.h" +#include "ash/common/wm/window_cycle_controller.h" #include <algorithm> #include <memory> @@ -10,22 +10,22 @@ #include "ash/common/focus_cycler.h" #include "ash/common/scoped_root_window_for_new_windows.h" #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/window_cycle_list.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/shelf_view_test_api.h" #include "ash/test/test_app_list_view_presenter_impl.h" -#include "ash/test/test_shelf_delegate.h" #include "ash/test/test_shell_delegate.h" -#include "ash/wm/window_cycle_list.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h"
diff --git a/ash/wm/window_cycle_event_filter.h b/ash/wm/window_cycle_event_filter.h deleted file mode 100644 index 711aca2..0000000 --- a/ash/wm/window_cycle_event_filter.h +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_CYCLE_EVENT_FILTER_H_ -#define ASH_WM_WINDOW_CYCLE_EVENT_FILTER_H_ - -#include "ash/ash_export.h" - -namespace ash { - -// Created by WindowCycleController when cycling through windows. Eats all key -// events and stops cycling when the necessary key sequence is encountered. -class ASH_EXPORT WindowCycleEventFilter { - public: - virtual ~WindowCycleEventFilter() {} -}; - -} // namepsace ash - -#endif // ASH_WM_WINDOW_CYCLE_EVENT_FILTER_H_
diff --git a/ash/wm/window_cycle_event_filter_aura.cc b/ash/wm/window_cycle_event_filter_aura.cc index 9af1c1c..77ec193 100644 --- a/ash/wm/window_cycle_event_filter_aura.cc +++ b/ash/wm/window_cycle_event_filter_aura.cc
@@ -4,11 +4,11 @@ #include "ash/wm/window_cycle_event_filter_aura.h" -#include "ash/accelerators/debug_commands.h" +#include "ash/common/accelerators/debug_commands.h" +#include "ash/common/wm/window_cycle_controller.h" +#include "ash/common/wm/window_cycle_list.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/wm/window_cycle_controller.h" -#include "ash/wm/window_cycle_list.h" #include "ui/events/event.h" namespace ash {
diff --git a/ash/wm/window_cycle_event_filter_aura.h b/ash/wm/window_cycle_event_filter_aura.h index 3cec0ce..eb567f6 100644 --- a/ash/wm/window_cycle_event_filter_aura.h +++ b/ash/wm/window_cycle_event_filter_aura.h
@@ -5,7 +5,7 @@ #ifndef ASH_WM_WINDOW_CYCLE_EVENT_FILTER_AURA_H_ #define ASH_WM_WINDOW_CYCLE_EVENT_FILTER_AURA_H_ -#include "ash/wm/window_cycle_event_filter.h" +#include "ash/common/wm/window_cycle_event_filter.h" #include "base/macros.h" #include "base/timer/timer.h" #include "ui/events/event_handler.h"
diff --git a/ash/wm/window_cycle_list.cc b/ash/wm/window_cycle_list.cc deleted file mode 100644 index 0f1ea9a..0000000 --- a/ash/wm/window_cycle_list.cc +++ /dev/null
@@ -1,551 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_cycle_list.h" - -#include <list> -#include <map> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" -#include "base/command_line.h" -#include "ui/accessibility/ax_node_data.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/canvas.h" -#include "ui/views/background.h" -#include "ui/views/border.h" -#include "ui/views/controls/label.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/painter.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/wm/core/visibility_controller.h" - -namespace ash { - -namespace { - -bool g_disable_initial_delay = false; - -// Used for the highlight view and the shield (black background). -constexpr float kBackgroundCornerRadius = 4.f; - -// This background paints a |Painter| but fills the view's layer's size rather -// than the view's size. -class LayerFillBackgroundPainter : public views::Background { - public: - explicit LayerFillBackgroundPainter(std::unique_ptr<views::Painter> painter) - : painter_(std::move(painter)) {} - - ~LayerFillBackgroundPainter() override {} - - void Paint(gfx::Canvas* canvas, views::View* view) const override { - views::Painter::PaintPainterAt(canvas, painter_.get(), - gfx::Rect(view->layer()->size())); - } - - private: - std::unique_ptr<views::Painter> painter_; - - DISALLOW_COPY_AND_ASSIGN(LayerFillBackgroundPainter); -}; - -} // namespace - -// This view represents a single WmWindow by displaying a title and a thumbnail -// of the window's contents. -class WindowPreviewView : public views::View, public aura::WindowObserver { - public: - explicit WindowPreviewView(WmWindow* window) - : window_title_(new views::Label), - preview_background_(new views::View), - mirror_view_(window->CreateViewWithRecreatedLayers().release()), - window_observer_(this) { - window_observer_.Add(window->aura_window()); - window_title_->SetText(window->GetTitle()); - window_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - window_title_->SetEnabledColor(SK_ColorWHITE); - window_title_->SetAutoColorReadabilityEnabled(false); - // Background is not fully opaque, so subpixel rendering won't look good. - window_title_->SetSubpixelRenderingEnabled(false); - // The base font is 12pt (for English) so this comes out to 14pt. - const int kLabelSizeDelta = 2; - window_title_->SetFontList( - window_title_->font_list().DeriveWithSizeDelta(kLabelSizeDelta)); - const int kAboveLabelPadding = 5; - const int kBelowLabelPadding = 10; - window_title_->SetBorder( - views::CreateEmptyBorder(kAboveLabelPadding, 0, kBelowLabelPadding, 0)); - AddChildView(window_title_); - - // Preview padding is black at 50% opacity. - preview_background_->set_background( - views::Background::CreateSolidBackground( - SkColorSetA(SK_ColorBLACK, 0xFF / 2))); - AddChildView(preview_background_); - - AddChildView(mirror_view_); - - SetFocusBehavior(FocusBehavior::ALWAYS); - } - ~WindowPreviewView() override {} - - // views::View: - gfx::Size GetPreferredSize() const override { - gfx::Size size = GetSizeForPreviewArea(); - size.Enlarge(0, window_title_->GetPreferredSize().height()); - return size; - } - - void Layout() override { - const gfx::Size preview_area_size = GetSizeForPreviewArea(); - // The window title is positioned above the preview area. - window_title_->SetBounds(0, 0, width(), - height() - preview_area_size.height()); - - gfx::Rect preview_area_bounds(preview_area_size); - preview_area_bounds.set_y(height() - preview_area_size.height()); - mirror_view_->SetSize(GetMirrorViewScaledSize()); - if (mirror_view_->size() == preview_area_size) { - // Padding is not needed, hide the background and set the mirror view - // to take up the entire preview area. - mirror_view_->SetPosition(preview_area_bounds.origin()); - preview_background_->SetVisible(false); - return; - } - - // Padding is needed, so show the background and set the mirror view to be - // centered within it. - preview_background_->SetBoundsRect(preview_area_bounds); - preview_background_->SetVisible(true); - preview_area_bounds.ClampToCenteredSize(mirror_view_->size()); - mirror_view_->SetPosition(preview_area_bounds.origin()); - } - - void GetAccessibleNodeData(ui::AXNodeData* node_data) override { - node_data->role = ui::AX_ROLE_WINDOW; - node_data->SetName(window_title_->text()); - } - - // aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override { - window_observer_.Remove(window); - } - - void OnWindowTitleChanged(aura::Window* window) override { - window_title_->SetText(window->GetTitle()); - } - - private: - // The maximum width of a window preview. - static const int kMaxPreviewWidth = 512; - // All previews are the same height (this is achieved via a combination of - // scaling and padding). - static const int kFixedPreviewHeight = 256; - - // Returns the size for the mirror view, scaled to fit within the max bounds. - // Scaling is always 1:1 and we only scale down, never up. - gfx::Size GetMirrorViewScaledSize() const { - gfx::Size mirror_pref_size = mirror_view_->GetPreferredSize(); - - if (mirror_pref_size.width() > kMaxPreviewWidth || - mirror_pref_size.height() > kFixedPreviewHeight) { - float scale = std::min( - kMaxPreviewWidth / static_cast<float>(mirror_pref_size.width()), - kFixedPreviewHeight / static_cast<float>(mirror_pref_size.height())); - mirror_pref_size = - gfx::ScaleToFlooredSize(mirror_pref_size, scale, scale); - } - - return mirror_pref_size; - } - - // Returns the size for the entire preview area (mirror view and additional - // padding). All previews will be the same height, so if the mirror view isn't - // tall enough we will add top and bottom padding. Previews can range in width - // from kMaxPreviewWidth down to half that value. Again, padding will be added - // to the sides to achieve this if the preview is too narrow. - gfx::Size GetSizeForPreviewArea() const { - gfx::Size mirror_size = GetMirrorViewScaledSize(); - float aspect_ratio = - static_cast<float>(mirror_size.width()) / mirror_size.height(); - gfx::Size preview_size = mirror_size; - // Very narrow windows get vertical bars of padding on the sides. - if (aspect_ratio < 0.5f) - preview_size.set_width(mirror_size.height() / 2); - - // All previews are the same height (this may add padding on top and - // bottom). - preview_size.set_height(kFixedPreviewHeight); - // Previews should never be narrower than half their max width (128dip). - preview_size.set_width( - std::max(preview_size.width(), kMaxPreviewWidth / 2)); - - return preview_size; - } - - // Displays the title of the window above the preview. - views::Label* window_title_; - // When visible, shows a darkened background area behind |mirror_view_| - // (effectively padding the preview to fit the desired bounds). - views::View* preview_background_; - // The view that actually renders a thumbnail version of the window. - views::View* mirror_view_; - - ScopedObserver<aura::Window, aura::WindowObserver> window_observer_; - - DISALLOW_COPY_AND_ASSIGN(WindowPreviewView); -}; - -// A view that shows a collection of windows the user can tab through. -class WindowCycleView : public views::WidgetDelegateView { - public: - explicit WindowCycleView(const WindowCycleList::WindowList& windows) - : mirror_container_(new views::View()), - highlight_view_(new views::View()), - target_window_(nullptr) { - DCHECK(!windows.empty()); - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - layer()->SetMasksToBounds(true); - layer()->SetOpacity(0.0); - { - ui::ScopedLayerAnimationSettings animate_fade(layer()->GetAnimator()); - animate_fade.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(100)); - layer()->SetOpacity(1.0); - } - - const int kInsideBorderPaddingDip = 64; - const int kBetweenChildPaddingDip = 10; - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kHorizontal, kInsideBorderPaddingDip, - kInsideBorderPaddingDip, kBetweenChildPaddingDip); - layout->set_cross_axis_alignment( - views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); - mirror_container_->SetLayoutManager(layout); - mirror_container_->SetPaintToLayer(); - mirror_container_->layer()->SetFillsBoundsOpaquely(false); - - for (WmWindow* window : windows) { - // |mirror_container_| owns |view|. - views::View* view = new WindowPreviewView(window); - window_view_map_[window] = view; - mirror_container_->AddChildView(view); - } - - // The background needs to be painted to fill the layer, not the View, - // because the layer animates bounds changes but the View's bounds change - // immediately. - highlight_view_->set_background(new LayerFillBackgroundPainter( - views::Painter::CreateRoundRectWith1PxBorderPainter( - SkColorSetA(SK_ColorWHITE, 0x4D), SkColorSetA(SK_ColorWHITE, 0x33), - kBackgroundCornerRadius))); - highlight_view_->SetPaintToLayer(); - - highlight_view_->layer()->SetFillsBoundsOpaquely(false); - - AddChildView(highlight_view_); - AddChildView(mirror_container_); - } - - ~WindowCycleView() override {} - - void SetTargetWindow(WmWindow* target) { - target_window_ = target; - if (GetWidget()) { - Layout(); - if (target_window_) - window_view_map_[target_window_]->RequestFocus(); - } - } - - void HandleWindowDestruction(WmWindow* destroying_window, - WmWindow* new_target) { - auto view_iter = window_view_map_.find(destroying_window); - views::View* preview = view_iter->second; - views::View* parent = preview->parent(); - DCHECK_EQ(mirror_container_, parent); - window_view_map_.erase(view_iter); - delete preview; - // With one of its children now gone, we must re-layout |mirror_container_|. - // This must happen before SetTargetWindow() to make sure our own Layout() - // works correctly when it's calculating highlight bounds. - parent->Layout(); - SetTargetWindow(new_target); - } - - void DestroyContents() { - window_view_map_.clear(); - RemoveAllChildViews(true); - } - - // views::WidgetDelegateView overrides: - gfx::Size GetPreferredSize() const override { - return mirror_container_->GetPreferredSize(); - } - - void Layout() override { - if (!target_window_ || bounds().IsEmpty()) - return; - - bool first_layout = mirror_container_->bounds().IsEmpty(); - // If |mirror_container_| has not yet been laid out, we must lay it and its - // descendants out so that the calculations based on |target_view| work - // properly. - if (first_layout) - mirror_container_->SizeToPreferredSize(); - - views::View* target_view = window_view_map_[target_window_]; - gfx::RectF target_bounds(target_view->GetLocalBounds()); - views::View::ConvertRectToTarget(target_view, mirror_container_, - &target_bounds); - gfx::Rect container_bounds(mirror_container_->GetPreferredSize()); - // Case one: the container is narrower than the screen. Center the - // container. - int x_offset = (width() - container_bounds.width()) / 2; - if (x_offset < 0) { - // Case two: the container is wider than the screen. Center the target - // view by moving the list just enough to ensure the target view is in the - // center. - x_offset = width() / 2 - - mirror_container_->GetMirroredXInView( - target_bounds.CenterPoint().x()); - - // However, the container must span the screen, i.e. the maximum x is 0 - // and the minimum for its right boundary is the width of the screen. - x_offset = std::min(x_offset, 0); - x_offset = std::max(x_offset, width() - container_bounds.width()); - } - container_bounds.set_x(x_offset); - mirror_container_->SetBoundsRect(container_bounds); - - // Calculate the target preview's bounds relative to |this|. - views::View::ConvertRectToTarget(mirror_container_, this, &target_bounds); - const int kHighlightPaddingDip = 5; - target_bounds.Inset(gfx::InsetsF(-kHighlightPaddingDip)); - target_bounds.set_x( - GetMirroredXWithWidthInView(target_bounds.x(), target_bounds.width())); - highlight_view_->SetBoundsRect(gfx::ToEnclosingRect(target_bounds)); - - // Enable animations only after the first Layout() pass. - if (first_layout) { - // The preview list animates bounds changes (other animatable properties - // never change). - mirror_container_->layer()->SetAnimator( - ui::LayerAnimator::CreateImplicitAnimator()); - // The selection highlight also animates all bounds changes and never - // changes other animatable properties. - highlight_view_->layer()->SetAnimator( - ui::LayerAnimator::CreateImplicitAnimator()); - } - } - - void OnPaintBackground(gfx::Canvas* canvas) override { - // We can't set a bg on the mirror container itself because the highlight - // view needs to be on top of the bg but behind the target windows. - const gfx::RectF shield_bounds(mirror_container_->bounds()); - cc::PaintFlags flags; - flags.setColor(SkColorSetA(SK_ColorBLACK, 0xE6)); - flags.setStyle(cc::PaintFlags::kFill_Style); - float corner_radius = 0.f; - if (shield_bounds.width() < width()) { - flags.setAntiAlias(true); - corner_radius = kBackgroundCornerRadius; - } - canvas->DrawRoundRect(shield_bounds, corner_radius, flags); - } - - View* GetInitiallyFocusedView() override { - return window_view_map_[target_window_]; - } - - WmWindow* target_window() { return target_window_; } - - private: - std::map<WmWindow*, views::View*> window_view_map_; - views::View* mirror_container_; - views::View* highlight_view_; - WmWindow* target_window_; - - DISALLOW_COPY_AND_ASSIGN(WindowCycleView); -}; - -WindowCycleList::WindowCycleList(const WindowList& windows) - : windows_(windows), - screen_observer_(this) { - if (!ShouldShowUi()) - WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(true); - - for (WmWindow* window : windows_) - window->aura_window()->AddObserver(this); - - if (ShouldShowUi()) { - if (g_disable_initial_delay) { - InitWindowCycleView(); - } else { - show_ui_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), - this, &WindowCycleList::InitWindowCycleView); - } - } -} - -WindowCycleList::~WindowCycleList() { - if (!ShouldShowUi()) - WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(false); - - for (WmWindow* window : windows_) - window->aura_window()->RemoveObserver(this); - - if (!windows_.empty() && user_did_accept_) { - WmWindow* target_window = windows_[current_index_]; - target_window->Show(); - target_window->GetWindowState()->Activate(); - } - - if (cycle_ui_widget_) - cycle_ui_widget_->Close(); - - // |this| is responsible for notifying |cycle_view_| when windows are - // destroyed. Since |this| is going away, clobber |cycle_view_|. Otherwise - // there will be a race where a window closes after now but before the - // Widget::Close() call above actually destroys |cycle_view_|. See - // crbug.com/681207 - if (cycle_view_) - cycle_view_->DestroyContents(); -} - -void WindowCycleList::Step(WindowCycleController::Direction direction) { - if (windows_.empty()) - return; - - // When there is only one window, we should give feedback to the user. If the - // window is minimized, we should also show it. - if (windows_.size() == 1) { - windows_[0]->Animate(::wm::WINDOW_ANIMATION_TYPE_BOUNCE); - windows_[0]->Show(); - windows_[0]->GetWindowState()->Activate(); - return; - } - - DCHECK(static_cast<size_t>(current_index_) < windows_.size()); - - if (!cycle_view_ && current_index_ == 0) { - // Special case the situation where we're cycling forward but the MRU window - // is not active. This occurs when all windows are minimized. The starting - // window should be the first one rather than the second. - if (direction == WindowCycleController::FORWARD && !windows_[0]->IsActive()) - current_index_ = -1; - } - - // We're in a valid cycle, so step forward or backward. - current_index_ += direction == WindowCycleController::FORWARD ? 1 : -1; - - // Wrap to window list size. - current_index_ = (current_index_ + windows_.size()) % windows_.size(); - DCHECK(windows_[current_index_]); - - if (ShouldShowUi()) { - if (current_index_ > 1) - InitWindowCycleView(); - - if (cycle_view_) - cycle_view_->SetTargetWindow(windows_[current_index_]); - } -} - -// static -void WindowCycleList::DisableInitialDelayForTesting() { - g_disable_initial_delay = true; -} - -void WindowCycleList::OnWindowDestroying(aura::Window* window) { - window->RemoveObserver(this); - - WindowList::iterator i = - std::find(windows_.begin(), windows_.end(), WmWindow::Get(window)); - // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed. - CHECK(i != windows_.end()); - int removed_index = static_cast<int>(i - windows_.begin()); - windows_.erase(i); - if (current_index_ > removed_index || - current_index_ == static_cast<int>(windows_.size())) { - current_index_--; - } - - if (cycle_view_) { - WmWindow* new_target_window = - windows_.empty() ? nullptr : windows_[current_index_]; - cycle_view_->HandleWindowDestruction(WmWindow::Get(window), - new_target_window); - if (windows_.empty()) { - // This deletes us. - WmShell::Get()->window_cycle_controller()->CancelCycling(); - return; - } - } -} - -void WindowCycleList::OnDisplayAdded(const display::Display& new_display) {} - -void WindowCycleList::OnDisplayRemoved(const display::Display& old_display) {} - -void WindowCycleList::OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) { - if (cycle_ui_widget_ && - display.id() == - display::Screen::GetScreen() - ->GetDisplayNearestWindow(cycle_ui_widget_->GetNativeView()) - .id() && - (changed_metrics & (DISPLAY_METRIC_BOUNDS | DISPLAY_METRIC_ROTATION))) { - WmShell::Get()->window_cycle_controller()->CancelCycling(); - // |this| is deleted. - return; - } -} - -bool WindowCycleList::ShouldShowUi() { - return windows_.size() > 1; -} - -void WindowCycleList::InitWindowCycleView() { - if (cycle_view_) - return; - - cycle_view_ = new WindowCycleView(windows_); - cycle_view_->SetTargetWindow(windows_[current_index_]); - - views::Widget* widget = new views::Widget; - views::Widget::InitParams params; - params.delegate = cycle_view_; - params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.accept_events = true; - params.name = "WindowCycleList (Alt+Tab)"; - // TODO(estade): make sure nothing untoward happens when the lock screen - // or a system modal dialog is shown. - WmWindow* root_window = WmShell::Get()->GetRootWindowForNewWindows(); - root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - widget, kShellWindowId_OverlayContainer, ¶ms); - gfx::Rect widget_rect = root_window->GetDisplayNearestWindow().bounds(); - const int widget_height = cycle_view_->GetPreferredSize().height(); - widget_rect.set_y(widget_rect.y() + - (widget_rect.height() - widget_height) / 2); - widget_rect.set_height(widget_height); - params.bounds = widget_rect; - widget->Init(params); - - screen_observer_.Add(display::Screen::GetScreen()); - widget->Show(); - cycle_ui_widget_ = widget; -} - -} // namespace ash
diff --git a/ash/wm/window_cycle_list.h b/ash/wm/window_cycle_list.h deleted file mode 100644 index bbc06481..0000000 --- a/ash/wm/window_cycle_list.h +++ /dev/null
@@ -1,110 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_CYCLE_LIST_H_ -#define ASH_WM_WINDOW_CYCLE_LIST_H_ - -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "ash/wm/window_cycle_controller.h" -#include "base/macros.h" -#include "base/scoped_observer.h" -#include "base/timer/timer.h" -#include "ui/aura/window_observer.h" -#include "ui/display/display_observer.h" - -namespace display { -class Screen; -} - -namespace views { -class Widget; -} - -namespace ash { - -class WindowCycleView; - -// Tracks a set of Windows that can be stepped through. This class is used by -// the WindowCycleController. -class ASH_EXPORT WindowCycleList : public aura::WindowObserver, - public display::DisplayObserver { - public: - using WindowList = std::vector<WmWindow*>; - - explicit WindowCycleList(const WindowList& windows); - ~WindowCycleList() override; - - bool empty() const { return windows_.empty(); } - - // Cycles to the next or previous window based on |direction|. - void Step(WindowCycleController::Direction direction); - - int current_index() const { return current_index_; } - - void set_user_did_accept(bool user_did_accept) { - user_did_accept_ = user_did_accept; - } - - private: - friend class WindowCycleControllerTest; - - static void DisableInitialDelayForTesting(); - const views::Widget* widget() const { return cycle_ui_widget_; } - - const WindowList& windows() const { return windows_; } - - // aura::WindowObserver overrides: - // There is a chance a window is destroyed, for example by JS code. We need to - // take care of that even if it is not intended for the user to close a window - // while window cycling. - void OnWindowDestroying(aura::Window* window) override; - - // display::DisplayObserver overrides: - void OnDisplayAdded(const display::Display& new_display) override; - void OnDisplayRemoved(const display::Display& old_display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) override; - - // Returns true if the window list overlay should be shown. - bool ShouldShowUi(); - - // Initializes and shows |cycle_view_|. - void InitWindowCycleView(); - - // List of weak pointers to windows to use while cycling with the keyboard. - // List is built when the user initiates the gesture (i.e. hits alt-tab the - // first time) and is emptied when the gesture is complete (i.e. releases the - // alt key). - WindowList windows_; - - // Current position in the |windows_|. Can be used to query selection depth, - // i.e., the position of an active window in a global MRU ordering. - int current_index_ = 0; - - // True if the user accepted the window switch (as opposed to cancelling or - // interrupting the interaction). - bool user_did_accept_ = false; - - // The top level View for the window cycle UI. May be null if the UI is not - // showing. - WindowCycleView* cycle_view_ = nullptr; - - // The widget that hosts the window cycle UI. - views::Widget* cycle_ui_widget_ = nullptr; - - // The window list will dismiss if the display metrics change. - ScopedObserver<display::Screen, display::DisplayObserver> screen_observer_; - - // A timer to delay showing the UI. Quick Alt+Tab should not flash a UI. - base::OneShotTimer show_ui_timer_; - - DISALLOW_COPY_AND_ASSIGN(WindowCycleList); -}; - -} // namespace ash - -#endif // ASH_WM_WINDOW_CYCLE_LIST_H_
diff --git a/ash/wm/window_dimmer.cc b/ash/wm/window_dimmer.cc deleted file mode 100644 index b43c2a83..0000000 --- a/ash/wm/window_dimmer.cc +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_dimmer.h" - -#include <memory> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "base/time/time.h" -#include "ui/aura/window.h" -#include "ui/compositor/layer.h" -#include "ui/wm/core/window_animations.h" - -namespace ash { -namespace { - -const int kDefaultDimAnimationDurationMs = 200; - -const float kDefaultDimOpacity = 0.5f; - -} // namespace - -WindowDimmer::WindowDimmer(WmWindow* parent) - : parent_(parent), - window_(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, - ui::LAYER_SOLID_COLOR)) { - window_->SetVisibilityChangesAnimated(); - window_->SetVisibilityAnimationType( - ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); - window_->SetVisibilityAnimationDuration( - base::TimeDelta::FromMilliseconds(kDefaultDimAnimationDurationMs)); - window_->aura_window()->AddObserver(this); - - SetDimOpacity(kDefaultDimOpacity); - - parent->AddChild(window_); - parent->aura_window()->AddObserver(this); - parent->StackChildAtTop(window_); - - window_->SetBounds(gfx::Rect(parent_->GetBounds().size())); -} - -WindowDimmer::~WindowDimmer() { - if (parent_) - parent_->aura_window()->RemoveObserver(this); - if (window_) { - window_->aura_window()->RemoveObserver(this); - window_->Destroy(); - } -} - -void WindowDimmer::SetDimOpacity(float target_opacity) { - DCHECK(window_); - window_->GetLayer()->SetColor( - SkColorSetA(SK_ColorBLACK, 255 * target_opacity)); -} - -void WindowDimmer::OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - if (WmWindow::Get(window) == parent_) - window_->SetBounds(gfx::Rect(new_bounds.size())); -} - -void WindowDimmer::OnWindowDestroying(aura::Window* window) { - if (WmWindow::Get(window) == parent_) { - parent_->aura_window()->RemoveObserver(this); - parent_ = nullptr; - } else { - DCHECK_EQ(window_, WmWindow::Get(window)); - window_->aura_window()->RemoveObserver(this); - window_ = nullptr; - } -} - -void WindowDimmer::OnWindowHierarchyChanging( - const HierarchyChangeParams& params) { - if (WmWindow::Get(params.receiver) == window_ && - params.target == params.receiver) { - // This may happen on a display change or some unexpected condition. Hide - // the window to ensure it isn't obscuring the wrong thing. - window_->Hide(); - } -} - -} // namespace ash
diff --git a/ash/wm/window_mirror_view.cc b/ash/wm/window_mirror_view.cc index 16f19bf..94dd847 100644 --- a/ash/wm/window_mirror_view.cc +++ b/ash/wm/window_mirror_view.cc
@@ -4,8 +4,8 @@ #include "ash/wm/window_mirror_view.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h"
diff --git a/ash/wm/window_parenting_utils.cc b/ash/wm/window_parenting_utils.cc deleted file mode 100644 index edf4c835..0000000 --- a/ash/wm/window_parenting_utils.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_parenting_utils.h" - -#include "ash/common/wm_window.h" - -namespace ash { -namespace wm { - -void ReparentChildWithTransientChildren(WmWindow* child, - WmWindow* old_parent, - WmWindow* new_parent) { - if (child->GetParent() == old_parent) - new_parent->AddChild(child); - ReparentTransientChildrenOfChild(child, old_parent, new_parent); -} - -void ReparentTransientChildrenOfChild(WmWindow* child, - WmWindow* old_parent, - WmWindow* new_parent) { - for (WmWindow* transient_child : child->GetTransientChildren()) - ReparentChildWithTransientChildren(transient_child, old_parent, new_parent); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/window_parenting_utils.h b/ash/wm/window_parenting_utils.h deleted file mode 100644 index 86f5f8b..0000000 --- a/ash/wm/window_parenting_utils.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_PARENTING_UTILS_H_ -#define ASH_WM_WINDOW_PARENTING_UTILS_H_ - -namespace ash { - -class WmWindow; - -namespace wm { - -// Changes the parent of a |child| and all its transient children that are -// themselves children of |old_parent| to |new_parent|. -void ReparentChildWithTransientChildren(WmWindow* child, - WmWindow* old_parent, - WmWindow* new_parent); - -// Changes the parent of all transient children of a |child| to |new_parent|. -// Does not change parent of the transient children that are not themselves -// children of |old_parent|. -void ReparentTransientChildrenOfChild(WmWindow* child, - WmWindow* old_parent, - WmWindow* new_parent); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_PARENTING_UTILS_H_
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc deleted file mode 100644 index b58b153..0000000 --- a/ash/wm/window_positioner.cc +++ /dev/null
@@ -1,564 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_positioner.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_screen_util.h" -#include "ui/compositor/layer.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/insets.h" - -namespace ash { - -const int WindowPositioner::kMinimumWindowOffset = 32; - -// The number of pixels which are kept free top, left and right when a window -// gets positioned to its default location. -// static -const int WindowPositioner::kDesktopBorderSize = 16; - -// Maximum width of a window even if there is more room on the desktop. -// static -const int WindowPositioner::kMaximumWindowWidth = 1100; - -namespace { - -// When a window gets opened in default mode and the screen is less than or -// equal to this width, the window will get opened in maximized mode. This value -// can be reduced to a "tame" number if the feature is disabled. -const int kForceMaximizeWidthLimit = 1366; - -// The time in milliseconds which should be used to visually move a window -// through an automatic "intelligent" window management option. -const int kWindowAutoMoveDurationMS = 125; - -// If set to true all window repositioning actions will be ignored. Set through -// WindowPositioner::SetIgnoreActivations(). -static bool disable_auto_positioning = false; - -// If set to true, by default the first window in ASH will be maximized. -static bool maximize_first_window = false; - -// Check if any management should be performed (with a given |window|). -bool UseAutoWindowManager(const WmWindow* window) { - if (disable_auto_positioning) - return false; - const wm::WindowState* window_state = window->GetWindowState(); - return !window_state->is_dragged() && window_state->window_position_managed(); -} - -// Check if a given |window| can be managed. This includes that its -// state is not minimized/maximized/fullscreen/the user has changed -// its size by hand already. It furthermore checks for the -// WindowIsManaged status. -bool WindowPositionCanBeManaged(const WmWindow* window) { - if (disable_auto_positioning) - return false; - const wm::WindowState* window_state = window->GetWindowState(); - return window_state->window_position_managed() && - !window_state->IsMinimized() && !window_state->IsMaximized() && - !window_state->IsFullscreen() && !window_state->IsPinned() && - !window_state->bounds_changed_by_user(); -} - -// Move the given |bounds| on the available |work_area| in the direction -// indicated by |move_right|. If |move_right| is true, the rectangle gets moved -// to the right edge, otherwise to the left one. -bool MoveRectToOneSide(const gfx::Rect& work_area, - bool move_right, - gfx::Rect* bounds) { - if (move_right) { - if (work_area.right() > bounds->right()) { - bounds->set_x(work_area.right() - bounds->width()); - return true; - } - } else { - if (work_area.x() < bounds->x()) { - bounds->set_x(work_area.x()); - return true; - } - } - return false; -} - -// Move a |window| to new |bounds|. Animate if desired by user. -// Moves the transient children of the |window| as well by the same |offset| as -// the parent |window|. -void SetBoundsAndOffsetTransientChildren(WmWindow* window, - const gfx::Rect& bounds, - const gfx::Rect& work_area, - const gfx::Vector2d& offset) { - std::vector<WmWindow*> transient_children = window->GetTransientChildren(); - for (WmWindow* transient_child : transient_children) { - gfx::Rect child_bounds = transient_child->GetBounds(); - gfx::Rect new_child_bounds = child_bounds + offset; - if ((child_bounds.x() <= work_area.x() && - new_child_bounds.x() <= work_area.x()) || - (child_bounds.right() >= work_area.right() && - new_child_bounds.right() >= work_area.right())) { - continue; - } - if (new_child_bounds.right() > work_area.right()) - new_child_bounds.set_x(work_area.right() - bounds.width()); - else if (new_child_bounds.x() < work_area.x()) - new_child_bounds.set_x(work_area.x()); - SetBoundsAndOffsetTransientChildren(transient_child, new_child_bounds, - work_area, offset); - } - - window->SetBoundsWithTransitionDelay( - bounds, base::TimeDelta::FromMilliseconds(kWindowAutoMoveDurationMS)); -} - -// Move a |window| to new |bounds|. Animate if desired by user. -// Note: The function will do nothing if the bounds did not change. -void SetBoundsAnimated(WmWindow* window, - const gfx::Rect& bounds, - const gfx::Rect& work_area) { - gfx::Rect old_bounds = window->GetTargetBounds(); - if (bounds == old_bounds) - return; - gfx::Vector2d offset(bounds.origin() - old_bounds.origin()); - SetBoundsAndOffsetTransientChildren(window, bounds, work_area, offset); -} - -// Move |window| into the center of the screen - or restore it to the previous -// position. -void AutoPlaceSingleWindow(WmWindow* window, bool animated) { - gfx::Rect work_area = wm::GetDisplayWorkAreaBoundsInParent(window); - gfx::Rect bounds = window->GetBounds(); - const gfx::Rect* user_defined_area = - window->GetWindowState()->pre_auto_manage_window_bounds(); - if (user_defined_area) { - bounds = *user_defined_area; - wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area, &bounds); - } else { - // Center the window (only in x). - bounds.set_x(work_area.x() + (work_area.width() - bounds.width()) / 2); - } - - if (animated) - SetBoundsAnimated(window, bounds, work_area); - else - window->SetBounds(bounds); -} - -// Get the first open (non minimized) window which is on the screen defined. -WmWindow* GetReferenceWindow(const WmWindow* root_window, - const WmWindow* exclude, - bool* single_window) { - if (single_window) - *single_window = true; - // Get the active window. - WmWindow* active = root_window->GetShell()->GetActiveWindow(); - if (active && active->GetRootWindow() != root_window) - active = NULL; - - // Get a list of all windows. - const std::vector<WmWindow*> windows = root_window->GetShell() - ->mru_window_tracker() - ->BuildWindowListIgnoreModal(); - - if (windows.empty()) - return nullptr; - - int index = 0; - // Find the index of the current active window. - if (active) - index = std::find(windows.begin(), windows.end(), active) - windows.begin(); - - // Scan the cycle list backwards to see which is the second topmost window - // (and so on). Note that we might cycle a few indices twice if there is no - // suitable window. However - since the list is fairly small this should be - // very fast anyways. - WmWindow* found = nullptr; - for (int i = index + windows.size(); i >= 0; i--) { - WmWindow* window = windows[i % windows.size()]; - while (window->GetTransientParent()) - window = window->GetTransientParent(); - if (window != exclude && window->GetType() == ui::wm::WINDOW_TYPE_NORMAL && - window->GetRootWindow() == root_window && - window->GetTargetVisibility() && - window->GetWindowState()->window_position_managed()) { - if (found && found != window) { - // no need to check !single_window because the function must have - // been already returned in the "if (!single_window)" below. - *single_window = false; - return found; - } - found = window; - // If there is no need to check single window, return now. - if (!single_window) - return found; - } - } - return found; -} - -} // namespace - -// static -int WindowPositioner::GetForceMaximizedWidthLimit() { - return kForceMaximizeWidthLimit; -} - -// static -void WindowPositioner::GetBoundsAndShowStateForNewWindow( - const WmWindow* new_window, - bool is_saved_bounds, - ui::WindowShowState show_state_in, - gfx::Rect* bounds_in_out, - ui::WindowShowState* show_state_out) { - // Always open new window in the target display. - WmWindow* target = WmShell::Get()->GetRootWindowForNewWindows(); - - WmWindow* top_window = GetReferenceWindow(target, nullptr, nullptr); - // Our window should not have any impact if we are already on top. - if (top_window == new_window) - top_window = nullptr; - - // If there is no valid other window we take and adjust the passed coordinates - // and show state. - if (!top_window) { - gfx::Rect work_area = target->GetDisplayNearestWindow().work_area(); - - bounds_in_out->AdjustToFit(work_area); - // Use adjusted saved bounds, if there is one. - if (is_saved_bounds) - return; - - if (show_state_in == ui::SHOW_STATE_DEFAULT) { - const bool maximize_first_window_on_first_run = - target->GetShell()->IsForceMaximizeOnFirstRun(); - // We want to always open maximized on "small screens" or when policy - // tells us to. - const bool set_maximized = - maximize_first_window || - ((work_area.width() <= GetForceMaximizedWidthLimit() || - maximize_first_window_on_first_run) && - (!new_window || !new_window->GetWindowState()->IsFullscreen())); - - if (set_maximized) - *show_state_out = ui::SHOW_STATE_MAXIMIZED; - } - return; - } - - wm::WindowState* top_window_state = top_window->GetWindowState(); - bool maximized = top_window_state->IsMaximized(); - // We ignore the saved show state, but look instead for the top level - // window's show state. - if (show_state_in == ui::SHOW_STATE_DEFAULT) { - *show_state_out = - maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_DEFAULT; - } - - if (maximized || top_window_state->IsFullscreen()) { - bool has_restore_bounds = top_window_state->HasRestoreBounds(); - if (has_restore_bounds) { - // For a maximized/fullscreen window ignore the real bounds of - // the top level window and use its restore bounds - // instead. Offset the bounds to prevent the windows from - // overlapping exactly when restored. - *bounds_in_out = - top_window_state->GetRestoreBoundsInScreen() + - gfx::Vector2d(kMinimumWindowOffset, kMinimumWindowOffset); - } - if (is_saved_bounds || has_restore_bounds) { - gfx::Rect work_area = target->GetDisplayNearestWindow().work_area(); - bounds_in_out->AdjustToFit(work_area); - // Use adjusted saved bounds or restore bounds, if there is one. - return; - } - } - - // Use the size of the other window. The window's bound will be rearranged - // in ash::WorkspaceLayoutManager using this location. - *bounds_in_out = top_window->GetBoundsInScreen(); -} - -// static -void WindowPositioner::RearrangeVisibleWindowOnHideOrRemove( - const WmWindow* removed_window) { - if (!UseAutoWindowManager(removed_window)) - return; - // Find a single open browser window. - bool single_window; - WmWindow* other_shown_window = GetReferenceWindow( - removed_window->GetRootWindow(), removed_window, &single_window); - if (!other_shown_window || !single_window || - !WindowPositionCanBeManaged(other_shown_window)) - return; - AutoPlaceSingleWindow(other_shown_window, true); -} - -// static -bool WindowPositioner::DisableAutoPositioning(bool ignore) { - bool old_state = disable_auto_positioning; - disable_auto_positioning = ignore; - return old_state; -} - -// static -void WindowPositioner::RearrangeVisibleWindowOnShow(WmWindow* added_window) { - wm::WindowState* added_window_state = added_window->GetWindowState(); - if (!added_window->GetTargetVisibility()) - return; - - if (!UseAutoWindowManager(added_window) || - added_window_state->bounds_changed_by_user()) { - if (added_window_state->minimum_visibility()) { - // Guarantee minimum visibility within the work area. - gfx::Rect work_area = wm::GetDisplayWorkAreaBoundsInParent(added_window); - gfx::Rect bounds = added_window->GetBounds(); - gfx::Rect new_bounds = bounds; - wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area, &new_bounds); - if (new_bounds != bounds) - added_window->SetBounds(new_bounds); - } - return; - } - // Find a single open managed window. - bool single_window; - WmWindow* other_shown_window = GetReferenceWindow( - added_window->GetRootWindow(), added_window, &single_window); - - if (!other_shown_window) { - // It could be that this window is the first window joining the workspace. - if (!WindowPositionCanBeManaged(added_window) || other_shown_window) - return; - // Since we might be going from 0 to 1 window, we have to arrange the new - // window to a good default. - AutoPlaceSingleWindow(added_window, false); - return; - } - - gfx::Rect other_bounds = other_shown_window->GetBounds(); - gfx::Rect work_area = wm::GetDisplayWorkAreaBoundsInParent(added_window); - bool move_other_right = - other_bounds.CenterPoint().x() > work_area.x() + work_area.width() / 2; - - // Push the other window to the size only if there are two windows left. - if (single_window) { - // When going from one to two windows both windows loose their - // "positioned by user" flags. - added_window_state->set_bounds_changed_by_user(false); - wm::WindowState* other_window_state = other_shown_window->GetWindowState(); - other_window_state->set_bounds_changed_by_user(false); - - if (WindowPositionCanBeManaged(other_shown_window)) { - // Don't override pre auto managed bounds as the current bounds - // may not be original. - if (!other_window_state->pre_auto_manage_window_bounds()) - other_window_state->SetPreAutoManageWindowBounds(other_bounds); - - // Push away the other window after remembering its current position. - if (MoveRectToOneSide(work_area, move_other_right, &other_bounds)) - SetBoundsAnimated(other_shown_window, other_bounds, work_area); - } - } - - // Remember the current location of the window if it's new and push - // it also to the opposite location if needed. Since it is just - // being shown, we do not need to animate it. - gfx::Rect added_bounds = added_window->GetBounds(); - if (!added_window_state->pre_auto_manage_window_bounds()) - added_window_state->SetPreAutoManageWindowBounds(added_bounds); - if (MoveRectToOneSide(work_area, !move_other_right, &added_bounds)) - added_window->SetBounds(added_bounds); -} - -WindowPositioner::WindowPositioner(WmShell* shell) - : shell_(shell), - pop_position_offset_increment_x(0), - pop_position_offset_increment_y(0), - popup_position_offset_from_screen_corner_x(0), - popup_position_offset_from_screen_corner_y(0), - last_popup_position_x_(0), - last_popup_position_y_(0) {} - -WindowPositioner::~WindowPositioner() {} - -gfx::Rect WindowPositioner::GetDefaultWindowBounds( - const display::Display& display) { - const gfx::Rect work_area = display.work_area(); - // There should be a 'desktop' border around the window at the left and right - // side. - int default_width = work_area.width() - 2 * kDesktopBorderSize; - // There should also be a 'desktop' border around the window at the top. - // Since the workspace excludes the tray area we only need one border size. - int default_height = work_area.height() - kDesktopBorderSize; - int offset_x = kDesktopBorderSize; - if (default_width > kMaximumWindowWidth) { - // The window should get centered on the screen and not follow the grid. - offset_x = (work_area.width() - kMaximumWindowWidth) / 2; - default_width = kMaximumWindowWidth; - } - return gfx::Rect(work_area.x() + offset_x, work_area.y() + kDesktopBorderSize, - default_width, default_height); -} - -gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Rect& old_pos) { - int grid = kMinimumWindowOffset; - popup_position_offset_from_screen_corner_x = grid; - popup_position_offset_from_screen_corner_y = grid; - if (!pop_position_offset_increment_x) { - // When the popup position increment is 0, the last popup position - // was not yet initialized. - last_popup_position_x_ = popup_position_offset_from_screen_corner_x; - last_popup_position_y_ = popup_position_offset_from_screen_corner_y; - } - pop_position_offset_increment_x = grid; - pop_position_offset_increment_y = grid; - // We handle the Multi monitor support by retrieving the active window's - // work area. - WmWindow* window = shell_->GetActiveWindow(); - const gfx::Rect work_area = - window && window->IsVisible() - ? window->GetDisplayNearestWindow().work_area() - : display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); - // Only try to reposition the popup when it is not spanning the entire - // screen. - if ((old_pos.width() + popup_position_offset_from_screen_corner_x >= - work_area.width()) || - (old_pos.height() + popup_position_offset_from_screen_corner_y >= - work_area.height())) - return AlignPopupPosition(old_pos, work_area, grid); - const gfx::Rect result = SmartPopupPosition(old_pos, work_area, grid); - if (!result.IsEmpty()) - return AlignPopupPosition(result, work_area, grid); - return NormalPopupPosition(old_pos, work_area); -} - -// static -void WindowPositioner::SetMaximizeFirstWindow(bool maximize) { - maximize_first_window = maximize; -} - -gfx::Rect WindowPositioner::NormalPopupPosition(const gfx::Rect& old_pos, - const gfx::Rect& work_area) { - int w = old_pos.width(); - int h = old_pos.height(); - // Note: The 'last_popup_position' is checked and kept relative to the - // screen size. The offsetting will be done in the last step when the - // target rectangle gets returned. - bool reset = false; - if (last_popup_position_y_ + h > work_area.height() || - last_popup_position_x_ + w > work_area.width()) { - // Popup does not fit on screen. Reset to next diagonal row. - last_popup_position_x_ -= last_popup_position_y_ - - popup_position_offset_from_screen_corner_x - - pop_position_offset_increment_x; - last_popup_position_y_ = popup_position_offset_from_screen_corner_y; - reset = true; - } - if (last_popup_position_x_ + w > work_area.width()) { - // Start again over. - last_popup_position_x_ = popup_position_offset_from_screen_corner_x; - last_popup_position_y_ = popup_position_offset_from_screen_corner_y; - reset = true; - } - int x = last_popup_position_x_; - int y = last_popup_position_y_; - if (!reset) { - last_popup_position_x_ += pop_position_offset_increment_x; - last_popup_position_y_ += pop_position_offset_increment_y; - } - return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); -} - -gfx::Rect WindowPositioner::SmartPopupPosition(const gfx::Rect& old_pos, - const gfx::Rect& work_area, - int grid) { - const std::vector<WmWindow*> windows = - shell_->mru_window_tracker()->BuildWindowListIgnoreModal(); - - std::vector<const gfx::Rect*> regions; - // Process the window list and check if we can bail immediately. - for (size_t i = 0; i < windows.size(); i++) { - // We only include opaque and visible windows. - if (windows[i] && windows[i]->IsVisible() && windows[i]->GetLayer() && - (windows[i]->GetLayer()->fills_bounds_opaquely() || - windows[i]->GetLayer()->GetTargetOpacity() == 1.0)) { - wm::WindowState* window_state = windows[i]->GetWindowState(); - // When any window is maximized we cannot find any free space. - if (window_state->IsMaximizedOrFullscreenOrPinned()) - return gfx::Rect(0, 0, 0, 0); - if (window_state->IsNormalOrSnapped()) - regions.push_back(&windows[i]->GetBounds()); - } - } - - if (regions.empty()) - return gfx::Rect(0, 0, 0, 0); - - int w = old_pos.width(); - int h = old_pos.height(); - int x_end = work_area.width() / 2; - int x, x_increment; - // We parse for a proper location on the screen. We do this in two runs: - // The first run will start from the left, parsing down, skipping any - // overlapping windows it will encounter until the popup's height can not - // be served anymore. Then the next grid position to the right will be - // taken, and the same cycle starts again. This will be repeated until we - // hit the middle of the screen (or we find a suitable location). - // In the second run we parse beginning from the right corner downwards and - // then to the left. - // When no location was found, an empty rectangle will be returned. - for (int run = 0; run < 2; run++) { - if (run == 0) { // First run: Start left, parse right till mid screen. - x = 0; - x_increment = pop_position_offset_increment_x; - } else { // Second run: Start right, parse left till mid screen. - x = work_area.width() - w; - x_increment = -pop_position_offset_increment_x; - } - // Note: The passing (x,y,w,h) window is always relative to the work area's - // origin. - for (; x_increment > 0 ? (x < x_end) : (x > x_end); x += x_increment) { - int y = 0; - while (y + h <= work_area.height()) { - size_t i; - for (i = 0; i < regions.size(); i++) { - if (regions[i]->Intersects( - gfx::Rect(x + work_area.x(), y + work_area.y(), w, h))) { - y = regions[i]->bottom() - work_area.y(); - break; - } - } - if (i >= regions.size()) - return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h); - } - } - } - return gfx::Rect(0, 0, 0, 0); -} - -gfx::Rect WindowPositioner::AlignPopupPosition(const gfx::Rect& pos, - const gfx::Rect& work_area, - int grid) { - if (grid <= 1) - return pos; - - int x = pos.x() - (pos.x() - work_area.x()) % grid; - int y = pos.y() - (pos.y() - work_area.y()) % grid; - int w = pos.width(); - int h = pos.height(); - - // If the alignment was pushing the window out of the screen, we ignore the - // alignment for that call. - if (abs(pos.right() - work_area.right()) < grid) - x = work_area.right() - w; - if (abs(pos.bottom() - work_area.bottom()) < grid) - y = work_area.bottom() - h; - return gfx::Rect(x, y, w, h); -} - -} // namespace ash
diff --git a/ash/wm/window_positioner.h b/ash/wm/window_positioner.h deleted file mode 100644 index ade2c25a..0000000 --- a/ash/wm/window_positioner.h +++ /dev/null
@@ -1,131 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_POSITIONER_H_ -#define ASH_WM_WINDOW_POSITIONER_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/base/ui_base_types.h" - -namespace display { -class Display; -} - -namespace gfx { -class Rect; -} - -namespace ash { - -class WmShell; -class WmWindow; - -namespace test { -class WindowPositionerTest; -} - -// WindowPositioner is used by the browser to move new popups automatically to -// a usable position on the closest work area (of the active window). -class ASH_EXPORT WindowPositioner { - public: - // When the screen resolution width is smaller then this size, The algorithm - // will default to maximized. - static int GetForceMaximizedWidthLimit(); - - // The number of pixels which are kept free top, left and right when a window - // gets positioned to its default location. - static const int kDesktopBorderSize; - - // Maximum width of a window even if there is more room on the desktop. - static const int kMaximumWindowWidth; - - // Computes and returns the bounds and show state for new window - // based on the parameter passed AND existing windows. |window| is - // the one this function will generate a bounds for and used to - // exclude the self window in making decision how to position the - // window. |window| can be (and in most case) NULL. - // |is_saved_bounds| indicates the |bounds_in_out| is the saved - // bounds. - static void GetBoundsAndShowStateForNewWindow( - const WmWindow* new_window, - bool is_saved_bounds, - ui::WindowShowState show_state_in, - gfx::Rect* bounds_in_out, - ui::WindowShowState* show_state_out); - - // Returns the default bounds for a window to be created in the |display|. - static gfx::Rect GetDefaultWindowBounds(const display::Display& display); - - // Check if after removal or hide of the given |removed_window| an - // automated desktop location management can be performed and - // rearrange accordingly. - static void RearrangeVisibleWindowOnHideOrRemove( - const WmWindow* removed_window); - - // Turn the automatic positioning logic temporarily off. Returns the previous - // state. - static bool DisableAutoPositioning(bool ignore); - - // Check if after insertion or showing of the given |added_window| - // an automated desktop location management can be performed and - // rearrange accordingly. - static void RearrangeVisibleWindowOnShow(WmWindow* added_window); - - explicit WindowPositioner(WmShell* shell); - ~WindowPositioner(); - - // Find a suitable screen position for a popup window and return it. The - // passed input position is only used to retrieve the width and height. - // The position is determined on the left / right / top / bottom first. If - // no smart space is found, the position will follow the standard what other - // operating systems do (default cascading style). - gfx::Rect GetPopupPosition(const gfx::Rect& old_pos); - - // Accessor to set a flag indicating whether the first window in ASH should - // be maximized. - static void SetMaximizeFirstWindow(bool maximize); - - protected: - friend class test::WindowPositionerTest; - - // Find a smart way to position the popup window. If there is no space this - // function will return an empty rectangle. - gfx::Rect SmartPopupPosition(const gfx::Rect& old_pos, - const gfx::Rect& work_area, - int grid); - - // Find the next available cascading popup position (on the given screen). - gfx::Rect NormalPopupPosition(const gfx::Rect& old_pos, - const gfx::Rect& work_area); - - // Align the location to the grid / snap to the right / bottom corner. - gfx::Rect AlignPopupPosition(const gfx::Rect& pos, - const gfx::Rect& work_area, - int grid); - - // Constant exposed for unittest. - static const int kMinimumWindowOffset; - - WmShell* shell_; - - // The offset in X and Y for the next popup which opens. - int pop_position_offset_increment_x; - int pop_position_offset_increment_y; - - // The position on the screen for the first popup which gets shown if no - // empty space can be found. - int popup_position_offset_from_screen_corner_x; - int popup_position_offset_from_screen_corner_y; - - // The last used position. - int last_popup_position_x_; - int last_popup_position_y_; - - DISALLOW_COPY_AND_ASSIGN(WindowPositioner); -}; - -} // namespace ash - -#endif // ASH_WM_WINDOW_POSITIONER_H_
diff --git a/ash/wm/window_positioner_unittest.cc b/ash/wm/window_positioner_unittest.cc index 7c5353b31..2bda5d7 100644 --- a/ash/wm/window_positioner_unittest.cc +++ b/ash/wm/window_positioner_unittest.cc
@@ -2,19 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/window_positioner.h" +#include "ash/common/wm/window_positioner.h" #include <string> #include "ash/common/scoped_root_window_for_new_windows.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/shell.h" #include "ash/shell/toplevel_window.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_shell_delegate.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/strings/string_number_conversions.h" #include "ui/display/screen.h"
diff --git a/ash/wm/window_positioning_utils.cc b/ash/wm/window_positioning_utils.cc deleted file mode 100644 index 84000a6..0000000 --- a/ash/wm/window_positioning_utils.cc +++ /dev/null
@@ -1,201 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_positioning_utils.h" - -#include <algorithm> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ash/shell.h" -#include "ash/wm/system_modal_container_layout_manager.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ui/aura/window_tracker.h" -#include "ui/display/display.h" -#include "ui/display/types/display_constants.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" - -namespace ash { -namespace wm { - -namespace { - -// Returns the default width of a snapped window. -int GetDefaultSnappedWindowWidth(WmWindow* window) { - const float kSnappedWidthWorkspaceRatio = 0.5f; - - int work_area_width = GetDisplayWorkAreaBoundsInParent(window).width(); - int min_width = window->GetMinimumSize().width(); - int ideal_width = - static_cast<int>(work_area_width * kSnappedWidthWorkspaceRatio); - return std::min(work_area_width, std::max(ideal_width, min_width)); -} - -// Return true if the window or one of its ancestor returns true from -// IsLockedToRoot(). -bool IsWindowOrAncestorLockedToRoot(const WmWindow* window) { - return window && (window->IsLockedToRoot() || - IsWindowOrAncestorLockedToRoot(window->GetParent())); -} - -// Move all transient children to |dst_root|, including the ones in -// the child windows and transient children of the transient children. -void MoveAllTransientChildrenToNewRoot(const display::Display& display, - WmWindow* window) { - WmWindow* dst_root = - Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow(); - for (WmWindow* transient_child : window->GetTransientChildren()) { - const int container_id = transient_child->GetParent()->GetShellWindowId(); - DCHECK_GE(container_id, 0); - WmWindow* container = dst_root->GetChildByShellWindowId(container_id); - const gfx::Rect transient_child_bounds_in_screen = - transient_child->GetBoundsInScreen(); - container->AddChild(transient_child); - transient_child->SetBoundsInScreen(transient_child_bounds_in_screen, - display); - - // Transient children may have transient children. - MoveAllTransientChildrenToNewRoot(display, transient_child); - } - // Move transient children of the child windows if any. - for (WmWindow* child : window->GetChildren()) - MoveAllTransientChildrenToNewRoot(display, child); -} - -} // namespace - -void AdjustBoundsSmallerThan(const gfx::Size& max_size, gfx::Rect* bounds) { - bounds->set_width(std::min(bounds->width(), max_size.width())); - bounds->set_height(std::min(bounds->height(), max_size.height())); -} - -void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& visible_area, - int min_width, - int min_height, - gfx::Rect* bounds) { - AdjustBoundsSmallerThan(visible_area.size(), bounds); - - min_width = std::min(min_width, visible_area.width()); - min_height = std::min(min_height, visible_area.height()); - - if (bounds->right() < visible_area.x() + min_width) { - bounds->set_x(visible_area.x() + std::min(bounds->width(), min_width) - - bounds->width()); - } else if (bounds->x() > visible_area.right() - min_width) { - bounds->set_x(visible_area.right() - std::min(bounds->width(), min_width)); - } - if (bounds->bottom() < visible_area.y() + min_height) { - bounds->set_y(visible_area.y() + std::min(bounds->height(), min_height) - - bounds->height()); - } else if (bounds->y() > visible_area.bottom() - min_height) { - bounds->set_y(visible_area.bottom() - - std::min(bounds->height(), min_height)); - } - if (bounds->y() < visible_area.y()) - bounds->set_y(visible_area.y()); -} - -void AdjustBoundsToEnsureMinimumWindowVisibility(const gfx::Rect& visible_area, - gfx::Rect* bounds) { - AdjustBoundsToEnsureWindowVisibility(visible_area, kMinimumOnScreenArea, - kMinimumOnScreenArea, bounds); -} - -gfx::Rect GetDefaultLeftSnappedWindowBoundsInParent(WmWindow* window) { - gfx::Rect work_area_in_parent(GetDisplayWorkAreaBoundsInParent(window)); - return gfx::Rect(work_area_in_parent.x(), work_area_in_parent.y(), - GetDefaultSnappedWindowWidth(window), - work_area_in_parent.height()); -} - -gfx::Rect GetDefaultRightSnappedWindowBoundsInParent(WmWindow* window) { - gfx::Rect work_area_in_parent(GetDisplayWorkAreaBoundsInParent(window)); - int width = GetDefaultSnappedWindowWidth(window); - return gfx::Rect(work_area_in_parent.right() - width, work_area_in_parent.y(), - width, work_area_in_parent.height()); -} - -void CenterWindow(WmWindow* window) { - WMEvent event(WM_EVENT_CENTER); - window->GetWindowState()->OnWMEvent(&event); -} - -void SetBoundsInScreen(WmWindow* window, - const gfx::Rect& bounds_in_screen, - const display::Display& display) { - DCHECK_NE(display::kInvalidDisplayId, display.id()); - // Don't move a window to other root window if: - // a) the window is a transient window. It moves when its - // transient parent moves. - // b) if the window or its ancestor has IsLockedToRoot(). It's intentionally - // kept in the same root window even if the bounds is outside of the - // display. - if (!window->GetTransientParent() && - !IsWindowOrAncestorLockedToRoot(window)) { - RootWindowController* dst_root_window_controller = - Shell::GetRootWindowControllerWithDisplayId(display.id()); - DCHECK(dst_root_window_controller); - WmWindow* dst_root = dst_root_window_controller->GetWindow(); - DCHECK(dst_root); - WmWindow* dst_container = nullptr; - if (dst_root != window->GetRootWindow()) { - int container_id = window->GetParent()->GetShellWindowId(); - // All containers that uses screen coordinates must have valid window ids. - DCHECK_GE(container_id, 0); - // Don't move modal background. - if (!SystemModalContainerLayoutManager::IsModalBackground(window)) - dst_container = dst_root->GetChildByShellWindowId(container_id); - } - - if (dst_container && window->GetParent() != dst_container) { - WmWindow* focused = WmShell::Get()->GetFocusedWindow(); - WmWindow* active = WmShell::Get()->GetActiveWindow(); - - aura::WindowTracker tracker; - if (focused) - tracker.Add(focused->aura_window()); - if (active && focused != active) - tracker.Add(active->aura_window()); - - gfx::Point origin = bounds_in_screen.origin(); - const gfx::Point display_origin = display.bounds().origin(); - origin.Offset(-display_origin.x(), -display_origin.y()); - gfx::Rect new_bounds = gfx::Rect(origin, bounds_in_screen.size()); - - // Set new bounds now so that the container's layout manager can adjust - // the bounds if necessary. - window->SetBounds(new_bounds); - - dst_container->AddChild(window); - - MoveAllTransientChildrenToNewRoot(display, window); - - // Restore focused/active window. - if (focused && tracker.Contains(focused->aura_window())) { - focused->SetFocused(); - WmShell::Get()->set_root_window_for_new_windows( - focused->GetRootWindow()); - } else if (active && tracker.Contains(active->aura_window())) { - active->Activate(); - } - // TODO(oshima): We should not have to update the bounds again - // below in theory, but we currently do need as there is a code - // that assumes that the bounds will never be overridden by the - // layout mananger. We should have more explicit control how - // constraints are applied by the layout manager. - } - } - gfx::Point origin(bounds_in_screen.origin()); - const gfx::Point display_origin = - window->GetDisplayNearestWindow().bounds().origin(); - origin.Offset(-display_origin.x(), -display_origin.y()); - window->SetBounds(gfx::Rect(origin, bounds_in_screen.size())); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/window_positioning_utils.h b/ash/wm/window_positioning_utils.h deleted file mode 100644 index d8cd861c7..0000000 --- a/ash/wm/window_positioning_utils.h +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_POSITIONING_UTILS_H_ -#define ASH_WM_WINDOW_POSITIONING_UTILS_H_ - -#include "ash/ash_export.h" - -namespace display { -class Display; -} - -namespace gfx { -class Rect; -class Size; -} - -namespace ash { - -class WmWindow; - -namespace wm { - -// We force at least this many DIPs for any window on the screen. -const int kMinimumOnScreenArea = 25; - -// Adjusts |bounds| so that the size does not exceed |max_size|. -ASH_EXPORT void AdjustBoundsSmallerThan(const gfx::Size& max_size, - gfx::Rect* bounds); - -// Move the given bounds inside the given |visible_area| in parent coordinates, -// including a safety margin given by |min_width| and |min_height|. -// This also ensures that the top of the bounds is visible. -ASH_EXPORT void AdjustBoundsToEnsureWindowVisibility( - const gfx::Rect& visible_area, - int min_width, - int min_height, - gfx::Rect* bounds); - -// Move the given bounds inside the given |visible_area| in parent coordinates, -// including a safety margin given by |kMinimumOnScreenArea|. -// This also ensures that the top of the bounds is visible. -ASH_EXPORT void AdjustBoundsToEnsureMinimumWindowVisibility( - const gfx::Rect& visible_area, - gfx::Rect* bounds); - -// Returns the bounds of a left snapped window with default width in parent -// coordinates. -ASH_EXPORT gfx::Rect GetDefaultLeftSnappedWindowBoundsInParent( - WmWindow* window); - -// Returns the bounds of a right snapped window with default width in parent -// coordinates. -ASH_EXPORT gfx::Rect GetDefaultRightSnappedWindowBoundsInParent( - WmWindow* window); - -// Moves the window to the center of the display. -ASH_EXPORT void CenterWindow(WmWindow* window); - -// Sets the bounds of |window| to |bounds_in_screen|. This may move |window| -// to |display| if necessary. -ASH_EXPORT void SetBoundsInScreen(WmWindow* window, - const gfx::Rect& bounds_in_screen, - const display::Display& display); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_POSITIONING_UTILS_H_
diff --git a/ash/wm/window_properties.cc b/ash/wm/window_properties.cc index dc0ac72..f6f8e41a2 100644 --- a/ash/wm/window_properties.cc +++ b/ash/wm/window_properties.cc
@@ -4,7 +4,7 @@ #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" +#include "ash/common/wm/window_state.h" DECLARE_UI_CLASS_PROPERTY_TYPE(ash::wm::WindowState*); DECLARE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, ash::WidgetCreationType);
diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h index 4733412..561f18b 100644 --- a/ash/wm/window_properties.h +++ b/ash/wm/window_properties.h
@@ -8,7 +8,7 @@ #include <stdint.h> #include "ash/ash_export.h" -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_types.h" #include "ui/base/class_property.h" #include "ui/base/ui_base_types.h" #include "ui/gfx/geometry/rect.h"
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc deleted file mode 100644 index 5aa2fd6..0000000 --- a/ash/wm/window_resizer.cc +++ /dev/null
@@ -1,329 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_resizer.h" - -#include "ash/common/wm_window.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/root_window_finder.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" -#include "ui/base/hit_test.h" -#include "ui/base/ui_base_types.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { - -namespace { - -// Returns true for resize components along the right edge, where a drag in -// positive x will make the window larger. -bool IsRightEdge(int window_component) { - return window_component == HTTOPRIGHT || window_component == HTRIGHT || - window_component == HTBOTTOMRIGHT || window_component == HTGROWBOX; -} - -} // namespace - -// static -const int WindowResizer::kBoundsChange_None = 0; -// static -const int WindowResizer::kBoundsChange_Repositions = 1; -// static -const int WindowResizer::kBoundsChange_Resizes = 2; - -// static -const int WindowResizer::kBoundsChangeDirection_None = 0; -// static -const int WindowResizer::kBoundsChangeDirection_Horizontal = 1; -// static -const int WindowResizer::kBoundsChangeDirection_Vertical = 2; - -WindowResizer::WindowResizer(wm::WindowState* window_state) - : window_state_(window_state) { - DCHECK(window_state_->drag_details()); -} - -WindowResizer::~WindowResizer() {} - -// static -int WindowResizer::GetBoundsChangeForWindowComponent(int component) { - int bounds_change = WindowResizer::kBoundsChange_None; - switch (component) { - case HTTOPLEFT: - case HTTOP: - case HTTOPRIGHT: - case HTLEFT: - case HTBOTTOMLEFT: - bounds_change |= WindowResizer::kBoundsChange_Repositions | - WindowResizer::kBoundsChange_Resizes; - break; - case HTCAPTION: - bounds_change |= WindowResizer::kBoundsChange_Repositions; - break; - case HTRIGHT: - case HTBOTTOMRIGHT: - case HTBOTTOM: - case HTGROWBOX: - bounds_change |= WindowResizer::kBoundsChange_Resizes; - break; - default: - break; - } - return bounds_change; -} - -// static -int WindowResizer::GetPositionChangeDirectionForWindowComponent( - int window_component) { - int pos_change_direction = WindowResizer::kBoundsChangeDirection_None; - switch (window_component) { - case HTTOPLEFT: - case HTBOTTOMRIGHT: - case HTGROWBOX: - case HTCAPTION: - pos_change_direction |= WindowResizer::kBoundsChangeDirection_Horizontal | - WindowResizer::kBoundsChangeDirection_Vertical; - break; - case HTTOP: - case HTTOPRIGHT: - case HTBOTTOM: - pos_change_direction |= WindowResizer::kBoundsChangeDirection_Vertical; - break; - case HTBOTTOMLEFT: - case HTRIGHT: - case HTLEFT: - pos_change_direction |= WindowResizer::kBoundsChangeDirection_Horizontal; - break; - default: - break; - } - return pos_change_direction; -} - -gfx::Rect WindowResizer::CalculateBoundsForDrag( - const gfx::Point& passed_location) { - if (!details().is_resizable) - return details().initial_bounds_in_parent; - - gfx::Point location = passed_location; - int delta_x = location.x() - details().initial_location_in_parent.x(); - int delta_y = location.y() - details().initial_location_in_parent.y(); - - AdjustDeltaForTouchResize(&delta_x, &delta_y); - - // The minimize size constraint may limit how much we change the window - // position. For example, dragging the left edge to the right should stop - // repositioning the window when the minimize size is reached. - gfx::Size size = GetSizeForDrag(&delta_x, &delta_y); - gfx::Point origin = GetOriginForDrag(delta_x, delta_y); - gfx::Rect new_bounds(origin, size); - - // Sizing has to keep the result on the screen. Note that this correction - // has to come first since it might have an impact on the origin as well as - // on the size. - if (details().bounds_change & kBoundsChange_Resizes) { - gfx::Rect work_area = GetTarget()->GetDisplayNearestWindow().work_area(); - DockedWindowLayoutManager* dock_layout = - DockedWindowLayoutManager::Get(GetTarget()); - - work_area.Union(dock_layout->docked_bounds()); - work_area = GetTarget()->GetParent()->ConvertRectFromScreen(work_area); - if (details().size_change_direction & kBoundsChangeDirection_Horizontal) { - if (IsRightEdge(details().window_component) && - new_bounds.right() < work_area.x() + wm::kMinimumOnScreenArea) { - int delta = - work_area.x() + wm::kMinimumOnScreenArea - new_bounds.right(); - new_bounds.set_width(new_bounds.width() + delta); - } else if (new_bounds.x() > - work_area.right() - wm::kMinimumOnScreenArea) { - int width = - new_bounds.right() - work_area.right() + wm::kMinimumOnScreenArea; - new_bounds.set_x(work_area.right() - wm::kMinimumOnScreenArea); - new_bounds.set_width(width); - } - } - if (details().size_change_direction & kBoundsChangeDirection_Vertical) { - if (!IsBottomEdge(details().window_component) && - new_bounds.y() > work_area.bottom() - wm::kMinimumOnScreenArea) { - int height = - new_bounds.bottom() - work_area.bottom() + wm::kMinimumOnScreenArea; - new_bounds.set_y(work_area.bottom() - wm::kMinimumOnScreenArea); - new_bounds.set_height(height); - } else if (details().window_component == HTBOTTOM || - details().window_component == HTBOTTOMRIGHT || - details().window_component == HTBOTTOMLEFT) { - // Update bottom edge to stay in the work area when we are resizing - // by dragging the bottom edge or corners. - if (new_bounds.bottom() > work_area.bottom()) - new_bounds.Inset(0, 0, 0, new_bounds.bottom() - work_area.bottom()); - } - } - if (details().bounds_change & kBoundsChange_Repositions && - new_bounds.y() < 0) { - int delta = new_bounds.y(); - new_bounds.set_y(0); - new_bounds.set_height(new_bounds.height() + delta); - } - } - - if (details().bounds_change & kBoundsChange_Repositions) { - // When we might want to reposition a window which is also restored to its - // previous size, to keep the cursor within the dragged window. - if (!details().restore_bounds.IsEmpty()) { - // However - it is not desirable to change the origin if the window would - // be still hit by the cursor. - if (details().initial_location_in_parent.x() > - details().initial_bounds_in_parent.x() + - details().restore_bounds.width()) - new_bounds.set_x(location.x() - details().restore_bounds.width() / 2); - } - - // Make sure that |new_bounds| doesn't leave any of the displays. Note that - // the |work_area| above isn't good for this check since it is the work area - // for the current display but the window can move to a different one. - WmWindow* parent = GetTarget()->GetParent(); - gfx::Point passed_location_in_screen( - parent->ConvertPointToScreen(passed_location)); - gfx::Rect near_passed_location(passed_location_in_screen, gfx::Size()); - // Use a pointer location (matching the logic in DragWindowResizer) to - // calculate the target display after the drag. - const display::Display& display = - display::Screen::GetScreen()->GetDisplayMatching(near_passed_location); - DockedWindowLayoutManager* dock_layout = DockedWindowLayoutManager::Get( - wm::GetRootWindowMatching(near_passed_location)); - - gfx::Rect screen_work_area = display.work_area(); - screen_work_area.Union(dock_layout->docked_bounds()); - screen_work_area.Inset(wm::kMinimumOnScreenArea, 0); - gfx::Rect new_bounds_in_screen = parent->ConvertRectToScreen(new_bounds); - if (!screen_work_area.Intersects(new_bounds_in_screen)) { - // Make sure that the x origin does not leave the current display. - new_bounds_in_screen.set_x(std::max( - screen_work_area.x() - new_bounds.width(), - std::min(screen_work_area.right(), new_bounds_in_screen.x()))); - new_bounds = parent->ConvertRectFromScreen(new_bounds_in_screen); - } - } - - return new_bounds; -} - -// static -bool WindowResizer::IsBottomEdge(int window_component) { - return window_component == HTBOTTOMLEFT || window_component == HTBOTTOM || - window_component == HTBOTTOMRIGHT || window_component == HTGROWBOX; -} - -void WindowResizer::AdjustDeltaForTouchResize(int* delta_x, int* delta_y) { - if (details().source != aura::client::WINDOW_MOVE_SOURCE_TOUCH || - !(details().bounds_change & kBoundsChange_Resizes)) - return; - - if (details().size_change_direction & kBoundsChangeDirection_Horizontal) { - if (IsRightEdge(details().window_component)) { - *delta_x += details().initial_location_in_parent.x() - - details().initial_bounds_in_parent.right(); - } else { - *delta_x += details().initial_location_in_parent.x() - - details().initial_bounds_in_parent.x(); - } - } - if (details().size_change_direction & kBoundsChangeDirection_Vertical) { - if (IsBottomEdge(details().window_component)) { - *delta_y += details().initial_location_in_parent.y() - - details().initial_bounds_in_parent.bottom(); - } else { - *delta_y += details().initial_location_in_parent.y() - - details().initial_bounds_in_parent.y(); - } - } -} - -gfx::Point WindowResizer::GetOriginForDrag(int delta_x, int delta_y) { - gfx::Point origin = details().initial_bounds_in_parent.origin(); - if (details().bounds_change & kBoundsChange_Repositions) { - int pos_change_direction = GetPositionChangeDirectionForWindowComponent( - details().window_component); - if (pos_change_direction & kBoundsChangeDirection_Horizontal) - origin.Offset(delta_x, 0); - if (pos_change_direction & kBoundsChangeDirection_Vertical) - origin.Offset(0, delta_y); - } - return origin; -} - -gfx::Size WindowResizer::GetSizeForDrag(int* delta_x, int* delta_y) { - gfx::Size size = details().initial_bounds_in_parent.size(); - if (details().bounds_change & kBoundsChange_Resizes) { - gfx::Size min_size = GetTarget()->GetMinimumSize(); - size.SetSize(GetWidthForDrag(min_size.width(), delta_x), - GetHeightForDrag(min_size.height(), delta_y)); - } else if (!details().restore_bounds.IsEmpty()) { - size = details().restore_bounds.size(); - } - return size; -} - -int WindowResizer::GetWidthForDrag(int min_width, int* delta_x) { - int width = details().initial_bounds_in_parent.width(); - if (details().size_change_direction & kBoundsChangeDirection_Horizontal) { - // Along the right edge, positive delta_x increases the window size. - int x_multiplier = IsRightEdge(details().window_component) ? 1 : -1; - width += x_multiplier * (*delta_x); - - // Ensure we don't shrink past the minimum width and clamp delta_x - // for the window origin computation. - if (width < min_width) { - width = min_width; - *delta_x = -x_multiplier * - (details().initial_bounds_in_parent.width() - min_width); - } - - // And don't let the window go bigger than the display. - int max_width = GetTarget()->GetDisplayNearestWindow().bounds().width(); - gfx::Size max_size = GetTarget()->GetMaximumSize(); - if (max_size.width() != 0) - max_width = std::min(max_width, max_size.width()); - if (width > max_width) { - width = max_width; - *delta_x = -x_multiplier * - (details().initial_bounds_in_parent.width() - max_width); - } - } - return width; -} - -int WindowResizer::GetHeightForDrag(int min_height, int* delta_y) { - int height = details().initial_bounds_in_parent.height(); - if (details().size_change_direction & kBoundsChangeDirection_Vertical) { - // Along the bottom edge, positive delta_y increases the window size. - int y_multiplier = IsBottomEdge(details().window_component) ? 1 : -1; - height += y_multiplier * (*delta_y); - - // Ensure we don't shrink past the minimum height and clamp delta_y - // for the window origin computation. - if (height < min_height) { - height = min_height; - *delta_y = -y_multiplier * - (details().initial_bounds_in_parent.height() - min_height); - } - - // And don't let the window go bigger than the display. - int max_height = GetTarget()->GetDisplayNearestWindow().bounds().height(); - gfx::Size max_size = GetTarget()->GetMaximumSize(); - if (max_size.height() != 0) - max_height = std::min(max_height, max_size.height()); - if (height > max_height) { - height = max_height; - *delta_y = -y_multiplier * - (details().initial_bounds_in_parent.height() - max_height); - } - } - return height; -} - -} // namespace ash
diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h deleted file mode 100644 index d0d8d8b..0000000 --- a/ash/wm/window_resizer.h +++ /dev/null
@@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_RESIZER_H_ -#define ASH_WM_WINDOW_RESIZER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/drag_details.h" -#include "ash/wm/window_state.h" -#include "base/macros.h" -#include "ui/wm/public/window_move_client.h" - -namespace gfx { -class Rect; -} - -namespace ash { - -class WmWindow; - -// WindowResizer is used by ToplevelWindowEventFilter to handle dragging, moving -// or resizing a window. All coordinates passed to this are in the parent -// windows coordinates. -class ASH_EXPORT WindowResizer { - public: - // Constants to identify the type of resize. - static const int kBoundsChange_None; - static const int kBoundsChange_Repositions; - static const int kBoundsChange_Resizes; - - // Used to indicate which direction the resize occurs in. - static const int kBoundsChangeDirection_None; - static const int kBoundsChangeDirection_Horizontal; - static const int kBoundsChangeDirection_Vertical; - - explicit WindowResizer(wm::WindowState* window_state); - virtual ~WindowResizer(); - - // Returns a bitmask of the kBoundsChange_ values. - static int GetBoundsChangeForWindowComponent(int component); - - // Returns a bitmask of the kBoundsChange_ values. - static int GetPositionChangeDirectionForWindowComponent(int window_component); - - // Invoked to drag/move/resize the window. |location| is in the coordinates - // of the window supplied to the constructor. |event_flags| is the event - // flags from the event. - virtual void Drag(const gfx::Point& location, int event_flags) = 0; - - // Invoked to complete the drag. - virtual void CompleteDrag() = 0; - - // Reverts the drag. - virtual void RevertDrag() = 0; - - // Returns the target window the resizer was created for. - WmWindow* GetTarget() const { - return window_state_ ? window_state_->window() : nullptr; - } - // See comment for |DragDetails::initial_location_in_parent|. - const gfx::Point& GetInitialLocation() const { - return window_state_->drag_details()->initial_location_in_parent; - } - - // Drag parameters established when drag starts. - const DragDetails& details() const { return *window_state_->drag_details(); } - - protected: - gfx::Rect CalculateBoundsForDrag(const gfx::Point& location); - - static bool IsBottomEdge(int component); - - // WindowState of the drag target. - wm::WindowState* window_state_; - - private: - // In case of touch resizing, adjusts deltas so that the border is positioned - // just under the touch point. - void AdjustDeltaForTouchResize(int* delta_x, int* delta_y); - - // Returns the new origin of the window. The arguments are the difference - // between the current location and the initial location. - gfx::Point GetOriginForDrag(int delta_x, int delta_y); - - // Returns the size of the window for the drag. - gfx::Size GetSizeForDrag(int* delta_x, int* delta_y); - - // Returns the width of the window. - int GetWidthForDrag(int min_width, int* delta_x); - - // Returns the height of the drag. - int GetHeightForDrag(int min_height, int* delta_y); - - DISALLOW_COPY_AND_ASSIGN(WindowResizer); -}; - -// Creates a WindowResizer for |window|. Returns a unique_ptr with null if -// |window| should not be resized nor dragged. -ASH_EXPORT std::unique_ptr<WindowResizer> CreateWindowResizer( - WmWindow* window, - const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source); - -} // namespace ash - -#endif // ASH_WM_WINDOW_RESIZER_H_
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc deleted file mode 100644 index 324c3111..0000000 --- a/ash/wm/window_state.cc +++ /dev/null
@@ -1,401 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_state.h" - -#include <utility> - -#include "ash/common/wm_window.h" -#include "ash/wm/default_state.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state_delegate.h" -#include "ash/wm/window_state_observer.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "base/auto_reset.h" - -namespace ash { -namespace wm { - -namespace { - -WMEventType WMEventTypeFromShowState(ui::WindowShowState requested_show_state) { - switch (requested_show_state) { - case ui::SHOW_STATE_DEFAULT: - case ui::SHOW_STATE_NORMAL: - return WM_EVENT_NORMAL; - case ui::SHOW_STATE_MINIMIZED: - return WM_EVENT_MINIMIZE; - case ui::SHOW_STATE_MAXIMIZED: - return WM_EVENT_MAXIMIZE; - case ui::SHOW_STATE_FULLSCREEN: - return WM_EVENT_FULLSCREEN; - case ui::SHOW_STATE_INACTIVE: - return WM_EVENT_SHOW_INACTIVE; - - // TODO(afakhry): Remove Docked Windows in M58. - case ui::SHOW_STATE_DOCKED: - return WM_EVENT_DOCK; - case ui::SHOW_STATE_END: - NOTREACHED() << "No WMEvent defined for the show state:" - << requested_show_state; - } - return WM_EVENT_NORMAL; -} - -} // namespace - -WindowState::~WindowState() {} - -bool WindowState::HasDelegate() const { - return !!delegate_; -} - -void WindowState::SetDelegate(std::unique_ptr<WindowStateDelegate> delegate) { - DCHECK(!delegate_.get()); - delegate_ = std::move(delegate); -} - -WindowStateType WindowState::GetStateType() const { - return current_state_->GetType(); -} - -bool WindowState::IsMinimized() const { - return GetStateType() == WINDOW_STATE_TYPE_MINIMIZED || - GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; -} - -bool WindowState::IsMaximized() const { - return GetStateType() == WINDOW_STATE_TYPE_MAXIMIZED; -} - -bool WindowState::IsFullscreen() const { - return GetStateType() == WINDOW_STATE_TYPE_FULLSCREEN; -} - -bool WindowState::IsMaximizedOrFullscreenOrPinned() const { - return GetStateType() == WINDOW_STATE_TYPE_MAXIMIZED || - GetStateType() == WINDOW_STATE_TYPE_FULLSCREEN || IsPinned(); -} - -bool WindowState::IsSnapped() const { - return GetStateType() == WINDOW_STATE_TYPE_LEFT_SNAPPED || - GetStateType() == WINDOW_STATE_TYPE_RIGHT_SNAPPED; -} - -bool WindowState::IsPinned() const { - return GetStateType() == WINDOW_STATE_TYPE_PINNED || - GetStateType() == WINDOW_STATE_TYPE_TRUSTED_PINNED; -} - -bool WindowState::IsTrustedPinned() const { - return GetStateType() == WINDOW_STATE_TYPE_TRUSTED_PINNED; -} - -bool WindowState::IsNormalStateType() const { - return GetStateType() == WINDOW_STATE_TYPE_NORMAL || - GetStateType() == WINDOW_STATE_TYPE_DEFAULT; -} - -bool WindowState::IsNormalOrSnapped() const { - return IsNormalStateType() || IsSnapped(); -} - -bool WindowState::IsActive() const { - return window_->IsActive(); -} - -bool WindowState::IsDocked() const { - return GetStateType() == WINDOW_STATE_TYPE_DOCKED || - GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED; -} - -bool WindowState::IsUserPositionable() const { - return (window_->GetType() == ui::wm::WINDOW_TYPE_NORMAL || - window_->GetType() == ui::wm::WINDOW_TYPE_PANEL); -} - -bool WindowState::CanMaximize() const { - // Window must allow maximization and have no maximum width or height. - if (!window_->CanMaximize()) - return false; - - if (!window_->HasNonClientArea()) - return true; - - gfx::Size max_size = window_->GetMaximumSize(); - return !max_size.width() && !max_size.height(); -} - -bool WindowState::CanMinimize() const { - return window_->CanMinimize(); -} - -bool WindowState::CanResize() const { - return window_->CanResize(); -} - -bool WindowState::CanActivate() const { - return window_->CanActivate(); -} - -bool WindowState::CanSnap() const { - if (!CanResize() || window_->GetType() == ui::wm::WINDOW_TYPE_PANEL || - window_->GetTransientParent()) { - return false; - } - // If a window cannot be maximized, assume it cannot snap either. - // TODO(oshima): We should probably snap if the maximum size is greater than - // the snapped size. - return CanMaximize(); -} - -bool WindowState::HasRestoreBounds() const { - return window_->HasRestoreBounds(); -} - -void WindowState::Maximize() { - window_->Maximize(); -} - -void WindowState::Minimize() { - window_->Minimize(); -} - -void WindowState::Unminimize() { - window_->Unminimize(); -} - -void WindowState::Activate() { - window_->Activate(); -} - -void WindowState::Deactivate() { - window_->Deactivate(); -} - -void WindowState::Restore() { - if (!IsNormalStateType()) { - const WMEvent event(WM_EVENT_NORMAL); - OnWMEvent(&event); - } -} - -void WindowState::DisableAlwaysOnTop(WmWindow* window_on_top) { - if (GetAlwaysOnTop()) { - // |window_| is hidden first to avoid canceling fullscreen mode when it is - // no longer always on top and gets added to default container. This avoids - // sending redundant OnFullscreenStateChanged to the layout manager. The - // |window_| visibility is restored after it no longer obscures the - // |window_on_top|. - bool visible = window_->IsVisible(); - if (visible) - window_->Hide(); - window_->SetAlwaysOnTop(false); - // Technically it is possible that a |window_| could make itself - // always_on_top really quickly. This is probably not a realistic case but - // check if the two windows are in the same container just in case. - if (window_on_top && window_on_top->GetParent() == window_->GetParent()) - window_->GetParent()->StackChildAbove(window_on_top, window_); - if (visible) - window_->Show(); - cached_always_on_top_ = true; - } -} - -void WindowState::RestoreAlwaysOnTop() { - if (delegate() && delegate()->RestoreAlwaysOnTop(this)) - return; - if (cached_always_on_top_) { - cached_always_on_top_ = false; - window_->SetAlwaysOnTop(true); - } -} - -void WindowState::OnWMEvent(const WMEvent* event) { - current_state_->OnWMEvent(this, event); -} - -void WindowState::SaveCurrentBoundsForRestore() { - gfx::Rect bounds_in_screen = - window_->GetParent()->ConvertRectToScreen(window_->GetBounds()); - SetRestoreBoundsInScreen(bounds_in_screen); -} - -gfx::Rect WindowState::GetRestoreBoundsInScreen() const { - return window_->GetRestoreBoundsInScreen(); -} - -gfx::Rect WindowState::GetRestoreBoundsInParent() const { - return window_->GetParent()->ConvertRectFromScreen( - GetRestoreBoundsInScreen()); -} - -void WindowState::SetRestoreBoundsInScreen(const gfx::Rect& bounds) { - window_->SetRestoreBoundsInScreen(bounds); -} - -void WindowState::SetRestoreBoundsInParent(const gfx::Rect& bounds) { - SetRestoreBoundsInScreen(window_->GetParent()->ConvertRectToScreen(bounds)); -} - -void WindowState::ClearRestoreBounds() { - window_->ClearRestoreBounds(); -} - -std::unique_ptr<WindowState::State> WindowState::SetStateObject( - std::unique_ptr<WindowState::State> new_state) { - current_state_->DetachState(this); - std::unique_ptr<WindowState::State> old_object = std::move(current_state_); - current_state_ = std::move(new_state); - current_state_->AttachState(this, old_object.get()); - return old_object; -} - -void WindowState::SetPreAutoManageWindowBounds(const gfx::Rect& bounds) { - pre_auto_manage_window_bounds_.reset(new gfx::Rect(bounds)); -} - -void WindowState::AddObserver(WindowStateObserver* observer) { - observer_list_.AddObserver(observer); -} - -void WindowState::RemoveObserver(WindowStateObserver* observer) { - observer_list_.RemoveObserver(observer); -} - -void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) { - bounds_changed_by_user_ = bounds_changed_by_user; - if (bounds_changed_by_user) - pre_auto_manage_window_bounds_.reset(); -} - -void WindowState::CreateDragDetails(const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source) { - drag_details_.reset( - new DragDetails(window_, point_in_parent, window_component, source)); -} - -void WindowState::DeleteDragDetails() { - drag_details_.reset(); -} - -void WindowState::SetAndClearRestoreBounds() { - DCHECK(HasRestoreBounds()); - SetBoundsInScreen(GetRestoreBoundsInScreen()); - ClearRestoreBounds(); -} - -void WindowState::OnWindowShowStateChanged() { - if (!ignore_property_change_) { - WMEvent event(WMEventTypeFromShowState(GetShowState())); - OnWMEvent(&event); - } -} - -WindowState::WindowState(WmWindow* window) - : window_(window), - window_position_managed_(false), - bounds_changed_by_user_(false), - ignored_by_shelf_(false), - can_consume_system_keys_(false), - unminimize_to_restore_bounds_(false), - in_immersive_fullscreen_(false), - hide_shelf_when_fullscreen_(true), - minimum_visibility_(false), - can_be_dragged_(true), - cached_always_on_top_(false), - ignore_property_change_(false), - current_state_(new DefaultState(ToWindowStateType(GetShowState()))) {} - -bool WindowState::GetAlwaysOnTop() const { - return window_->IsAlwaysOnTop(); -} - -ui::WindowShowState WindowState::GetShowState() const { - return window_->GetShowState(); -} - -void WindowState::SetBoundsInScreen(const gfx::Rect& bounds_in_screen) { - gfx::Rect bounds_in_parent = - window_->GetParent()->ConvertRectFromScreen(bounds_in_screen); - window_->SetBounds(bounds_in_parent); -} - -void WindowState::AdjustSnappedBounds(gfx::Rect* bounds) { - if (is_dragged() || !IsSnapped()) - return; - gfx::Rect maximized_bounds = GetMaximizedWindowBoundsInParent(window_); - if (GetStateType() == WINDOW_STATE_TYPE_LEFT_SNAPPED) - bounds->set_x(maximized_bounds.x()); - else if (GetStateType() == WINDOW_STATE_TYPE_RIGHT_SNAPPED) - bounds->set_x(maximized_bounds.right() - bounds->width()); - bounds->set_y(maximized_bounds.y()); - bounds->set_height(maximized_bounds.height()); -} - -void WindowState::UpdateWindowShowStateFromStateType() { - ui::WindowShowState new_window_state = - ToWindowShowState(current_state_->GetType()); - if (new_window_state != GetShowState()) { - base::AutoReset<bool> resetter(&ignore_property_change_, true); - window_->SetShowState(new_window_state); - } -} - -void WindowState::NotifyPreStateTypeChange( - WindowStateType old_window_state_type) { - for (auto& observer : observer_list_) - observer.OnPreWindowStateTypeChange(this, old_window_state_type); -} - -void WindowState::NotifyPostStateTypeChange( - WindowStateType old_window_state_type) { - for (auto& observer : observer_list_) - observer.OnPostWindowStateTypeChange(this, old_window_state_type); -} - -void WindowState::SetBoundsDirect(const gfx::Rect& bounds) { - gfx::Rect actual_new_bounds(bounds); - // Ensure we don't go smaller than our minimum bounds in "normal" window - // modes - if (window_->HasNonClientArea() && !IsMaximized() && !IsFullscreen()) { - // Get the minimum usable size of the minimum size and the screen size. - gfx::Size min_size = window_->GetMinimumSize(); - min_size.SetToMin(window_->GetDisplayNearestWindow().work_area().size()); - - actual_new_bounds.set_width( - std::max(min_size.width(), actual_new_bounds.width())); - actual_new_bounds.set_height( - std::max(min_size.height(), actual_new_bounds.height())); - } - window_->SetBoundsDirect(actual_new_bounds); -} - -void WindowState::SetBoundsConstrained(const gfx::Rect& bounds) { - gfx::Rect work_area_in_parent = GetDisplayWorkAreaBoundsInParent(window_); - gfx::Rect child_bounds(bounds); - AdjustBoundsSmallerThan(work_area_in_parent.size(), &child_bounds); - SetBoundsDirect(child_bounds); -} - -void WindowState::SetBoundsDirectAnimated(const gfx::Rect& bounds) { - window_->SetBoundsDirectAnimated(bounds); -} - -void WindowState::SetBoundsDirectCrossFade(const gfx::Rect& new_bounds) { - // Some test results in invoking CrossFadeToBounds when window is not visible. - // No animation is necessary in that case, thus just change the bounds and - // quit. - if (!window_->GetTargetVisibility()) { - SetBoundsConstrained(new_bounds); - return; - } - - window_->SetBoundsDirectCrossFade(new_bounds); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h deleted file mode 100644 index 37cf627..0000000 --- a/ash/wm/window_state.h +++ /dev/null
@@ -1,397 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_STATE_H_ -#define ASH_WM_WINDOW_STATE_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/drag_details.h" -#include "ash/wm/wm_types.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "ui/base/ui_base_types.h" - -namespace aura { -class Window; -} - -namespace gfx { -class Rect; -} - -namespace ash { -class LockWindowState; -class MaximizeModeWindowState; -class WmWindow; - -namespace wm { -class WindowStateDelegate; -class WindowStateObserver; -class WMEvent; - -// WindowState manages and defines ash specific window state and -// behavior. Ash specific per-window state (such as ones that controls -// window manager behavior) and ash specific window behavior (such as -// maximize, minimize, snap sizing etc) should be added here instead -// of defining separate functions (like |MaximizeWindow(aura::Window* -// window)|) or using aura Window property. -// The WindowState gets created when first accessed by -// |wm::GetWindowState|, and deleted when the window is deleted. -// Prefer using this class instead of passing aura::Window* around in -// ash code as this is often what you need to interact with, and -// accessing the window using |window()| is cheap. -class ASH_EXPORT WindowState { - public: - // A subclass of State class represents one of the window's states - // that corresponds to WindowStateType in Ash environment, e.g. - // maximized, minimized or side snapped, as subclass. - // Each subclass defines its own behavior and transition for each WMEvent. - class State { - public: - State() {} - virtual ~State() {} - - // Update WindowState based on |event|. - virtual void OnWMEvent(WindowState* window_state, const WMEvent* event) = 0; - - virtual WindowStateType GetType() const = 0; - - // Gets called when the state object became active and the managed window - // needs to be adjusted to the State's requirement. - // The passed |previous_state| may be used to properly implement state - // transitions such as bound animations from the previous state. - // Note: This only gets called when the state object gets changed. - virtual void AttachState(WindowState* window_state, - State* previous_state) = 0; - - // Gets called before the state objects gets deactivated / detached from the - // window, so that it can save the various states it is interested in. - // Note: This only gets called when the state object gets changed. - virtual void DetachState(WindowState* window_state) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(State); - }; - - // Call GetWindowState() to instantiate this class. - virtual ~WindowState(); - - WmWindow* window() { return window_; } - const WmWindow* window() const { return window_; } - - bool HasDelegate() const; - void SetDelegate(std::unique_ptr<WindowStateDelegate> delegate); - - // Returns the window's current ash state type. - // Refer to WindowStateType definition in wm_types.h as for why Ash - // has its own state type. - WindowStateType GetStateType() const; - - // Predicates to check window state. - bool IsMinimized() const; - bool IsMaximized() const; - bool IsFullscreen() const; - bool IsSnapped() const; - bool IsPinned() const; - bool IsTrustedPinned() const; - - // True if the window's state type is WINDOW_STATE_TYPE_MAXIMIZED, - // WINDOW_STATE_TYPE_FULLSCREEN or WINDOW_STATE_TYPE_PINNED. - bool IsMaximizedOrFullscreenOrPinned() const; - - // True if the window's state type is WINDOW_STATE_TYPE_NORMAL or - // WINDOW_STATE_TYPE_DEFAULT. - bool IsNormalStateType() const; - - bool IsNormalOrSnapped() const; - - bool IsActive() const; - bool IsDocked() const; - - // Returns true if the window's location can be controlled by the user. - bool IsUserPositionable() const; - - // Checks if the window can change its state accordingly. - bool CanMaximize() const; - bool CanMinimize() const; - bool CanResize() const; - bool CanSnap() const; - bool CanActivate() const; - - // Returns true if the window has restore bounds. - bool HasRestoreBounds() const; - - // These methods use aura::WindowProperty to change the window's state - // instead of using WMEvent directly. This is to use the same mechanism as - // what views::Widget is using. - void Maximize(); - void Minimize(); - void Unminimize(); - - void Activate(); - void Deactivate(); - - // Set the window state to normal. - // TODO(oshima): Change to use RESTORE event. - void Restore(); - - // Caches, then disables always on top state and then stacks |window_| below - // |window_on_top| if a |window_| is currently in always on top state. - void DisableAlwaysOnTop(WmWindow* window_on_top); - - // Restores always on top state that a window might have cached. - void RestoreAlwaysOnTop(); - - // Invoked when a WMevent occurs, which drives the internal - // state machine. - void OnWMEvent(const WMEvent* event); - - // TODO(oshima): Try hiding these methods and making them accessible only to - // state impl. State changes should happen through events (as much - // as possible). - - // Saves the current bounds to be used as a restore bounds. - void SaveCurrentBoundsForRestore(); - - // Same as |GetRestoreBoundsInScreen| except that it returns the - // bounds in the parent's coordinates. - gfx::Rect GetRestoreBoundsInParent() const; - - // Returns the restore bounds property on the window in the virtual screen - // coordinates. The bounds can be NULL if the bounds property does not - // exist for the window. The window owns the bounds object. - gfx::Rect GetRestoreBoundsInScreen() const; - - // Same as |SetRestoreBoundsInScreen| except that the bounds is in the - // parent's coordinates. - void SetRestoreBoundsInParent(const gfx::Rect& bounds_in_parent); - - // Sets the restore bounds property on the window in the virtual screen - // coordinates. Deletes existing bounds value if exists. - void SetRestoreBoundsInScreen(const gfx::Rect& bounds_in_screen); - - // Deletes and clears the restore bounds property on the window. - void ClearRestoreBounds(); - - // Replace the State object of a window with a state handler which can - // implement a new window manager type. The passed object will be owned - // by this object and the returned object will be owned by the caller. - std::unique_ptr<State> SetStateObject(std::unique_ptr<State> new_state); - - // True if the window should be unminimized to the restore bounds, as - // opposed to the window's current bounds. |unminimized_to_restore_bounds_| is - // reset to the default value after the window is unminimized. - bool unminimize_to_restore_bounds() const { - return unminimize_to_restore_bounds_; - } - void set_unminimize_to_restore_bounds(bool value) { - unminimize_to_restore_bounds_ = value; - } - - // Gets/sets whether the shelf should be hidden when this window is - // fullscreen. - bool hide_shelf_when_fullscreen() const { - return hide_shelf_when_fullscreen_; - } - - void set_hide_shelf_when_fullscreen(bool value) { - hide_shelf_when_fullscreen_ = value; - } - - // If the minimum visibility is true, ash will try to keep a - // minimum amount of the window is always visible on the work area - // when shown. - // TODO(oshima): Consolidate this and window_position_managed - // into single parameter to control the window placement. - bool minimum_visibility() const { return minimum_visibility_; } - void set_minimum_visibility(bool minimum_visibility) { - minimum_visibility_ = minimum_visibility; - } - - // Specifies if the window can be dragged by the user via the caption or not. - bool can_be_dragged() const { return can_be_dragged_; } - void set_can_be_dragged(bool can_be_dragged) { - can_be_dragged_ = can_be_dragged; - } - - // Gets/Sets the bounds of the window before it was moved by the auto window - // management. As long as it was not auto-managed, it will return NULL. - const gfx::Rect* pre_auto_manage_window_bounds() const { - return pre_auto_manage_window_bounds_.get(); - } - void SetPreAutoManageWindowBounds(const gfx::Rect& bounds); - - // Layout related properties - - void AddObserver(WindowStateObserver* observer); - void RemoveObserver(WindowStateObserver* observer); - - // Whether the window is being dragged. - bool is_dragged() const { return !!drag_details_; } - - // Whether or not the window's position can be managed by the - // auto management logic. - bool window_position_managed() const { return window_position_managed_; } - void set_window_position_managed(bool window_position_managed) { - window_position_managed_ = window_position_managed; - } - - // Whether or not the window's position or size was changed by a user. - bool bounds_changed_by_user() const { return bounds_changed_by_user_; } - void set_bounds_changed_by_user(bool bounds_changed_by_user); - - // True if the window is ignored by the shelf layout manager for - // purposes of darkening the shelf. - bool ignored_by_shelf() const { return ignored_by_shelf_; } - void set_ignored_by_shelf(bool ignored_by_shelf) { - ignored_by_shelf_ = ignored_by_shelf; - } - - // True if the window should be offered a chance to consume special system - // keys such as brightness, volume, etc. that are usually handled by the - // shell. - bool can_consume_system_keys() const { return can_consume_system_keys_; } - void set_can_consume_system_keys(bool can_consume_system_keys) { - can_consume_system_keys_ = can_consume_system_keys; - } - - // True if the window is in "immersive full screen mode" which is slightly - // different from the normal fullscreen mode by allowing the user to reveal - // the top portion of the window through a touch / mouse gesture. It might - // also allow the shelf to be shown in some situations. - bool in_immersive_fullscreen() const { return in_immersive_fullscreen_; } - void set_in_immersive_fullscreen(bool enable) { - in_immersive_fullscreen_ = enable; - } - - // True if the window should not adjust the window's bounds when - // virtual keyboard bounds changes. - // TODO(oshima): This is hack. Replace this with proper - // implementation based on EnsureCaretNotInRect. - bool ignore_keyboard_bounds_change() const { - return ignore_keyboard_bounds_change_; - } - void set_ignore_keyboard_bounds_change(bool ignore_keyboard_bounds_change) { - ignore_keyboard_bounds_change_ = ignore_keyboard_bounds_change; - } - - // True if the window's bounds can be updated using SET_BOUNDS event in - // maiximzed/fullscreen mode. - void set_allow_set_bounds_in_maximized(bool value) { - allow_set_bounds_in_maximized_ = value; - } - bool allow_set_bounds_in_maximized() const { - return allow_set_bounds_in_maximized_; - } - - // Creates and takes ownership of a pointer to DragDetails when resizing is - // active. This should be done before a resizer gets created. - void CreateDragDetails(const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source); - - // Deletes and clears a pointer to DragDetails. This should be done when the - // resizer gets destroyed. - void DeleteDragDetails(); - - // Sets the currently stored restore bounds and clears the restore bounds. - void SetAndClearRestoreBounds(); - - // Returns a pointer to DragDetails during drag operations. - const DragDetails* drag_details() const { return drag_details_.get(); } - DragDetails* drag_details() { return drag_details_.get(); } - - // Called from the associated WmWindow once the show state changes. - void OnWindowShowStateChanged(); - - protected: - explicit WindowState(WmWindow* window); - - private: - friend class DefaultState; - friend class ash::LockWindowState; - friend class ash::MaximizeModeWindowState; - FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeToBounds); - FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, - CrossFadeToBoundsFromTransform); - - WindowStateDelegate* delegate() { return delegate_.get(); } - - // Returns the window's current always_on_top state. - bool GetAlwaysOnTop() const; - - // Returns the window's current show state. - ui::WindowShowState GetShowState() const; - - // Sets the window's bounds in screen coordinates. - void SetBoundsInScreen(const gfx::Rect& bounds_in_screen); - - // Adjusts the |bounds| so that they are flush with the edge of the - // workspace if the window represented by |window_state| is side snapped. - void AdjustSnappedBounds(gfx::Rect* bounds); - - // Updates the window show state according to the current window state type. - // Note that this does not update the window bounds. - void UpdateWindowShowStateFromStateType(); - - void NotifyPreStateTypeChange(WindowStateType old_window_state_type); - void NotifyPostStateTypeChange(WindowStateType old_window_state_type); - - // Sets |bounds| as is and ensure the layer is aligned with pixel boundary. - void SetBoundsDirect(const gfx::Rect& bounds); - - // Sets the window's |bounds| with constraint where the size of the - // new bounds will not exceeds the size of the work area. - void SetBoundsConstrained(const gfx::Rect& bounds); - - // Sets the wndow's |bounds| and transitions to the new bounds with - // a scale animation. - void SetBoundsDirectAnimated(const gfx::Rect& bounds); - - // Sets the window's |bounds| and transition to the new bounds with - // a cross fade animation. - void SetBoundsDirectCrossFade(const gfx::Rect& bounds); - - // The owner of this window settings. - WmWindow* window_; - std::unique_ptr<WindowStateDelegate> delegate_; - - bool window_position_managed_; - bool bounds_changed_by_user_; - bool ignored_by_shelf_; - bool can_consume_system_keys_; - std::unique_ptr<DragDetails> drag_details_; - - bool unminimize_to_restore_bounds_; - bool in_immersive_fullscreen_; - bool ignore_keyboard_bounds_change_ = false; - bool hide_shelf_when_fullscreen_; - bool minimum_visibility_; - bool can_be_dragged_; - bool cached_always_on_top_; - bool allow_set_bounds_in_maximized_ = false; - - // A property to remember the window position which was set before the - // auto window position manager changed the window bounds, so that it can get - // restored when only this one window gets shown. - std::unique_ptr<gfx::Rect> pre_auto_manage_window_bounds_; - - base::ObserverList<WindowStateObserver> observer_list_; - - // True to ignore a property change event to avoid reentrance in - // UpdateWindowStateType() - bool ignore_property_change_; - - std::unique_ptr<State> current_state_; - - DISALLOW_COPY_AND_ASSIGN(WindowState); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_STATE_H_
diff --git a/ash/wm/window_state_aura.cc b/ash/wm/window_state_aura.cc index 4e3d923..c2ae3d6a 100644 --- a/ash/wm/window_state_aura.cc +++ b/ash/wm/window_state_aura.cc
@@ -4,9 +4,9 @@ #include "ash/wm/window_state_aura.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ui/aura/window.h"
diff --git a/ash/wm/window_state_delegate.cc b/ash/wm/window_state_delegate.cc deleted file mode 100644 index 5346b4b..0000000 --- a/ash/wm/window_state_delegate.cc +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_state_delegate.h" - -namespace ash { -namespace wm { - -WindowStateDelegate::WindowStateDelegate() {} - -WindowStateDelegate::~WindowStateDelegate() {} - -bool WindowStateDelegate::ToggleFullscreen(WindowState* window_state) { - return false; -} - -bool WindowStateDelegate::RestoreAlwaysOnTop(WindowState* window_state) { - return false; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/window_state_delegate.h b/ash/wm/window_state_delegate.h deleted file mode 100644 index 7912efe..0000000 --- a/ash/wm/window_state_delegate.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_STATE_DELEGATE_H_ -#define ASH_WM_WINDOW_STATE_DELEGATE_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" - -namespace ash { -namespace wm { -class WindowState; - -class ASH_EXPORT WindowStateDelegate { - public: - WindowStateDelegate(); - virtual ~WindowStateDelegate(); - - // Invoked when the user uses Shift+F4/F4 to toggle the window fullscreen - // state. If the window is not fullscreen and the window supports immersive - // fullscreen ToggleFullscreen() should put the window into immersive - // fullscreen instead of the default fullscreen type. The caller - // (ash::wm::WindowState) falls backs to the default implementation if this - // returns false. - virtual bool ToggleFullscreen(WindowState* window_state); - - // Invoked when workspace fullscreen state changes and a window may need to - // reassert its always on top state. Returns true if delegate has handled this - // and no additional work is needed, false otherwise. - virtual bool RestoreAlwaysOnTop(WindowState* window_state); - - private: - DISALLOW_COPY_AND_ASSIGN(WindowStateDelegate); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_STATE_DELEGATE_H_
diff --git a/ash/wm/window_state_observer.h b/ash/wm/window_state_observer.h deleted file mode 100644 index e18cb32..0000000 --- a/ash/wm/window_state_observer.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_STATE_OBSERVER_H_ -#define ASH_WM_WINDOW_STATE_OBSERVER_H_ - -#include "ash/ash_export.h" -#include "ash/wm/wm_types.h" - -namespace ash { -namespace wm { -class WindowState; - -class ASH_EXPORT WindowStateObserver { - public: - virtual ~WindowStateObserver() {} - - // Following observer methods are different from kWindowShowStatekey - // property change as they will be invoked when the window - // gets left/right maximized, and auto positioned. |old_type| is the value - // before the change. - - // Called after the window's state type is set to new type, but before - // the window's bounds has been updated for the new type. - // This is used to update the shell state such as work area so - // that the window can use the correct environment to update its bounds. - // TODO(oshima): Remove this once docked windows has its own state. - virtual void OnPreWindowStateTypeChange(WindowState* window_state, - WindowStateType old_type) {} - - // Called after the window's state has been updated. - // This is used to update the shell state that depends on the updated - // window bounds, such as shelf visibility. - virtual void OnPostWindowStateTypeChange(WindowState* window_state, - WindowStateType old_type) {} -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_STATE_OBSERVER_H_
diff --git a/ash/wm/window_state_unittest.cc b/ash/wm/window_state_unittest.cc index 6168dbab..b04883c 100644 --- a/ash/wm/window_state_unittest.cc +++ b/ash/wm/window_state_unittest.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/window_state.h" +#include "ash/common/wm/window_state.h" #include <utility> +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_util.h" +#include "ash/common/wm/wm_event.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/window_state_util.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "services/ui/public/interfaces/window_manager_constants.mojom.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/test/test_window_delegate.h"
diff --git a/ash/wm/window_state_util.cc b/ash/wm/window_state_util.cc deleted file mode 100644 index f83de561..0000000 --- a/ash/wm/window_state_util.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/window_state_util.h" - -#include "ash/common/wm_window.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_delegate.h" - -namespace ash { -namespace wm { - -void ToggleFullScreen(wm::WindowState* window_state, - WindowStateDelegate* delegate) { - // Window which cannot be maximized should not be full screen'ed. - // It can, however, be restored if it was full screen'ed. - bool is_fullscreen = window_state->IsFullscreen(); - if (!is_fullscreen && !window_state->CanMaximize()) - return; - - if (delegate && delegate->ToggleFullscreen(window_state)) - return; - window_state->window()->SetFullscreen(!is_fullscreen); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/window_state_util.h b/ash/wm/window_state_util.h deleted file mode 100644 index aa603de..0000000 --- a/ash/wm/window_state_util.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WINDOW_STATE_UTIL_H_ -#define ASH_WM_WINDOW_STATE_UTIL_H_ - -#include "ash/ash_export.h" - -namespace ash { -namespace wm { -class WindowState; -class WindowStateDelegate; - -// Toggle the full screen from inside a WindowState::State handler. -ASH_EXPORT void ToggleFullScreen(WindowState* window_state, - WindowStateDelegate* delegate); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WINDOW_STATE_UTIL_H_
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc index 5d833c7a..d4cf8ab 100644 --- a/ash/wm/window_util.cc +++ b/ash/wm/window_util.cc
@@ -7,15 +7,15 @@ #include <vector> #include "ash/common/ash_constants.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/aura/window_delegate.h"
diff --git a/ash/wm/window_util_unittest.cc b/ash/wm/window_util_unittest.cc index 3be9969..5811818 100644 --- a/ash/wm/window_util_unittest.cc +++ b/ash/wm/window_util_unittest.cc
@@ -4,10 +4,10 @@ #include "ash/wm/window_util.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/window.h" #include "ui/display/manager/display_manager.h"
diff --git a/ash/wm/wm_event.cc b/ash/wm/wm_event.cc deleted file mode 100644 index da5b77d..0000000 --- a/ash/wm/wm_event.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/wm_event.h" - -namespace ash { -namespace wm { - -WMEvent::WMEvent(WMEventType type) : type_(type) {} - -WMEvent::~WMEvent() {} - -SetBoundsEvent::SetBoundsEvent(WMEventType type, const gfx::Rect& bounds) - : WMEvent(type), requested_bounds_(bounds) {} - -SetBoundsEvent::~SetBoundsEvent() {} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/wm_event.h b/ash/wm/wm_event.h deleted file mode 100644 index c6b6f96..0000000 --- a/ash/wm/wm_event.h +++ /dev/null
@@ -1,129 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WM_EVENT_H_ -#define ASH_WM_WM_EVENT_H_ - -#include "ash/ash_export.h" -#include "ash/wm/wm_types.h" -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { -namespace wm { - -// WMEventType defines a set of operations that can change the -// window's state type and bounds. -enum WMEventType { - // Following events are the request to become corresponding state. - // Note that this does not mean the window will be in corresponding - // state and the request may not be fullfilled. - - // NORMAL is used as a restore operation with a few exceptions. - WM_EVENT_NORMAL, - WM_EVENT_MAXIMIZE, - WM_EVENT_MINIMIZE, - WM_EVENT_FULLSCREEN, - WM_EVENT_SNAP_LEFT, - WM_EVENT_SNAP_RIGHT, - WM_EVENT_DOCK, - - // A window is requested to be the given bounds. The request may or - // may not be fulfilled depending on the requested bounds and window's - // state. This will not change the window state type. - WM_EVENT_SET_BOUNDS, - - // Following events are compond events which may lead to different - // states depending on the current state. - - // A user requested to toggle maximized state by double clicking window - // header. - WM_EVENT_TOGGLE_MAXIMIZE_CAPTION, - - // A user requested to toggle maximized state using shortcut. - WM_EVENT_TOGGLE_MAXIMIZE, - - // A user requested to toggle vertical maximize by double clicking - // top/bottom edge. - WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE, - - // A user requested to toggle horizontal maximize by double clicking - // left/right edge. - WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE, - - // A user requested to toggle fullscreen state. - WM_EVENT_TOGGLE_FULLSCREEN, - - // A user requested a cycle of dock and snap left. - // The way this event is processed is the current window state is used as - // the starting state. Assuming normal window start state; if the window can - // be snapped left, snap it; otherwise progress to next state. If the window - // can be docked left, dock it; otherwise progress to next state. If the - // window can be restored; and this isn't the entry condition restore it; - // otherwise apply the bounce animation to the window. - WM_EVENT_CYCLE_SNAP_DOCK_LEFT, - - // A user requested a cycle of dock and snap right. - // See decription of WM_EVENT_CYCLE_SNAP_DOCK_LEFT. - WM_EVENT_CYCLE_SNAP_DOCK_RIGHT, - - // A user requested to center a window. - WM_EVENT_CENTER, - - // TODO(oshima): Investigate if this can be removed from ash. - // Widget requested to show in inactive state. - WM_EVENT_SHOW_INACTIVE, - - // Following events are generated when the workspace envrionment has changed. - // The window's state type will not be changed by these events. - - // The window is added to the workspace, either as a new window, due to - // display disconnection or dragging. - WM_EVENT_ADDED_TO_WORKSPACE, - - // Bounds of the display has changed. - WM_EVENT_DISPLAY_BOUNDS_CHANGED, - - // Bounds of the work area has changed. This will not occur when the work - // area has changed as a result of DISPLAY_BOUNDS_CHANGED. - WM_EVENT_WORKAREA_BOUNDS_CHANGED, - - // A user requested to pin a window. - WM_EVENT_PIN, - - // A user requested to pin a window for a trusted application. This is similar - // WM_EVENT_PIN but does not allow user to exit the mode by shortcut key. - WM_EVENT_TRUSTED_PIN, -}; - -class ASH_EXPORT WMEvent { - public: - explicit WMEvent(WMEventType type); - virtual ~WMEvent(); - - WMEventType type() const { return type_; } - - private: - WMEventType type_; - DISALLOW_COPY_AND_ASSIGN(WMEvent); -}; - -// An WMEvent to request new bounds for the window. -class ASH_EXPORT SetBoundsEvent : public WMEvent { - public: - SetBoundsEvent(WMEventType type, const gfx::Rect& requested_bounds); - ~SetBoundsEvent() override; - - const gfx::Rect& requested_bounds() const { return requested_bounds_; } - - private: - gfx::Rect requested_bounds_; - - DISALLOW_COPY_AND_ASSIGN(SetBoundsEvent); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WM_EVENT_H_
diff --git a/ash/wm/wm_screen_util.cc b/ash/wm/wm_screen_util.cc deleted file mode 100644 index 77ae246..0000000 --- a/ash/wm/wm_screen_util.cc +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/wm_screen_util.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/root_window_controller.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/size_conversions.h" - -namespace ash { -namespace wm { - -gfx::Rect GetDisplayWorkAreaBoundsInParent(WmWindow* window) { - display::Display display = window->GetDisplayNearestWindow(); - return window->GetParent()->ConvertRectFromScreen(display.work_area()); -} - -gfx::Rect GetDisplayBoundsInParent(WmWindow* window) { - display::Display display = window->GetDisplayNearestWindow(); - return window->GetParent()->ConvertRectFromScreen(display.bounds()); -} - -gfx::Rect GetMaximizedWindowBoundsInParent(WmWindow* window) { - if (window->GetRootWindowController()->HasShelf()) - return GetDisplayWorkAreaBoundsInParent(window); - - return GetDisplayBoundsInParent(window); -} - -gfx::Rect GetDisplayBoundsWithShelf(WmWindow* window) { - if (WmShell::Get()->IsInUnifiedMode()) { - // In unified desktop mode, there is only one shelf in the first display. - gfx::SizeF size(WmShell::Get()->GetFirstDisplay().size()); - float scale = window->GetRootWindow()->GetBounds().height() / size.height(); - size.Scale(scale, scale); - return gfx::Rect(gfx::ToCeiledSize(size)); - } - - return window->GetRootWindow()->GetBounds(); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/wm_screen_util.h b/ash/wm/wm_screen_util.h deleted file mode 100644 index 7d2c083..0000000 --- a/ash/wm/wm_screen_util.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WM_SCREEN_UTIL_H_ -#define ASH_WM_WM_SCREEN_UTIL_H_ - -#include "ash/ash_export.h" - -namespace gfx { -class Rect; -} - -namespace ash { - -class WmWindow; - -namespace wm { - -ASH_EXPORT gfx::Rect GetDisplayWorkAreaBoundsInParent(WmWindow* window); -ASH_EXPORT gfx::Rect GetDisplayBoundsInParent(WmWindow* window); -ASH_EXPORT gfx::Rect GetMaximizedWindowBoundsInParent(WmWindow* window); - -// Returns the bounds of the physical display containing the shelf for |window|. -// Physical displays can differ from logical displays in unified desktop mode. -// TODO(oshima): Consider using physical displays in window layout, instead of -// root windows, and only use logical display in display management code. -ASH_EXPORT gfx::Rect GetDisplayBoundsWithShelf(WmWindow* window); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WM_SCREEN_UTIL_H_
diff --git a/ash/wm/wm_snap_to_pixel_layout_manager.cc b/ash/wm/wm_snap_to_pixel_layout_manager.cc deleted file mode 100644 index 740a099..0000000 --- a/ash/wm/wm_snap_to_pixel_layout_manager.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/wm_snap_to_pixel_layout_manager.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/window_properties.h" -#include "base/memory/ptr_util.h" -#include "ui/aura/window.h" - -namespace ash { -namespace wm { - -WmSnapToPixelLayoutManager::WmSnapToPixelLayoutManager() {} - -WmSnapToPixelLayoutManager::~WmSnapToPixelLayoutManager() {} - -// static -void WmSnapToPixelLayoutManager::InstallOnContainers(WmWindow* window) { - for (WmWindow* child : window->GetChildren()) { - if (child->GetShellWindowId() < kShellWindowId_Min || - child->GetShellWindowId() > kShellWindowId_Max) // not a container - continue; - if (child->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)) { - if (!child->GetLayoutManager()) - child->SetLayoutManager(base::MakeUnique<WmSnapToPixelLayoutManager>()); - } else { - InstallOnContainers(child); - } - } -} - -void WmSnapToPixelLayoutManager::OnWindowResized() {} - -void WmSnapToPixelLayoutManager::OnWindowAddedToLayout(WmWindow* child) {} - -void WmSnapToPixelLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) { -} - -void WmSnapToPixelLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {} - -void WmSnapToPixelLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, - bool visibile) { -} - -void WmSnapToPixelLayoutManager::SetChildBounds( - WmWindow* child, - const gfx::Rect& requested_bounds) { - child->SetBoundsDirect(requested_bounds); - child->SnapToPixelBoundaryIfNecessary(); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/wm_snap_to_pixel_layout_manager.h b/ash/wm/wm_snap_to_pixel_layout_manager.h deleted file mode 100644 index da98f023..0000000 --- a/ash/wm/wm_snap_to_pixel_layout_manager.h +++ /dev/null
@@ -1,43 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WM_SNAP_TO_PIXEL_LAYOUT_MANAGER_H_ -#define ASH_WM_WM_SNAP_TO_PIXEL_LAYOUT_MANAGER_H_ - -#include "ash/ash_export.h" -#include "ash/common/wm_layout_manager.h" -#include "base/macros.h" - -namespace ash { -namespace wm { - -// A layout manager that places children's layer at the physical pixel -// boundaries. -class ASH_EXPORT WmSnapToPixelLayoutManager : public WmLayoutManager { - public: - WmSnapToPixelLayoutManager(); - ~WmSnapToPixelLayoutManager() override; - - // Sets WmSnapToPixelLayoutManager as the LayoutManager on the appropriate - // descendants of |window|. - static void InstallOnContainers(WmWindow* window); - - protected: - // Overridden from aura::LayoutManager: - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override; - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - private: - DISALLOW_COPY_AND_ASSIGN(WmSnapToPixelLayoutManager); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WM_SNAP_TO_PIXEL_LAYOUT_MANAGER_H_
diff --git a/ash/wm/wm_toplevel_window_event_handler.cc b/ash/wm/wm_toplevel_window_event_handler.cc deleted file mode 100644 index 6c4eac1..0000000 --- a/ash/wm/wm_toplevel_window_event_handler.cc +++ /dev/null
@@ -1,550 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/wm_toplevel_window_event_handler.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/window_resizer.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_observer.h" -#include "ash/wm/wm_event.h" -#include "ui/aura/window.h" -#include "ui/aura/window_observer.h" -#include "ui/base/hit_test.h" -#include "ui/events/event.h" - -namespace { -const double kMinHorizVelocityForWindowSwipe = 1100; -const double kMinVertVelocityForWindowMinimize = 1000; -} - -namespace ash { -namespace wm { - -namespace { - -// Returns whether |window| can be moved via a two finger drag given -// the hittest results of the two fingers. -bool CanStartTwoFingerMove(WmWindow* window, - int window_component1, - int window_component2) { - // We allow moving a window via two fingers when the hittest components are - // HTCLIENT. This is done so that a window can be dragged via two fingers when - // the tab strip is full and hitting the caption area is difficult. We check - // the window type and the state type so that we do not steal touches from the - // web contents. - if (!window->GetWindowState()->IsNormalOrSnapped() || - window->GetType() != ui::wm::WINDOW_TYPE_NORMAL) { - return false; - } - int component1_behavior = - WindowResizer::GetBoundsChangeForWindowComponent(window_component1); - int component2_behavior = - WindowResizer::GetBoundsChangeForWindowComponent(window_component2); - return (component1_behavior & WindowResizer::kBoundsChange_Resizes) == 0 && - (component2_behavior & WindowResizer::kBoundsChange_Resizes) == 0; -} - -// Returns whether |window| can be moved or resized via one finger given -// |window_component|. -bool CanStartOneFingerDrag(int window_component) { - return WindowResizer::GetBoundsChangeForWindowComponent(window_component) != - 0; -} - -// Returns the window component containing |event|'s location. -int GetWindowComponent(WmWindow* window, const ui::LocatedEvent& event) { - return window->GetNonClientComponent(event.location()); -} - -} // namespace - -// ScopedWindowResizer --------------------------------------------------------- - -// Wraps a WindowResizer and installs an observer on its target window. When -// the window is destroyed ResizerWindowDestroyed() is invoked back on the -// WmToplevelWindowEventHandler to clean up. -class WmToplevelWindowEventHandler::ScopedWindowResizer - : public aura::WindowObserver, - public wm::WindowStateObserver { - public: - ScopedWindowResizer(WmToplevelWindowEventHandler* handler, - std::unique_ptr<WindowResizer> resizer); - ~ScopedWindowResizer() override; - - // Returns true if the drag moves the window and does not resize. - bool IsMove() const; - - WindowResizer* resizer() { return resizer_.get(); } - - // WindowObserver overrides: - void OnWindowDestroying(aura::Window* window) override; - - // WindowStateObserver overrides: - void OnPreWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType type) override; - - private: - WmToplevelWindowEventHandler* handler_; - std::unique_ptr<WindowResizer> resizer_; - - // Whether ScopedWindowResizer grabbed capture. - bool grabbed_capture_; - - DISALLOW_COPY_AND_ASSIGN(ScopedWindowResizer); -}; - -WmToplevelWindowEventHandler::ScopedWindowResizer::ScopedWindowResizer( - WmToplevelWindowEventHandler* handler, - std::unique_ptr<WindowResizer> resizer) - : handler_(handler), resizer_(std::move(resizer)), grabbed_capture_(false) { - WmWindow* target = resizer_->GetTarget(); - target->aura_window()->AddObserver(this); - target->GetWindowState()->AddObserver(this); - - if (!target->HasCapture()) { - grabbed_capture_ = true; - target->SetCapture(); - } -} - -WmToplevelWindowEventHandler::ScopedWindowResizer::~ScopedWindowResizer() { - WmWindow* target = resizer_->GetTarget(); - target->aura_window()->RemoveObserver(this); - target->GetWindowState()->RemoveObserver(this); - if (grabbed_capture_) - target->ReleaseCapture(); -} - -bool WmToplevelWindowEventHandler::ScopedWindowResizer::IsMove() const { - return resizer_->details().bounds_change == - WindowResizer::kBoundsChange_Repositions; -} - -void WmToplevelWindowEventHandler::ScopedWindowResizer:: - OnPreWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old) { - handler_->CompleteDrag(DragResult::SUCCESS); -} - -void WmToplevelWindowEventHandler::ScopedWindowResizer::OnWindowDestroying( - aura::Window* window) { - DCHECK_EQ(resizer_->GetTarget(), WmWindow::Get(window)); - handler_->ResizerWindowDestroyed(); -} - -// WmToplevelWindowEventHandler -// -------------------------------------------------- - -WmToplevelWindowEventHandler::WmToplevelWindowEventHandler(WmShell* shell) - : shell_(shell), first_finger_hittest_(HTNOWHERE) { - shell_->AddDisplayObserver(this); -} - -WmToplevelWindowEventHandler::~WmToplevelWindowEventHandler() { - shell_->RemoveDisplayObserver(this); -} - -void WmToplevelWindowEventHandler::OnKeyEvent(ui::KeyEvent* event) { - if (window_resizer_.get() && event->type() == ui::ET_KEY_PRESSED && - event->key_code() == ui::VKEY_ESCAPE) { - CompleteDrag(DragResult::REVERT); - } -} - -void WmToplevelWindowEventHandler::OnMouseEvent(ui::MouseEvent* event, - WmWindow* target) { - if (event->handled()) - return; - if ((event->flags() & - (ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON)) != 0) - return; - - if (event->type() == ui::ET_MOUSE_CAPTURE_CHANGED) { - // Capture is grabbed when both gesture and mouse drags start. Handle - // capture loss regardless of which type of drag is in progress. - HandleCaptureLost(event); - return; - } - - if (in_gesture_drag_) - return; - - switch (event->type()) { - case ui::ET_MOUSE_PRESSED: - HandleMousePressed(target, event); - break; - case ui::ET_MOUSE_DRAGGED: - HandleDrag(target, event); - break; - case ui::ET_MOUSE_RELEASED: - HandleMouseReleased(target, event); - break; - case ui::ET_MOUSE_MOVED: - HandleMouseMoved(target, event); - break; - case ui::ET_MOUSE_EXITED: - HandleMouseExited(target, event); - break; - default: - break; - } -} - -void WmToplevelWindowEventHandler::OnGestureEvent(ui::GestureEvent* event, - WmWindow* target) { - if (event->handled()) - return; - if (!target->HasNonClientArea()) - return; - - if (window_resizer_.get() && !in_gesture_drag_) - return; - - if (window_resizer_.get() && - window_resizer_->resizer()->GetTarget() != target) { - return; - } - - if (event->details().touch_points() > 2) { - if (CompleteDrag(DragResult::SUCCESS)) - event->StopPropagation(); - return; - } - - switch (event->type()) { - case ui::ET_GESTURE_TAP_DOWN: { - int component = GetWindowComponent(target, *event); - if (!(WindowResizer::GetBoundsChangeForWindowComponent(component) & - WindowResizer::kBoundsChange_Resizes)) - return; - target->ShowResizeShadow(component); - return; - } - case ui::ET_GESTURE_END: { - target->HideResizeShadow(); - - if (window_resizer_.get() && - (event->details().touch_points() == 1 || - !CanStartOneFingerDrag(first_finger_hittest_))) { - CompleteDrag(DragResult::SUCCESS); - event->StopPropagation(); - } - return; - } - case ui::ET_GESTURE_BEGIN: { - if (event->details().touch_points() == 1) { - first_finger_hittest_ = GetWindowComponent(target, *event); - } else if (window_resizer_.get()) { - if (!window_resizer_->IsMove()) { - // The transition from resizing with one finger to resizing with two - // fingers causes unintended resizing because the location of - // ET_GESTURE_SCROLL_UPDATE jumps from the position of the first - // finger to the position in the middle of the two fingers. For this - // reason two finger resizing is not supported. - CompleteDrag(DragResult::SUCCESS); - event->StopPropagation(); - } - } else { - int second_finger_hittest = GetWindowComponent(target, *event); - if (CanStartTwoFingerMove(target, first_finger_hittest_, - second_finger_hittest)) { - gfx::Point location_in_parent = - event->details().bounding_box().CenterPoint(); - AttemptToStartDrag(target, location_in_parent, HTCAPTION, - aura::client::WINDOW_MOVE_SOURCE_TOUCH, - EndClosure()); - event->StopPropagation(); - } - } - return; - } - case ui::ET_GESTURE_SCROLL_BEGIN: { - // The one finger drag is not started in ET_GESTURE_BEGIN to avoid the - // window jumping upon initiating a two finger drag. When a one finger - // drag is converted to a two finger drag, a jump occurs because the - // location of the ET_GESTURE_SCROLL_UPDATE event switches from the single - // finger's position to the position in the middle of the two fingers. - if (window_resizer_.get()) - return; - int component = GetWindowComponent(target, *event); - if (!CanStartOneFingerDrag(component)) - return; - gfx::Point location_in_parent( - target->ConvertPointToTarget(target->GetParent(), event->location())); - AttemptToStartDrag(target, location_in_parent, component, - aura::client::WINDOW_MOVE_SOURCE_TOUCH, EndClosure()); - event->StopPropagation(); - return; - } - default: - break; - } - - if (!window_resizer_.get()) - return; - - switch (event->type()) { - case ui::ET_GESTURE_SCROLL_UPDATE: - HandleDrag(target, event); - event->StopPropagation(); - return; - case ui::ET_GESTURE_SCROLL_END: - // We must complete the drag here instead of as a result of ET_GESTURE_END - // because otherwise the drag will be reverted when EndMoveLoop() is - // called. - // TODO(pkotwicz): Pass drag completion status to - // WindowMoveClient::EndMoveLoop(). - CompleteDrag(DragResult::SUCCESS); - event->StopPropagation(); - return; - case ui::ET_SCROLL_FLING_START: - CompleteDrag(DragResult::SUCCESS); - - // TODO(pkotwicz): Fix tests which inadvertantly start flings and check - // window_resizer_->IsMove() instead of the hittest component at |event|'s - // location. - if (GetWindowComponent(target, *event) != HTCAPTION || - !target->GetWindowState()->IsNormalOrSnapped()) { - return; - } - - if (event->details().velocity_y() > kMinVertVelocityForWindowMinimize) { - SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MINIMIZED); - } else if (event->details().velocity_y() < - -kMinVertVelocityForWindowMinimize) { - SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MAXIMIZED); - } else if (event->details().velocity_x() > - kMinHorizVelocityForWindowSwipe) { - SetWindowStateTypeFromGesture(target, - wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED); - } else if (event->details().velocity_x() < - -kMinHorizVelocityForWindowSwipe) { - SetWindowStateTypeFromGesture(target, - wm::WINDOW_STATE_TYPE_LEFT_SNAPPED); - } - event->StopPropagation(); - return; - case ui::ET_GESTURE_SWIPE: - DCHECK_GT(event->details().touch_points(), 0); - if (event->details().touch_points() == 1) - return; - if (!target->GetWindowState()->IsNormalOrSnapped()) - return; - - CompleteDrag(DragResult::SUCCESS); - - if (event->details().swipe_down()) { - SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MINIMIZED); - } else if (event->details().swipe_up()) { - SetWindowStateTypeFromGesture(target, wm::WINDOW_STATE_TYPE_MAXIMIZED); - } else if (event->details().swipe_right()) { - SetWindowStateTypeFromGesture(target, - wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED); - } else { - SetWindowStateTypeFromGesture(target, - wm::WINDOW_STATE_TYPE_LEFT_SNAPPED); - } - event->StopPropagation(); - return; - default: - return; - } -} - -bool WmToplevelWindowEventHandler::AttemptToStartDrag( - WmWindow* window, - const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source, - const EndClosure& end_closure) { - if (window_resizer_.get()) - return false; - std::unique_ptr<WindowResizer> resizer( - CreateWindowResizer(window, point_in_parent, window_component, source)); - if (!resizer) - return false; - - end_closure_ = end_closure; - window_resizer_.reset(new ScopedWindowResizer(this, std::move(resizer))); - - pre_drag_window_bounds_ = window->GetBounds(); - in_gesture_drag_ = (source == aura::client::WINDOW_MOVE_SOURCE_TOUCH); - return true; -} - -void WmToplevelWindowEventHandler::RevertDrag() { - CompleteDrag(DragResult::REVERT); -} - -bool WmToplevelWindowEventHandler::CompleteDrag(DragResult result) { - if (!window_resizer_) - return false; - - std::unique_ptr<ScopedWindowResizer> resizer(std::move(window_resizer_)); - switch (result) { - case DragResult::SUCCESS: - resizer->resizer()->CompleteDrag(); - break; - case DragResult::REVERT: - resizer->resizer()->RevertDrag(); - break; - case DragResult::WINDOW_DESTROYED: - // We explicitly do not invoke RevertDrag() since that may do things to - // the window that was destroyed. - break; - } - - first_finger_hittest_ = HTNOWHERE; - in_gesture_drag_ = false; - if (!end_closure_.is_null()) { - // Clear local state in case running the closure deletes us. - EndClosure end_closure = end_closure_; - end_closure_.Reset(); - end_closure.Run(result); - } - return true; -} - -void WmToplevelWindowEventHandler::HandleMousePressed(WmWindow* target, - ui::MouseEvent* event) { - if (event->phase() != ui::EP_PRETARGET || !target->HasNonClientArea()) - return; - - // We also update the current window component here because for the - // mouse-drag-release-press case, where the mouse is released and - // pressed without mouse move event. - int component = GetWindowComponent(target, *event); - if ((event->flags() & (ui::EF_IS_DOUBLE_CLICK | ui::EF_IS_TRIPLE_CLICK)) == - 0 && - WindowResizer::GetBoundsChangeForWindowComponent(component)) { - gfx::Point location_in_parent( - target->ConvertPointToTarget(target->GetParent(), event->location())); - AttemptToStartDrag(target, location_in_parent, component, - aura::client::WINDOW_MOVE_SOURCE_MOUSE, EndClosure()); - // Set as handled so that other event handlers do no act upon the event - // but still receive it so that they receive both parts of each pressed/ - // released pair. - event->SetHandled(); - } else { - CompleteDrag(DragResult::SUCCESS); - } -} - -void WmToplevelWindowEventHandler::HandleMouseReleased(WmWindow* target, - ui::MouseEvent* event) { - if (event->phase() == ui::EP_PRETARGET) - CompleteDrag(DragResult::SUCCESS); -} - -void WmToplevelWindowEventHandler::HandleDrag(WmWindow* target, - ui::LocatedEvent* event) { - // This function only be triggered to move window - // by mouse drag or touch move event. - DCHECK(event->type() == ui::ET_MOUSE_DRAGGED || - event->type() == ui::ET_TOUCH_MOVED || - event->type() == ui::ET_GESTURE_SCROLL_UPDATE); - - // Drag actions are performed pre-target handling to prevent spurious mouse - // moves from the move/size operation from being sent to the target. - if (event->phase() != ui::EP_PRETARGET) - return; - - if (!window_resizer_) - return; - window_resizer_->resizer()->Drag( - target->ConvertPointToTarget(target->GetParent(), event->location()), - event->flags()); - event->StopPropagation(); -} - -void WmToplevelWindowEventHandler::HandleMouseMoved(WmWindow* target, - ui::LocatedEvent* event) { - // Shadow effects are applied after target handling. Note that we don't - // respect ER_HANDLED here right now since we have not had a reason to allow - // the target to cancel shadow rendering. - if (event->phase() != ui::EP_POSTTARGET || !target->HasNonClientArea()) - return; - - // TODO(jamescook): Move the resize cursor update code into here from - // CompoundEventFilter? - if (event->flags() & ui::EF_IS_NON_CLIENT) { - int component = target->GetNonClientComponent(event->location()); - target->ShowResizeShadow(component); - } else { - target->HideResizeShadow(); - } -} - -void WmToplevelWindowEventHandler::HandleMouseExited(WmWindow* target, - ui::LocatedEvent* event) { - // Shadow effects are applied after target handling. Note that we don't - // respect ER_HANDLED here right now since we have not had a reason to allow - // the target to cancel shadow rendering. - if (event->phase() != ui::EP_POSTTARGET) - return; - - target->HideResizeShadow(); -} - -void WmToplevelWindowEventHandler::HandleCaptureLost(ui::LocatedEvent* event) { - if (event->phase() == ui::EP_PRETARGET) { - // We complete the drag instead of reverting it, as reverting it will result - // in a weird behavior when a dragged tab produces a modal dialog while the - // drag is in progress. crbug.com/558201. - CompleteDrag(DragResult::SUCCESS); - } -} - -void WmToplevelWindowEventHandler::SetWindowStateTypeFromGesture( - WmWindow* window, - wm::WindowStateType new_state_type) { - wm::WindowState* window_state = window->GetWindowState(); - // TODO(oshima): Move extra logic (set_unminimize_to_restore_bounds, - // SetRestoreBoundsInParent) that modifies the window state - // into WindowState. - switch (new_state_type) { - case wm::WINDOW_STATE_TYPE_MINIMIZED: - if (window_state->CanMinimize()) { - window_state->Minimize(); - window_state->set_unminimize_to_restore_bounds(true); - window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); - } - break; - case wm::WINDOW_STATE_TYPE_MAXIMIZED: - if (window_state->CanMaximize()) { - window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); - window_state->Maximize(); - } - break; - case wm::WINDOW_STATE_TYPE_LEFT_SNAPPED: - if (window_state->CanSnap()) { - window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); - const wm::WMEvent event(wm::WM_EVENT_SNAP_LEFT); - window_state->OnWMEvent(&event); - } - break; - case wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED: - if (window_state->CanSnap()) { - window_state->SetRestoreBoundsInParent(pre_drag_window_bounds_); - const wm::WMEvent event(wm::WM_EVENT_SNAP_RIGHT); - window_state->OnWMEvent(&event); - } - break; - default: - NOTREACHED(); - } -} - -void WmToplevelWindowEventHandler::ResizerWindowDestroyed() { - CompleteDrag(DragResult::WINDOW_DESTROYED); -} - -void WmToplevelWindowEventHandler::OnDisplayConfigurationChanging() { - CompleteDrag(DragResult::REVERT); -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/wm_toplevel_window_event_handler.h b/ash/wm/wm_toplevel_window_event_handler.h deleted file mode 100644 index 0327b5f..0000000 --- a/ash/wm/wm_toplevel_window_event_handler.h +++ /dev/null
@@ -1,128 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_ -#define ASH_WM_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/common/wm_display_observer.h" -#include "ash/wm/wm_types.h" -#include "base/callback.h" -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/wm/public/window_move_client.h" - -namespace ui { -class KeyEvent; -class LocatedEvent; -class MouseEvent; -class GestureEvent; -} - -namespace ash { - -class WmShell; -class WmWindow; - -namespace wm { - -// WmToplevelWindowEventHandler handles dragging and resizing of top level -// windows. WmToplevelWindowEventHandler is forwarded events, such as from an -// EventHandler. -class ASH_EXPORT WmToplevelWindowEventHandler : public WmDisplayObserver { - public: - // Describes what triggered ending the drag. - enum class DragResult { - // The drag successfully completed. - SUCCESS, - - REVERT, - - // The underlying window was destroyed while the drag is in process. - WINDOW_DESTROYED - }; - using EndClosure = base::Callback<void(DragResult)>; - - explicit WmToplevelWindowEventHandler(WmShell* shell); - ~WmToplevelWindowEventHandler() override; - - void OnKeyEvent(ui::KeyEvent* event); - void OnMouseEvent(ui::MouseEvent* event, WmWindow* target); - void OnGestureEvent(ui::GestureEvent* event, WmWindow* target); - - // Attempts to start a drag if one is not already in progress. Returns true if - // successful. |end_closure| is run when the drag completes. |end_closure| is - // not run if the drag does not start. - bool AttemptToStartDrag(WmWindow* window, - const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source, - const EndClosure& end_closure); - - // If there is a drag in progress it is reverted, otherwise does nothing. - void RevertDrag(); - - // Returns true if there is a drag in progress. - bool is_drag_in_progress() const { return window_resizer_.get() != nullptr; } - - private: - class ScopedWindowResizer; - - // Completes or reverts the drag if one is in progress. Returns true if a - // drag was completed or reverted. - bool CompleteDrag(DragResult result); - - void HandleMousePressed(WmWindow* target, ui::MouseEvent* event); - void HandleMouseReleased(WmWindow* target, ui::MouseEvent* event); - - // Called during a drag to resize/position the window. - void HandleDrag(WmWindow* target, ui::LocatedEvent* event); - - // Called during mouse moves to update window resize shadows. - void HandleMouseMoved(WmWindow* target, ui::LocatedEvent* event); - - // Called for mouse exits to hide window resize shadows. - void HandleMouseExited(WmWindow* target, ui::LocatedEvent* event); - - // Called when mouse capture is lost. - void HandleCaptureLost(ui::LocatedEvent* event); - - // Sets |window|'s state type to |new_state_type|. Called after the drag has - // been completed for fling gestures. - void SetWindowStateTypeFromGesture(WmWindow* window, - wm::WindowStateType new_state_type); - - // Invoked from ScopedWindowResizer if the window is destroyed. - void ResizerWindowDestroyed(); - - // WmDisplayObserver: - void OnDisplayConfigurationChanging() override; - - WmShell* shell_; - - // The hittest result for the first finger at the time that it initially - // touched the screen. |first_finger_hittest_| is one of ui/base/hit_test.h - int first_finger_hittest_; - - // The window bounds when the drag was started. When a window is minimized, - // maximized or snapped via a swipe/fling gesture, the restore bounds should - // be set to the bounds of the window when the drag was started. - gfx::Rect pre_drag_window_bounds_; - - // Is a window move/resize in progress because of gesture events? - bool in_gesture_drag_ = false; - - std::unique_ptr<ScopedWindowResizer> window_resizer_; - - EndClosure end_closure_; - - DISALLOW_COPY_AND_ASSIGN(WmToplevelWindowEventHandler); -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WM_TOPLEVEL_WINDOW_EVENT_HANDLER_H_
diff --git a/ash/wm/wm_types.cc b/ash/wm/wm_types.cc deleted file mode 100644 index 1466775..0000000 --- a/ash/wm/wm_types.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/wm_types.h" - -#include "base/logging.h" - -namespace ash { -namespace wm { - -// This is to catch the change to WindowShowState. -static_assert(ui::SHOW_STATE_END == - static_cast<ui::WindowShowState>(WINDOW_STATE_TYPE_END), - "show enum mismatch"); - -WindowStateType ToWindowStateType(ui::WindowShowState state) { - return static_cast<WindowStateType>(state); -} - -ui::WindowShowState ToWindowShowState(WindowStateType type) { - switch (type) { - case WINDOW_STATE_TYPE_DEFAULT: - return ui::SHOW_STATE_DEFAULT; - case WINDOW_STATE_TYPE_NORMAL: - case WINDOW_STATE_TYPE_RIGHT_SNAPPED: - case WINDOW_STATE_TYPE_LEFT_SNAPPED: - case WINDOW_STATE_TYPE_AUTO_POSITIONED: - return ui::SHOW_STATE_NORMAL; - - // TODO(afakhry): Remove Docked Windows in M58. - case WINDOW_STATE_TYPE_DOCKED: - return ui::SHOW_STATE_DOCKED; - case WINDOW_STATE_TYPE_MINIMIZED: - case WINDOW_STATE_TYPE_DOCKED_MINIMIZED: - return ui::SHOW_STATE_MINIMIZED; - case WINDOW_STATE_TYPE_MAXIMIZED: - return ui::SHOW_STATE_MAXIMIZED; - case WINDOW_STATE_TYPE_INACTIVE: - return ui::SHOW_STATE_INACTIVE; - case WINDOW_STATE_TYPE_FULLSCREEN: - case WINDOW_STATE_TYPE_PINNED: - case WINDOW_STATE_TYPE_TRUSTED_PINNED: - return ui::SHOW_STATE_FULLSCREEN; - case WINDOW_STATE_TYPE_END: - NOTREACHED(); - } - NOTREACHED(); - return ui::SHOW_STATE_DEFAULT; -} - -bool IsMaximizedOrFullscreenOrPinnedWindowStateType(WindowStateType type) { - return type == WINDOW_STATE_TYPE_MAXIMIZED || - type == WINDOW_STATE_TYPE_FULLSCREEN || - type == WINDOW_STATE_TYPE_PINNED || - type == WINDOW_STATE_TYPE_TRUSTED_PINNED; -} - -} // namespace wm -} // namespace ash
diff --git a/ash/wm/wm_types.h b/ash/wm/wm_types.h deleted file mode 100644 index d237f39..0000000 --- a/ash/wm/wm_types.h +++ /dev/null
@@ -1,66 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WM_TYPES_H_ -#define ASH_WM_WM_TYPES_H_ - -#include "ash/ash_export.h" -#include "ui/base/ui_base_types.h" - -namespace ash { -namespace wm { - -// This enum defines both common show state copied from -// ui::WindowShowState as well as new states introduced in ash. -// The separate enum is defined here because we don't want to leak -// these type to ui/base until they're stable and we know for sure -// that they'll persist over time. -enum WindowStateType { - // Common state - WINDOW_STATE_TYPE_DEFAULT = 0, - - // Normal represents a state where the position/size has been - // specified by a use. - WINDOW_STATE_TYPE_NORMAL, - WINDOW_STATE_TYPE_MINIMIZED, - WINDOW_STATE_TYPE_MAXIMIZED, - WINDOW_STATE_TYPE_INACTIVE, - WINDOW_STATE_TYPE_FULLSCREEN, - WINDOW_STATE_TYPE_DOCKED, - WINDOW_STATE_TYPE_END, // to avoid using SHOW_STATE_END - - // Ash specific states: - - WINDOW_STATE_TYPE_LEFT_SNAPPED, - WINDOW_STATE_TYPE_RIGHT_SNAPPED, - - WINDOW_STATE_TYPE_DOCKED_MINIMIZED, - - // A window is in this state when it is automatically placed and - // sized by the window manager. (it's newly opened, or pushed to the side - // due to new window, for example). - WINDOW_STATE_TYPE_AUTO_POSITIONED, - - // A window is pinned on top of other windows with fullscreenized. - // Corresponding shelf should be hidden, also most of windows other than the - // pinned one should be hidden. - WINDOW_STATE_TYPE_PINNED, - WINDOW_STATE_TYPE_TRUSTED_PINNED, -}; - -// Utility functions to convert WindowStateType <-> ui::WindowShowState. -// Note: LEFT/RIGHT MAXIMIZED, AUTO_POSITIONED type will be lost when -// converting to ui::WindowShowState. -ASH_EXPORT WindowStateType ToWindowStateType(ui::WindowShowState state); -ASH_EXPORT ui::WindowShowState ToWindowShowState(WindowStateType type); - -// Returns true if |type| is WINDOW_STATE_TYPE_MAXIMIZED, -// WINDOW_STATE_TYPE_FULLSCREEN or WINDOW_STATE_TYPE_PINNED. -ASH_EXPORT bool IsMaximizedOrFullscreenOrPinnedWindowStateType( - WindowStateType type); - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WM_TYPES_H_
diff --git a/ash/wm/wm_window_animations.cc b/ash/wm/wm_window_animations.cc deleted file mode 100644 index e21cc70a..0000000 --- a/ash/wm/wm_window_animations.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/wm_window_animations.h" - -#include "ui/compositor/layer.h" -#include "ui/gfx/transform.h" - -namespace ash { - -void SetTransformForScaleAnimation(ui::Layer* layer, - LayerScaleAnimationDirection type) { - // Scales for windows above and below the current workspace. - const float kLayerScaleAboveSize = 1.1f; - const float kLayerScaleBelowSize = .9f; - - const float scale = type == LAYER_SCALE_ANIMATION_ABOVE - ? kLayerScaleAboveSize - : kLayerScaleBelowSize; - gfx::Transform transform; - transform.Translate(-layer->bounds().width() * (scale - 1.0f) / 2, - -layer->bounds().height() * (scale - 1.0f) / 2); - transform.Scale(scale, scale); - layer->SetTransform(transform); -} - -} // namespace ash
diff --git a/ash/wm/wm_window_animations.h b/ash/wm/wm_window_animations.h deleted file mode 100644 index 860e51e..0000000 --- a/ash/wm/wm_window_animations.h +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WM_WINDOW_ANIMATIONS_H_ -#define ASH_WM_WM_WINDOW_ANIMATIONS_H_ - -#include "ash/ash_export.h" - -namespace ui { -class Layer; -} - -// This is only for animations specific to Ash. For window animations shared -// with desktop Chrome, see ui/views/corewm/window_animations.h. -namespace ash { - -// Direction for ash-specific window animations used in workspaces and -// lock/unlock animations. -enum LayerScaleAnimationDirection { - LAYER_SCALE_ANIMATION_ABOVE, - LAYER_SCALE_ANIMATION_BELOW, -}; - -// Applies scale related to the specified AshWindowScaleType. -ASH_EXPORT void SetTransformForScaleAnimation( - ui::Layer* layer, - LayerScaleAnimationDirection type); - -} // namespace ash - -#endif // ASH_WM_WM_WINDOW_ANIMATIONS_H_
diff --git a/ash/wm/workspace/magnetism_matcher.cc b/ash/wm/workspace/magnetism_matcher.cc deleted file mode 100644 index d7870ff..0000000 --- a/ash/wm/workspace/magnetism_matcher.cc +++ /dev/null
@@ -1,195 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/magnetism_matcher.h" - -#include <algorithm> -#include <cmath> - -#include "base/memory/ptr_util.h" - -namespace ash { -namespace { - -// Returns true if |a| is close enough to |b| that the two edges snap. -bool IsCloseEnough(int a, int b) { - return abs(a - b) <= MagnetismMatcher::kMagneticDistance; -} - -// Returns true if the specified SecondaryMagnetismEdge can be matched with a -// primary edge of |primary|. |edges| is a bitmask of the allowed -// MagnetismEdges. -bool CanMatchSecondaryEdge(MagnetismEdge primary, - SecondaryMagnetismEdge secondary, - uint32_t edges) { - // Convert |secondary| to a MagnetismEdge so we can compare it to |edges|. - MagnetismEdge secondary_as_magnetism_edge = MAGNETISM_EDGE_TOP; - switch (primary) { - case MAGNETISM_EDGE_TOP: - case MAGNETISM_EDGE_BOTTOM: - if (secondary == SECONDARY_MAGNETISM_EDGE_LEADING) - secondary_as_magnetism_edge = MAGNETISM_EDGE_LEFT; - else if (secondary == SECONDARY_MAGNETISM_EDGE_TRAILING) - secondary_as_magnetism_edge = MAGNETISM_EDGE_RIGHT; - else - NOTREACHED(); - break; - case MAGNETISM_EDGE_LEFT: - case MAGNETISM_EDGE_RIGHT: - if (secondary == SECONDARY_MAGNETISM_EDGE_LEADING) - secondary_as_magnetism_edge = MAGNETISM_EDGE_TOP; - else if (secondary == SECONDARY_MAGNETISM_EDGE_TRAILING) - secondary_as_magnetism_edge = MAGNETISM_EDGE_BOTTOM; - else - NOTREACHED(); - break; - } - return (edges & secondary_as_magnetism_edge) != 0; -} - -} // namespace - -// MagnetismEdgeMatcher -------------------------------------------------------- - -MagnetismEdgeMatcher::MagnetismEdgeMatcher(const gfx::Rect& bounds, - MagnetismEdge edge) - : bounds_(bounds), edge_(edge) { - ranges_.push_back(GetSecondaryRange(bounds_)); -} - -MagnetismEdgeMatcher::~MagnetismEdgeMatcher() {} - -bool MagnetismEdgeMatcher::ShouldAttach(const gfx::Rect& bounds) { - if (is_edge_obscured()) - return false; - - if (IsCloseEnough(GetPrimaryCoordinate(bounds_, edge_), - GetPrimaryCoordinate(bounds, FlipEdge(edge_)))) { - const Range range(GetSecondaryRange(bounds)); - Ranges::const_iterator i = - std::lower_bound(ranges_.begin(), ranges_.end(), range); - // Close enough, but only attach if some portion of the edge is visible. - if ((i != ranges_.begin() && RangesIntersect(*(i - 1), range)) || - (i != ranges_.end() && RangesIntersect(*i, range))) { - return true; - } - } - // NOTE: this checks against the current bounds, we may want to allow some - // flexibility here. - const Range primary_range(GetPrimaryRange(bounds)); - if (primary_range.first <= GetPrimaryCoordinate(bounds_, edge_) && - primary_range.second >= GetPrimaryCoordinate(bounds_, edge_)) { - UpdateRanges(GetSecondaryRange(bounds)); - } - return false; -} - -void MagnetismEdgeMatcher::UpdateRanges(const Range& range) { - Ranges::const_iterator it = - std::lower_bound(ranges_.begin(), ranges_.end(), range); - if (it != ranges_.begin() && RangesIntersect(*(it - 1), range)) - --it; - if (it == ranges_.end()) - return; - - for (size_t i = it - ranges_.begin(); - i < ranges_.size() && RangesIntersect(ranges_[i], range);) { - if (range.first <= ranges_[i].first && range.second >= ranges_[i].second) { - ranges_.erase(ranges_.begin() + i); - } else if (range.first < ranges_[i].first) { - DCHECK_GT(range.second, ranges_[i].first); - ranges_[i] = Range(range.second, ranges_[i].second); - ++i; - } else { - Range existing(ranges_[i]); - ranges_[i].second = range.first; - ++i; - if (existing.second > range.second) { - ranges_.insert(ranges_.begin() + i, - Range(range.second, existing.second)); - ++i; - } - } - } -} - -// MagnetismMatcher ------------------------------------------------------------ - -// static -const int MagnetismMatcher::kMagneticDistance = 8; - -MagnetismMatcher::MagnetismMatcher(const gfx::Rect& bounds, uint32_t edges) - : edges_(edges) { - if (edges & MAGNETISM_EDGE_TOP) { - matchers_.push_back( - base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_TOP)); - } - if (edges & MAGNETISM_EDGE_LEFT) { - matchers_.push_back( - base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_LEFT)); - } - if (edges & MAGNETISM_EDGE_BOTTOM) { - matchers_.push_back( - base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_BOTTOM)); - } - if (edges & MAGNETISM_EDGE_RIGHT) { - matchers_.push_back( - base::MakeUnique<MagnetismEdgeMatcher>(bounds, MAGNETISM_EDGE_RIGHT)); - } -} - -MagnetismMatcher::~MagnetismMatcher() {} - -bool MagnetismMatcher::ShouldAttach(const gfx::Rect& bounds, - MatchedEdge* edge) { - for (const auto& matcher : matchers_) { - if (matcher->ShouldAttach(bounds)) { - edge->primary_edge = matcher->edge(); - AttachToSecondaryEdge(bounds, edge->primary_edge, - &(edge->secondary_edge)); - return true; - } - } - return false; -} - -bool MagnetismMatcher::AreEdgesObscured() const { - for (const auto& matcher : matchers_) { - if (!matcher->is_edge_obscured()) - return false; - } - return true; -} - -void MagnetismMatcher::AttachToSecondaryEdge( - const gfx::Rect& bounds, - MagnetismEdge edge, - SecondaryMagnetismEdge* secondary_edge) const { - const gfx::Rect& src_bounds(matchers_[0]->bounds()); - if (edge == MAGNETISM_EDGE_LEFT || edge == MAGNETISM_EDGE_RIGHT) { - if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_LEADING, edges_) && - IsCloseEnough(bounds.y(), src_bounds.y())) { - *secondary_edge = SECONDARY_MAGNETISM_EDGE_LEADING; - } else if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_TRAILING, - edges_) && - IsCloseEnough(bounds.bottom(), src_bounds.bottom())) { - *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING; - } else { - *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE; - } - } else { - if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_LEADING, edges_) && - IsCloseEnough(bounds.x(), src_bounds.x())) { - *secondary_edge = SECONDARY_MAGNETISM_EDGE_LEADING; - } else if (CanMatchSecondaryEdge(edge, SECONDARY_MAGNETISM_EDGE_TRAILING, - edges_) && - IsCloseEnough(bounds.right(), src_bounds.right())) { - *secondary_edge = SECONDARY_MAGNETISM_EDGE_TRAILING; - } else { - *secondary_edge = SECONDARY_MAGNETISM_EDGE_NONE; - } - } -} - -} // namespace ash
diff --git a/ash/wm/workspace/magnetism_matcher.h b/ash/wm/workspace/magnetism_matcher.h deleted file mode 100644 index ef8a18d..0000000 --- a/ash/wm/workspace/magnetism_matcher.h +++ /dev/null
@@ -1,192 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_ -#define ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_ - -#include <stdint.h> - -#include <memory> -#include <utility> -#include <vector> - -#include "ash/ash_export.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" - -namespace ash { - -enum MagnetismEdge { - MAGNETISM_EDGE_TOP = 1 << 0, - MAGNETISM_EDGE_LEFT = 1 << 1, - MAGNETISM_EDGE_BOTTOM = 1 << 2, - MAGNETISM_EDGE_RIGHT = 1 << 3, -}; - -const uint32_t kAllMagnetismEdges = MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_LEFT | - MAGNETISM_EDGE_BOTTOM | - MAGNETISM_EDGE_RIGHT; - -// MagnetismEdgeMatcher is used for matching a particular edge of a window. You -// shouldn't need to use this directly, instead use MagnetismMatcher which takes -// care of all edges. -// MagnetismEdgeMatcher maintains a range of the visible portions of the -// edge. As ShouldAttach() is invoked the visible range is updated. -class MagnetismEdgeMatcher { - public: - MagnetismEdgeMatcher(const gfx::Rect& bounds, MagnetismEdge edge); - ~MagnetismEdgeMatcher(); - - MagnetismEdge edge() const { return edge_; } - const gfx::Rect& bounds() const { return bounds_; } - - // Returns true if the edge is completely obscured. If true ShouldAttach() - // will return false. - bool is_edge_obscured() const { return ranges_.empty(); } - - // Returns true if should attach to the specified bounds. - bool ShouldAttach(const gfx::Rect& bounds); - - private: - typedef std::pair<int, int> Range; - typedef std::vector<Range> Ranges; - - // Removes |range| from |ranges_|. - void UpdateRanges(const Range& range); - - static int GetPrimaryCoordinate(const gfx::Rect& bounds, MagnetismEdge edge) { - switch (edge) { - case MAGNETISM_EDGE_TOP: - return bounds.y(); - case MAGNETISM_EDGE_LEFT: - return bounds.x(); - case MAGNETISM_EDGE_BOTTOM: - return bounds.bottom(); - case MAGNETISM_EDGE_RIGHT: - return bounds.right(); - } - NOTREACHED(); - return 0; - } - - static MagnetismEdge FlipEdge(MagnetismEdge edge) { - switch (edge) { - case MAGNETISM_EDGE_TOP: - return MAGNETISM_EDGE_BOTTOM; - case MAGNETISM_EDGE_BOTTOM: - return MAGNETISM_EDGE_TOP; - case MAGNETISM_EDGE_LEFT: - return MAGNETISM_EDGE_RIGHT; - case MAGNETISM_EDGE_RIGHT: - return MAGNETISM_EDGE_LEFT; - } - NOTREACHED(); - return MAGNETISM_EDGE_LEFT; - } - - Range GetPrimaryRange(const gfx::Rect& bounds) const { - switch (edge_) { - case MAGNETISM_EDGE_TOP: - case MAGNETISM_EDGE_BOTTOM: - return Range(bounds.y(), bounds.bottom()); - case MAGNETISM_EDGE_LEFT: - case MAGNETISM_EDGE_RIGHT: - return Range(bounds.x(), bounds.right()); - } - NOTREACHED(); - return Range(); - } - - Range GetSecondaryRange(const gfx::Rect& bounds) const { - switch (edge_) { - case MAGNETISM_EDGE_TOP: - case MAGNETISM_EDGE_BOTTOM: - return Range(bounds.x(), bounds.right()); - case MAGNETISM_EDGE_LEFT: - case MAGNETISM_EDGE_RIGHT: - return Range(bounds.y(), bounds.bottom()); - } - NOTREACHED(); - return Range(); - } - - static bool RangesIntersect(const Range& r1, const Range& r2) { - return r2.first < r1.second && r2.second > r1.first; - } - - // The bounds of window. - const gfx::Rect bounds_; - - // The edge this matcher checks. - const MagnetismEdge edge_; - - // Visible ranges of the edge. Initialized with GetSecondaryRange() and - // updated as ShouldAttach() is invoked. When empty the edge is completely - // obscured by other bounds. - Ranges ranges_; - - DISALLOW_COPY_AND_ASSIGN(MagnetismEdgeMatcher); -}; - -enum SecondaryMagnetismEdge { - SECONDARY_MAGNETISM_EDGE_LEADING, - SECONDARY_MAGNETISM_EDGE_TRAILING, - SECONDARY_MAGNETISM_EDGE_NONE, -}; - -// Used to identify a matched edge. |primary_edge| is relative to the source and -// indicates the edge the two are to share. For example, if |primary_edge| is -// MAGNETISM_EDGE_RIGHT then the right edge of the source should snap to to the -// left edge of the target. |secondary_edge| indicates one of the edges along -// the opposite axis should should also be aligned. For example, if -// |primary_edge| is MAGNETISM_EDGE_RIGHT and |secondary_edge| is -// SECONDARY_MAGNETISM_EDGE_LEADING then the source should snap to the left top -// corner of the target. -struct MatchedEdge { - MagnetismEdge primary_edge; - SecondaryMagnetismEdge secondary_edge; -}; - -// MagnetismMatcher is used to test if a window should snap to another window. -// To use MagnetismMatcher do the following: -// . Create it with the bounds of the window being dragged. -// . Iterate over the child windows checking if the window being dragged should -// attach to it using ShouldAttach(). -// . Use AreEdgesObscured() to test if no other windows can match (because all -// edges are completely obscured). -class ASH_EXPORT MagnetismMatcher { - public: - static const int kMagneticDistance; - - // |edges| is a bitmask of MagnetismEdges to match against. - MagnetismMatcher(const gfx::Rect& bounds, uint32_t edges); - ~MagnetismMatcher(); - - // Returns true if |bounds| is close enough to the initial bounds that the two - // should be attached. If true is returned |edge| is set to indicates how the - // two should snap together. See description of MatchedEdge for details. - bool ShouldAttach(const gfx::Rect& bounds, MatchedEdge* edge); - - // Returns true if no other matches are possible. - bool AreEdgesObscured() const; - - private: - // Sets |secondary_edge| based on whether the secondary edges should snap. - void AttachToSecondaryEdge(const gfx::Rect& bounds, - MagnetismEdge edge, - SecondaryMagnetismEdge* secondary_edge) const; - - // The edges to match against. - const int32_t edges_; - - std::vector<std::unique_ptr<MagnetismEdgeMatcher>> matchers_; - - DISALLOW_COPY_AND_ASSIGN(MagnetismMatcher); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_
diff --git a/ash/wm/workspace/magnetism_matcher_unittest.cc b/ash/wm/workspace/magnetism_matcher_unittest.cc index e3124e3..c9c1c12b 100644 --- a/ash/wm/workspace/magnetism_matcher_unittest.cc +++ b/ash/wm/workspace/magnetism_matcher_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/workspace/magnetism_matcher.h" +#include "ash/common/wm/workspace/magnetism_matcher.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/wm/workspace/multi_window_resize_controller.cc b/ash/wm/workspace/multi_window_resize_controller.cc deleted file mode 100644 index 6e026131..0000000 --- a/ash/wm/workspace/multi_window_resize_controller.cc +++ /dev/null
@@ -1,540 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/multi_window_resize_controller.h" - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/root_window_controller.h" -#include "ash/wm/workspace/workspace_window_resizer.h" -#include "ui/base/cursor/cursor.h" -#include "ui/base/hit_test.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/display/screen.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/image/image.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/wm/core/compound_event_filter.h" - -namespace ash { -namespace { - -// Delay before showing. -const int kShowDelayMS = 400; - -// Delay before hiding. -const int kHideDelayMS = 500; - -// Padding from the bottom/right edge the resize widget is shown at. -const int kResizeWidgetPadding = 15; - -bool ContainsX(WmWindow* window, int x) { - return x >= 0 && x <= window->GetBounds().width(); -} - -bool ContainsScreenX(WmWindow* window, int x_in_screen) { - gfx::Point window_loc = - window->ConvertPointFromScreen(gfx::Point(x_in_screen, 0)); - return ContainsX(window, window_loc.x()); -} - -bool ContainsY(WmWindow* window, int y) { - return y >= 0 && y <= window->GetBounds().height(); -} - -bool ContainsScreenY(WmWindow* window, int y_in_screen) { - gfx::Point window_loc = - window->ConvertPointFromScreen(gfx::Point(0, y_in_screen)); - return ContainsY(window, window_loc.y()); -} - -bool Intersects(int x1, int max_1, int x2, int max_2) { - return x2 <= max_1 && max_2 > x1; -} - -} // namespace - -// View contained in the widget. Passes along mouse events to the -// MultiWindowResizeController so that it can start/stop the resize loop. -class MultiWindowResizeController::ResizeView : public views::View { - public: - explicit ResizeView(MultiWindowResizeController* controller, - Direction direction) - : controller_(controller), direction_(direction), image_(NULL) { - ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - int image_id = direction == TOP_BOTTOM ? IDR_AURA_MULTI_WINDOW_RESIZE_H - : IDR_AURA_MULTI_WINDOW_RESIZE_V; - image_ = rb.GetImageNamed(image_id).ToImageSkia(); - } - - // views::View overrides: - gfx::Size GetPreferredSize() const override { - return gfx::Size(image_->width(), image_->height()); - } - void OnPaint(gfx::Canvas* canvas) override { - canvas->DrawImageInt(*image_, 0, 0); - } - bool OnMousePressed(const ui::MouseEvent& event) override { - gfx::Point location(event.location()); - views::View::ConvertPointToScreen(this, &location); - controller_->StartResize(location); - return true; - } - bool OnMouseDragged(const ui::MouseEvent& event) override { - gfx::Point location(event.location()); - views::View::ConvertPointToScreen(this, &location); - controller_->Resize(location, event.flags()); - return true; - } - void OnMouseReleased(const ui::MouseEvent& event) override { - controller_->CompleteResize(); - } - void OnMouseCaptureLost() override { controller_->CancelResize(); } - gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override { - int component = (direction_ == LEFT_RIGHT) ? HTRIGHT : HTBOTTOM; - return ::wm::CompoundEventFilter::CursorForWindowComponent(component); - } - - private: - MultiWindowResizeController* controller_; - const Direction direction_; - const gfx::ImageSkia* image_; - - DISALLOW_COPY_AND_ASSIGN(ResizeView); -}; - -// MouseWatcherHost implementation for MultiWindowResizeController. Forwards -// Contains() to MultiWindowResizeController. -class MultiWindowResizeController::ResizeMouseWatcherHost - : public views::MouseWatcherHost { - public: - ResizeMouseWatcherHost(MultiWindowResizeController* host) : host_(host) {} - - // MouseWatcherHost overrides: - bool Contains(const gfx::Point& point_in_screen, - MouseEventType type) override { - return (type == MOUSE_PRESS) ? host_->IsOverResizeWidget(point_in_screen) - : host_->IsOverWindows(point_in_screen); - } - - private: - MultiWindowResizeController* host_; - - DISALLOW_COPY_AND_ASSIGN(ResizeMouseWatcherHost); -}; - -MultiWindowResizeController::ResizeWindows::ResizeWindows() - : window1(nullptr), window2(nullptr), direction(TOP_BOTTOM) {} - -MultiWindowResizeController::ResizeWindows::ResizeWindows( - const ResizeWindows& other) = default; - -MultiWindowResizeController::ResizeWindows::~ResizeWindows() {} - -bool MultiWindowResizeController::ResizeWindows::Equals( - const ResizeWindows& other) const { - return window1 == other.window1 && window2 == other.window2 && - direction == other.direction; -} - -MultiWindowResizeController::MultiWindowResizeController() {} - -MultiWindowResizeController::~MultiWindowResizeController() { - window_resizer_.reset(); - Hide(); -} - -void MultiWindowResizeController::Show(WmWindow* window, - int component, - const gfx::Point& point_in_window) { - // When the resize widget is showing we ignore Show() requests. Instead we - // only care about mouse movements from MouseWatcher. This is necessary as - // WorkspaceEventHandler only sees mouse movements over the windows, not all - // windows or over the desktop. - if (resize_widget_) - return; - - ResizeWindows windows(DetermineWindows(window, component, point_in_window)); - if (IsShowing() && windows_.Equals(windows)) - return; - - Hide(); - if (!windows.is_valid()) { - windows_ = ResizeWindows(); - return; - } - - windows_ = windows; - windows_.window1->aura_window()->AddObserver(this); - windows_.window2->aura_window()->AddObserver(this); - show_location_in_parent_ = - window->ConvertPointToTarget(window->GetParent(), point_in_window); - show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMS), - this, - &MultiWindowResizeController::ShowIfValidMouseLocation); -} - -void MultiWindowResizeController::Hide() { - if (window_resizer_) - return; // Ignore hides while actively resizing. - - if (windows_.window1) { - windows_.window1->aura_window()->RemoveObserver(this); - windows_.window1 = NULL; - } - if (windows_.window2) { - windows_.window2->aura_window()->RemoveObserver(this); - windows_.window2 = NULL; - } - - show_timer_.Stop(); - - if (!resize_widget_) - return; - - for (size_t i = 0; i < windows_.other_windows.size(); ++i) - windows_.other_windows[i]->aura_window()->RemoveObserver(this); - mouse_watcher_.reset(); - resize_widget_.reset(); - windows_ = ResizeWindows(); -} - -void MultiWindowResizeController::MouseMovedOutOfHost() { - Hide(); -} - -void MultiWindowResizeController::OnWindowDestroying(aura::Window* window) { - // Have to explicitly reset the WindowResizer, otherwise Hide() does nothing. - window_resizer_.reset(); - Hide(); -} - -MultiWindowResizeController::ResizeWindows -MultiWindowResizeController::DetermineWindowsFromScreenPoint( - WmWindow* window) const { - gfx::Point mouse_location( - display::Screen::GetScreen()->GetCursorScreenPoint()); - mouse_location = window->ConvertPointFromScreen(mouse_location); - const int component = window->GetNonClientComponent(mouse_location); - return DetermineWindows(window, component, mouse_location); -} - -void MultiWindowResizeController::CreateMouseWatcher() { - mouse_watcher_.reset( - new views::MouseWatcher(new ResizeMouseWatcherHost(this), this)); - mouse_watcher_->set_notify_on_exit_time( - base::TimeDelta::FromMilliseconds(kHideDelayMS)); - mouse_watcher_->Start(); -} - -MultiWindowResizeController::ResizeWindows -MultiWindowResizeController::DetermineWindows(WmWindow* window, - int window_component, - const gfx::Point& point) const { - ResizeWindows result; - gfx::Point point_in_parent = - window->ConvertPointToTarget(window->GetParent(), point); - switch (window_component) { - case HTRIGHT: - result.direction = LEFT_RIGHT; - result.window1 = window; - result.window2 = FindWindowByEdge( - window, HTLEFT, window->GetBounds().right(), point_in_parent.y()); - break; - case HTLEFT: - result.direction = LEFT_RIGHT; - result.window1 = FindWindowByEdge( - window, HTRIGHT, window->GetBounds().x(), point_in_parent.y()); - result.window2 = window; - break; - case HTTOP: - result.direction = TOP_BOTTOM; - result.window1 = FindWindowByEdge(window, HTBOTTOM, point_in_parent.x(), - window->GetBounds().y()); - result.window2 = window; - break; - case HTBOTTOM: - result.direction = TOP_BOTTOM; - result.window1 = window; - result.window2 = FindWindowByEdge(window, HTTOP, point_in_parent.x(), - window->GetBounds().bottom()); - break; - default: - break; - } - return result; -} - -WmWindow* MultiWindowResizeController::FindWindowByEdge( - WmWindow* window_to_ignore, - int edge_want, - int x_in_parent, - int y_in_parent) const { - WmWindow* parent = window_to_ignore->GetParent(); - std::vector<WmWindow*> windows = parent->GetChildren(); - for (auto i = windows.rbegin(); i != windows.rend(); ++i) { - WmWindow* window = *i; - if (window == window_to_ignore || !window->IsVisible()) - continue; - - // Ignore windows without a non-client area. - if (!window->HasNonClientArea()) - continue; - - gfx::Point p = parent->ConvertPointToTarget( - window, gfx::Point(x_in_parent, y_in_parent)); - switch (edge_want) { - case HTLEFT: - if (ContainsY(window, p.y()) && p.x() == 0) - return window; - break; - case HTRIGHT: - if (ContainsY(window, p.y()) && p.x() == window->GetBounds().width()) - return window; - break; - case HTTOP: - if (ContainsX(window, p.x()) && p.y() == 0) - return window; - break; - case HTBOTTOM: - if (ContainsX(window, p.x()) && p.y() == window->GetBounds().height()) - return window; - break; - default: - NOTREACHED(); - } - // Window doesn't contain the edge, but if window contains |point| - // it's obscuring any other window that could be at the location. - if (window->GetBounds().Contains(x_in_parent, y_in_parent)) - return NULL; - } - return NULL; -} - -WmWindow* MultiWindowResizeController::FindWindowTouching( - WmWindow* window, - Direction direction) const { - int right = window->GetBounds().right(); - int bottom = window->GetBounds().bottom(); - WmWindow* parent = window->GetParent(); - std::vector<WmWindow*> windows = parent->GetChildren(); - for (auto i = windows.rbegin(); i != windows.rend(); ++i) { - WmWindow* other = *i; - if (other == window || !other->IsVisible()) - continue; - switch (direction) { - case TOP_BOTTOM: - if (other->GetBounds().y() == bottom && - Intersects(other->GetBounds().x(), other->GetBounds().right(), - window->GetBounds().x(), window->GetBounds().right())) { - return other; - } - break; - case LEFT_RIGHT: - if (other->GetBounds().x() == right && - Intersects(other->GetBounds().y(), other->GetBounds().bottom(), - window->GetBounds().y(), window->GetBounds().bottom())) { - return other; - } - break; - default: - NOTREACHED(); - } - } - return NULL; -} - -void MultiWindowResizeController::FindWindowsTouching( - WmWindow* start, - Direction direction, - std::vector<WmWindow*>* others) const { - while (start) { - start = FindWindowTouching(start, direction); - if (start) - others->push_back(start); - } -} - -void MultiWindowResizeController::ShowIfValidMouseLocation() { - if (DetermineWindowsFromScreenPoint(windows_.window1).Equals(windows_) || - DetermineWindowsFromScreenPoint(windows_.window2).Equals(windows_)) { - ShowNow(); - } else { - Hide(); - } -} - -void MultiWindowResizeController::ShowNow() { - DCHECK(!resize_widget_.get()); - DCHECK(windows_.is_valid()); - show_timer_.Stop(); - resize_widget_.reset(new views::Widget); - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); - params.name = "MultiWindowResizeController"; - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - windows_.window1->GetRootWindowController() - ->ConfigureWidgetInitParamsForContainer( - resize_widget_.get(), kShellWindowId_AlwaysOnTopContainer, ¶ms); - ResizeView* view = new ResizeView(this, windows_.direction); - resize_widget_->set_focus_on_creation(false); - resize_widget_->Init(params); - WmWindow::Get(resize_widget_->GetNativeWindow()) - ->SetVisibilityAnimationType(::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); - resize_widget_->SetContentsView(view); - show_bounds_in_screen_ = windows_.window1->GetParent()->ConvertRectToScreen( - CalculateResizeWidgetBounds(show_location_in_parent_)); - resize_widget_->SetBounds(show_bounds_in_screen_); - resize_widget_->Show(); - CreateMouseWatcher(); -} - -bool MultiWindowResizeController::IsShowing() const { - return resize_widget_.get() || show_timer_.IsRunning(); -} - -void MultiWindowResizeController::StartResize( - const gfx::Point& location_in_screen) { - DCHECK(!window_resizer_.get()); - DCHECK(windows_.is_valid()); - gfx::Point location_in_parent = - windows_.window2->GetParent()->ConvertPointFromScreen(location_in_screen); - std::vector<WmWindow*> windows; - windows.push_back(windows_.window2); - DCHECK(windows_.other_windows.empty()); - FindWindowsTouching(windows_.window2, windows_.direction, - &windows_.other_windows); - for (size_t i = 0; i < windows_.other_windows.size(); ++i) { - windows_.other_windows[i]->aura_window()->AddObserver(this); - windows.push_back(windows_.other_windows[i]); - } - int component = windows_.direction == LEFT_RIGHT ? HTRIGHT : HTBOTTOM; - wm::WindowState* window_state = windows_.window1->GetWindowState(); - window_state->CreateDragDetails(location_in_parent, component, - aura::client::WINDOW_MOVE_SOURCE_MOUSE); - window_resizer_.reset(WorkspaceWindowResizer::Create(window_state, windows)); - - // Do not hide the resize widget while a drag is active. - mouse_watcher_.reset(); -} - -void MultiWindowResizeController::Resize(const gfx::Point& location_in_screen, - int event_flags) { - gfx::Point location_in_parent = - windows_.window1->GetParent()->ConvertPointFromScreen(location_in_screen); - window_resizer_->Drag(location_in_parent, event_flags); - gfx::Rect bounds = windows_.window1->GetParent()->ConvertRectToScreen( - CalculateResizeWidgetBounds(location_in_parent)); - - if (windows_.direction == LEFT_RIGHT) - bounds.set_y(show_bounds_in_screen_.y()); - else - bounds.set_x(show_bounds_in_screen_.x()); - resize_widget_->SetBounds(bounds); -} - -void MultiWindowResizeController::CompleteResize() { - window_resizer_->CompleteDrag(); - window_resizer_->GetTarget()->GetWindowState()->DeleteDragDetails(); - window_resizer_.reset(); - - // Mouse may still be over resizer, if not hide. - gfx::Point screen_loc = display::Screen::GetScreen()->GetCursorScreenPoint(); - if (!resize_widget_->GetWindowBoundsInScreen().Contains(screen_loc)) { - Hide(); - } else { - // If the mouse is over the resizer we need to remove observers on any of - // the |other_windows|. If we start another resize we'll recalculate the - // |other_windows| and invoke AddObserver() as necessary. - for (size_t i = 0; i < windows_.other_windows.size(); ++i) - windows_.other_windows[i]->aura_window()->RemoveObserver(this); - windows_.other_windows.clear(); - - CreateMouseWatcher(); - } -} - -void MultiWindowResizeController::CancelResize() { - if (!window_resizer_) - return; // Happens if window was destroyed and we nuked the WindowResizer. - window_resizer_->RevertDrag(); - window_resizer_->GetTarget()->GetWindowState()->DeleteDragDetails(); - window_resizer_.reset(); - Hide(); -} - -gfx::Rect MultiWindowResizeController::CalculateResizeWidgetBounds( - const gfx::Point& location_in_parent) const { - gfx::Size pref = resize_widget_->GetContentsView()->GetPreferredSize(); - int x = 0, y = 0; - if (windows_.direction == LEFT_RIGHT) { - x = windows_.window1->GetBounds().right() - pref.width() / 2; - y = location_in_parent.y() + kResizeWidgetPadding; - if (y + pref.height() / 2 > windows_.window1->GetBounds().bottom() && - y + pref.height() / 2 > windows_.window2->GetBounds().bottom()) { - y = location_in_parent.y() - kResizeWidgetPadding - pref.height(); - } - } else { - x = location_in_parent.x() + kResizeWidgetPadding; - if (x + pref.height() / 2 > windows_.window1->GetBounds().right() && - x + pref.height() / 2 > windows_.window2->GetBounds().right()) { - x = location_in_parent.x() - kResizeWidgetPadding - pref.width(); - } - y = windows_.window1->GetBounds().bottom() - pref.height() / 2; - } - return gfx::Rect(x, y, pref.width(), pref.height()); -} - -bool MultiWindowResizeController::IsOverResizeWidget( - const gfx::Point& location_in_screen) const { - return resize_widget_->GetWindowBoundsInScreen().Contains(location_in_screen); -} - -bool MultiWindowResizeController::IsOverWindows( - const gfx::Point& location_in_screen) const { - if (IsOverResizeWidget(location_in_screen)) - return true; - - if (windows_.direction == TOP_BOTTOM) { - if (!ContainsScreenX(windows_.window1, location_in_screen.x()) || - !ContainsScreenX(windows_.window2, location_in_screen.x())) { - return false; - } - } else { - if (!ContainsScreenY(windows_.window1, location_in_screen.y()) || - !ContainsScreenY(windows_.window2, location_in_screen.y())) { - return false; - } - } - - // Check whether |location_in_screen| is in the event target's resize region. - // This is tricky because a window's resize region can extend outside a - // window's bounds. - WmWindow* target = - windows_.window1->GetRootWindowController()->FindEventTarget( - location_in_screen); - if (target == windows_.window1) { - return IsOverComponent( - windows_.window1, location_in_screen, - windows_.direction == TOP_BOTTOM ? HTBOTTOM : HTRIGHT); - } - if (target == windows_.window2) { - return IsOverComponent(windows_.window2, location_in_screen, - windows_.direction == TOP_BOTTOM ? HTTOP : HTLEFT); - } - return false; -} - -bool MultiWindowResizeController::IsOverComponent( - WmWindow* window, - const gfx::Point& location_in_screen, - int component) const { - gfx::Point window_loc = window->ConvertPointFromScreen(location_in_screen); - return window->GetNonClientComponent(window_loc) == component; -} - -} // namespace ash
diff --git a/ash/wm/workspace/multi_window_resize_controller.h b/ash/wm/workspace/multi_window_resize_controller.h deleted file mode 100644 index e7609bc..0000000 --- a/ash/wm/workspace/multi_window_resize_controller.h +++ /dev/null
@@ -1,180 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_ -#define ASH_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_ - -#include <memory> -#include <vector> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/timer/timer.h" -#include "ui/aura/window_observer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/mouse_watcher.h" - -namespace views { -class Widget; -} - -namespace ash { -class MultiWindowResizeControllerTest; -class WmWindow; -class WorkspaceWindowResizer; - -// Two directions resizes happen in. -enum Direction { - TOP_BOTTOM, - LEFT_RIGHT, -}; - -// MultiWindowResizeController is responsible for determining and showing a -// widget that allows resizing multiple windows at the same time. -// MultiWindowResizeController is driven by WorkspaceEventFilter. -class ASH_EXPORT MultiWindowResizeController - : public views::MouseWatcherListener, - public aura::WindowObserver { - public: - MultiWindowResizeController(); - ~MultiWindowResizeController() override; - - // If necessary, shows the resize widget. |window| is the window the mouse - // is over, |component| the edge and |point| the location of the mouse. - void Show(WmWindow* window, int component, const gfx::Point& point); - - // Hides the resize widget. - void Hide(); - - // MouseWatcherListenre overrides: - void MouseMovedOutOfHost() override; - - // WindowObserver overrides: - void OnWindowDestroying(aura::Window* window) override; - - private: - friend class MultiWindowResizeControllerTest; - - // Used to track the two resizable windows and direction. - struct ResizeWindows { - ResizeWindows(); - ResizeWindows(const ResizeWindows& other); - ~ResizeWindows(); - - // Returns true if |other| equals this ResizeWindows. This does *not* - // consider the windows in |other_windows|. - bool Equals(const ResizeWindows& other) const; - - // Returns true if this ResizeWindows is valid. - bool is_valid() const { return window1 && window2; } - - // The left/top window to resize. - WmWindow* window1; - - // Other window to resize. - WmWindow* window2; - - // Direction - Direction direction; - - // Windows after |window2| that are to be resized. Determined at the time - // the resize starts. - std::vector<WmWindow*> other_windows; - }; - - class ResizeMouseWatcherHost; - class ResizeView; - - void CreateMouseWatcher(); - - // Returns a ResizeWindows based on the specified arguments. Use is_valid() - // to test if the return value is a valid multi window resize location. - ResizeWindows DetermineWindows(WmWindow* window, - int window_component, - const gfx::Point& point) const; - - // Variant of DetermineWindows() that uses the current location of the mouse - // to determine the resize windows. - ResizeWindows DetermineWindowsFromScreenPoint(WmWindow* window) const; - - // Finds a window by edge (one of the constants HitTestCompat. - WmWindow* FindWindowByEdge(WmWindow* window_to_ignore, - int edge_want, - int x_in_parent, - int y_in_parent) const; - - // Returns the first window touching |window|. - WmWindow* FindWindowTouching(WmWindow* window, Direction direction) const; - - // Places any windows touching |start| into |others|. - void FindWindowsTouching(WmWindow* start, - Direction direction, - std::vector<WmWindow*>* others) const; - - // Shows the resizer if the mouse is still at a valid location. This is called - // from the |show_timer_|. - void ShowIfValidMouseLocation(); - - // Shows the widget immediately. - void ShowNow(); - - // Returns true if the widget is showing. - bool IsShowing() const; - - // Initiates a resize. - void StartResize(const gfx::Point& location_in_screen); - - // Resizes to the new location. - void Resize(const gfx::Point& location_in_screen, int event_flags); - - // Completes the resize. - void CompleteResize(); - - // Cancels the resize. - void CancelResize(); - - // Returns the bounds for the resize widget. - gfx::Rect CalculateResizeWidgetBounds( - const gfx::Point& location_in_parent) const; - - // Returns true if |location_in_screen| is over the resize widget. - bool IsOverResizeWidget(const gfx::Point& location_in_screen) const; - - // Returns true if |location_in_screen| is over the resize windows - // (or the resize widget itself). - bool IsOverWindows(const gfx::Point& location_in_screen) const; - - // Returns true if |location_in_screen| is over |component| in |window|. - bool IsOverComponent(WmWindow* window, - const gfx::Point& location_in_screen, - int component) const; - - // Windows and direction to resize. - ResizeWindows windows_; - - // Timer used before showing. - base::OneShotTimer show_timer_; - - std::unique_ptr<views::Widget> resize_widget_; - - // If non-null we're in a resize loop. - std::unique_ptr<WorkspaceWindowResizer> window_resizer_; - - // Mouse coordinate passed to Show() in container's coodinates. - gfx::Point show_location_in_parent_; - - // Bounds the widget was last shown at in screen coordinates. - gfx::Rect show_bounds_in_screen_; - - // Used to detect whether the mouse is over the windows. While - // |resize_widget_| is non-NULL (ie the widget is showing) we ignore calls - // to Show(). - std::unique_ptr<views::MouseWatcher> mouse_watcher_; - - DISALLOW_COPY_AND_ASSIGN(MultiWindowResizeController); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_MULTI_WINDOW_RESIZE_CONTROLLER_H_
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc index 0df8682..6fd0a13 100644 --- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc +++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/workspace/multi_window_resize_controller.h" +#include "ash/common/wm/workspace/multi_window_resize_controller.h" #include "ash/common/ash_constants.h" +#include "ash/common/frame/custom_frame_view_ash.h" +#include "ash/common/test/workspace_event_handler_test_helper.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/common/wm_window.h" -#include "ash/frame/custom_frame_view_ash.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/shell_test_api.h" -#include "ash/test/workspace_event_handler_test_helper.h" #include "ash/wm/window_util.h" -#include "ash/wm/workspace_controller.h" #include "ash/wm/workspace_controller_test_helper.h" #include "base/stl_util.h" #include "ui/aura/test/test_window_delegate.h"
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc deleted file mode 100644 index 5cb8b4d..0000000 --- a/ash/wm/workspace/phantom_window_controller.cc +++ /dev/null
@@ -1,151 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/phantom_window_controller.h" - -#include <math.h> - -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/resources/grit/ash_resources.h" -#include "ash/root_window_controller.h" -#include "ash/wm/root_window_finder.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" -#include "ui/views/background.h" -#include "ui/views/painter.h" -#include "ui/views/view.h" -#include "ui/views/widget/widget.h" - -namespace ash { -namespace { - -// The duration of the show animation. -const int kAnimationDurationMs = 200; - -// The size of the phantom window at the beginning of the show animation in -// relation to the size of the phantom window at the end of the animation. -const float kStartBoundsRatio = 0.85f; - -// The amount of pixels that the phantom window's shadow should extend past -// the bounds passed into Show(). -const int kShadowThickness = 15; - -// The minimum size of a phantom window including the shadow. The minimum size -// is derived from the size of the IDR_AURA_PHANTOM_WINDOW image assets. -const int kMinSizeWithShadow = 100; - -// Adjusts the phantom window's bounds so that the bounds: -// - Include the size of the shadow. -// - Have a size equal to or larger than the minimum phantom window size. -gfx::Rect GetAdjustedBounds(const gfx::Rect& bounds) { - int x_inset = std::max( - static_cast<int>(ceil((kMinSizeWithShadow - bounds.width()) / 2.0f)), - kShadowThickness); - int y_inset = std::max( - static_cast<int>(ceil((kMinSizeWithShadow - bounds.height()) / 2.0f)), - kShadowThickness); - - gfx::Rect adjusted_bounds(bounds); - adjusted_bounds.Inset(-x_inset, -y_inset); - return adjusted_bounds; -} - -// Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget| -// is NULL. -void AnimateToBounds(views::Widget* widget, - const gfx::Rect& new_bounds_in_screen) { - if (!widget) - return; - - ui::ScopedLayerAnimationSettings scoped_setter( - WmWindow::Get(widget->GetNativeWindow())->GetLayer()->GetAnimator()); - scoped_setter.SetTweenType(gfx::Tween::EASE_IN); - scoped_setter.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - scoped_setter.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); - widget->SetBounds(new_bounds_in_screen); -} - -} // namespace - -// PhantomWindowController ---------------------------------------------------- - -PhantomWindowController::PhantomWindowController(WmWindow* window) - : window_(window) {} - -PhantomWindowController::~PhantomWindowController() {} - -void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) { - gfx::Rect adjusted_bounds_in_screen = GetAdjustedBounds(bounds_in_screen); - if (adjusted_bounds_in_screen == target_bounds_in_screen_) - return; - target_bounds_in_screen_ = adjusted_bounds_in_screen; - - gfx::Rect start_bounds_in_screen = target_bounds_in_screen_; - int start_width = std::max( - kMinSizeWithShadow, - static_cast<int>(start_bounds_in_screen.width() * kStartBoundsRatio)); - int start_height = std::max( - kMinSizeWithShadow, - static_cast<int>(start_bounds_in_screen.height() * kStartBoundsRatio)); - start_bounds_in_screen.Inset( - floor((start_bounds_in_screen.width() - start_width) / 2.0f), - floor((start_bounds_in_screen.height() - start_height) / 2.0f)); - phantom_widget_ = - CreatePhantomWidget(wm::GetRootWindowMatching(target_bounds_in_screen_), - start_bounds_in_screen); - - AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_); -} - -std::unique_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget( - WmWindow* root_window, - const gfx::Rect& bounds_in_screen) { - std::unique_ptr<views::Widget> phantom_widget(new views::Widget); - views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - // PhantomWindowController is used by FrameMaximizeButton to highlight the - // launcher button. Put the phantom in the same window as the launcher so that - // the phantom is visible. - params.keep_on_top = true; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.name = "PhantomWindow"; - root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer( - phantom_widget.get(), kShellWindowId_ShelfContainer, ¶ms); - phantom_widget->set_focus_on_creation(false); - phantom_widget->Init(params); - phantom_widget->SetVisibilityChangedAnimationsEnabled(false); - WmWindow* phantom_widget_window = - WmWindow::Get(phantom_widget->GetNativeWindow()); - phantom_widget_window->SetShellWindowId(kShellWindowId_PhantomWindow); - phantom_widget->SetBounds(bounds_in_screen); - // TODO(sky): I suspect this is never true, verify that. - if (phantom_widget_window->GetParent() == window_->GetParent()) { - phantom_widget_window->GetParent()->StackChildAbove(phantom_widget_window, - window_); - } - - const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW); - views::View* content_view = new views::View; - content_view->set_background(views::Background::CreateBackgroundPainter( - views::Painter::CreateImageGridPainter(kImages))); - phantom_widget->SetContentsView(content_view); - - // Show the widget after all the setups. - phantom_widget->Show(); - - // Fade the window in. - ui::Layer* widget_layer = phantom_widget_window->GetLayer(); - widget_layer->SetOpacity(0); - ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator()); - scoped_setter.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); - widget_layer->SetOpacity(1); - - return phantom_widget; -} - -} // namespace ash
diff --git a/ash/wm/workspace/phantom_window_controller.h b/ash/wm/workspace/phantom_window_controller.h deleted file mode 100644 index 4a43aba..0000000 --- a/ash/wm/workspace/phantom_window_controller.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_PHANTOM_WINDOW_CONTROLLER_H_ -#define ASH_WM_WORKSPACE_PHANTOM_WINDOW_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "ui/gfx/geometry/rect.h" - -namespace views { -class Widget; -} - -namespace ash { - -class WmWindow; - -// PhantomWindowController is responsible for showing a phantom representation -// of a window. It's used to show a preview of how snapping or docking a window -// will affect the window's bounds. -class ASH_EXPORT PhantomWindowController { - public: - explicit PhantomWindowController(WmWindow* window); - - // Hides the phantom window without any animation. - ~PhantomWindowController(); - - // Shows the phantom window and animates shrinking it to |bounds_in_screen|. - void Show(const gfx::Rect& bounds_in_screen); - - private: - // Creates, shows and returns a phantom widget at |bounds| - // with kShellWindowId_ShelfContainer in |root_window| as a parent. - std::unique_ptr<views::Widget> CreatePhantomWidget( - WmWindow* root_window, - const gfx::Rect& bounds_in_screen); - - // Window that the phantom window is stacked above. - WmWindow* window_; - - // Target bounds (including the shadows if any) of the animation in screen - // coordinates. - gfx::Rect target_bounds_in_screen_; - - // Phantom representation of the window. - std::unique_ptr<views::Widget> phantom_widget_; - - DISALLOW_COPY_AND_ASSIGN(PhantomWindowController); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_PHANTOM_WINDOW_CONTROLLER_H_
diff --git a/ash/wm/workspace/two_step_edge_cycler.cc b/ash/wm/workspace/two_step_edge_cycler.cc deleted file mode 100644 index f8485e01..0000000 --- a/ash/wm/workspace/two_step_edge_cycler.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/two_step_edge_cycler.h" - -#include <cstdlib> - -namespace ash { -namespace { - -// We cycle to the second mode if any of the following happens while the mouse -// is on the edge of the workspace: -// . The user stops moving the mouse for |kMaxDelay| and then moves the mouse -// again in the preferred direction from the last paused location for at least -// |kMaxPixelsAfterPause| horizontal pixels. -// . The mouse moves |kMaxPixels| horizontal pixels in the preferred direction. -// . The mouse is moved |kMaxMoves| times since the last pause. -const int kMaxDelay = 400; -const int kMaxPixels = 100; -const int kMaxPixelsAfterPause = 10; -const int kMaxMoves = 25; - -} // namespace - -TwoStepEdgeCycler::TwoStepEdgeCycler(const gfx::Point& start, - TwoStepEdgeCycler::Direction direction) - : second_mode_(false), - time_last_move_(base::TimeTicks::Now()), - num_moves_(0), - start_x_(start.x()), - paused_x_(start.x()), - paused_(false), - direction_(direction) {} - -TwoStepEdgeCycler::~TwoStepEdgeCycler() {} - -void TwoStepEdgeCycler::OnMove(const gfx::Point& location) { - if (second_mode_) - return; - - if ((base::TimeTicks::Now() - time_last_move_).InMilliseconds() > kMaxDelay) { - paused_ = true; - paused_x_ = location.x(); - num_moves_ = 0; - } - time_last_move_ = base::TimeTicks::Now(); - - int compare_x = paused_ ? paused_x_ : start_x_; - if (location.x() != compare_x && - (location.x() < compare_x) != (direction_ == DIRECTION_LEFT)) { - return; - } - - ++num_moves_; - bool moved_in_the_same_direction_after_pause = - paused_ && std::abs(location.x() - paused_x_) >= kMaxPixelsAfterPause; - second_mode_ = moved_in_the_same_direction_after_pause || - std::abs(location.x() - start_x_) >= kMaxPixels || - num_moves_ >= kMaxMoves; -} - -} // namespace ash
diff --git a/ash/wm/workspace/two_step_edge_cycler.h b/ash/wm/workspace/two_step_edge_cycler.h deleted file mode 100644 index d6aca87ee..0000000 --- a/ash/wm/workspace/two_step_edge_cycler.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_TWO_STEP_EDGE_CYCLER_H_ -#define ASH_WM_WORKSPACE_TWO_STEP_EDGE_CYCLER_H_ - -#include "ash/ash_export.h" -#include "base/macros.h" -#include "base/time/time.h" -#include "ui/gfx/geometry/point.h" - -namespace ash { - -// TwoStepEdgeCycler is responsible for cycling between two modes when the mouse -// is at the edge of the workspace. The cycler does not loop so it is impossible -// to get back to the first mode once the second mode is reached. -// TwoStepEdgeCycler should be destroyed once the mouse moves off the edge of -// the workspace. -class ASH_EXPORT TwoStepEdgeCycler { - public: - // The direction in which a mouse should travel to switch mode. - enum Direction { DIRECTION_LEFT, DIRECTION_RIGHT }; - - explicit TwoStepEdgeCycler(const gfx::Point& start, Direction direction); - ~TwoStepEdgeCycler(); - - // Update which mode should be used as a result of a mouse / touch move. - // |location| is the location of the event. - void OnMove(const gfx::Point& location); - - bool use_second_mode() const { return second_mode_; } - - private: - // Whether the second mode should be used. - bool second_mode_; - - // Time OnMove() was last invoked. - base::TimeTicks time_last_move_; - - // The number of moves since the cycler was constructed. - int num_moves_; - - // Initial x-coordinate. - int start_x_; - - // x-coordinate when paused. - int paused_x_; - - // Whether the movement was paused. - bool paused_; - - // Determines a preferred movement direction that we are watching. - Direction direction_; - - DISALLOW_COPY_AND_ASSIGN(TwoStepEdgeCycler); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_TWO_STEP_EDGE_CYCLER_H_
diff --git a/ash/wm/workspace/workspace_event_handler.cc b/ash/wm/workspace/workspace_event_handler.cc deleted file mode 100644 index e5e96cb0..0000000 --- a/ash/wm/workspace/workspace_event_handler.cc +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/workspace_event_handler.h" - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ui/base/hit_test.h" -#include "ui/events/event.h" - -namespace ash { - -WorkspaceEventHandler::WorkspaceEventHandler() : click_component_(HTNOWHERE) {} - -WorkspaceEventHandler::~WorkspaceEventHandler() {} - -void WorkspaceEventHandler::OnMouseEvent(ui::MouseEvent* event, - WmWindow* target) { - if (event->type() == ui::ET_MOUSE_PRESSED && event->IsOnlyLeftMouseButton() && - ((event->flags() & (ui::EF_IS_DOUBLE_CLICK | ui::EF_IS_TRIPLE_CLICK)) == - 0)) { - click_component_ = target->GetNonClientComponent(event->location()); - } - - if (event->handled()) - return; - - switch (event->type()) { - case ui::ET_MOUSE_MOVED: { - int component = target->GetNonClientComponent(event->location()); - multi_window_resize_controller_.Show(target, component, - event->location()); - break; - } - case ui::ET_MOUSE_ENTERED: - break; - case ui::ET_MOUSE_CAPTURE_CHANGED: - case ui::ET_MOUSE_EXITED: - break; - case ui::ET_MOUSE_PRESSED: { - wm::WindowState* target_state = target->GetWindowState(); - - if (event->IsOnlyLeftMouseButton()) { - if (event->flags() & ui::EF_IS_DOUBLE_CLICK) { - int component = target->GetNonClientComponent(event->location()); - if (component == HTCAPTION && component == click_component_) { - WmShell::Get()->RecordUserMetricsAction( - UMA_TOGGLE_MAXIMIZE_CAPTION_CLICK); - const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION); - target_state->OnWMEvent(&wm_event); - event->StopPropagation(); - } - click_component_ = HTNOWHERE; - } - } else { - click_component_ = HTNOWHERE; - } - - HandleVerticalResizeDoubleClick(target_state, event); - break; - } - default: - break; - } -} - -void WorkspaceEventHandler::OnGestureEvent(ui::GestureEvent* event, - WmWindow* target) { - if (event->handled() || event->type() != ui::ET_GESTURE_TAP) - return; - - int previous_target_component = click_component_; - click_component_ = target->GetNonClientComponent(event->location()); - - if (click_component_ != HTCAPTION) - return; - - if (event->details().tap_count() != 2) { - WmShell::Get()->RecordGestureAction(GESTURE_FRAMEVIEW_TAP); - return; - } - - if (click_component_ == previous_target_component) { - WmShell::Get()->RecordUserMetricsAction( - UMA_TOGGLE_MAXIMIZE_CAPTION_GESTURE); - WmShell::Get()->RecordGestureAction(GESTURE_MAXIMIZE_DOUBLETAP); - const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION); - target->GetWindowState()->OnWMEvent(&wm_event); - event->StopPropagation(); - } - click_component_ = HTNOWHERE; -} - -void WorkspaceEventHandler::HandleVerticalResizeDoubleClick( - wm::WindowState* target_state, - ui::MouseEvent* event) { - WmWindow* target = target_state->window(); - if (event->flags() & ui::EF_IS_DOUBLE_CLICK) { - int component = target->GetNonClientComponent(event->location()); - if (component == HTBOTTOM || component == HTTOP) { - WmShell::Get()->RecordUserMetricsAction( - UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK); - const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_VERTICAL_MAXIMIZE); - target_state->OnWMEvent(&wm_event); - event->StopPropagation(); - } else if (component == HTLEFT || component == HTRIGHT) { - WmShell::Get()->RecordUserMetricsAction( - UMA_TOGGLE_SINGLE_AXIS_MAXIMIZE_BORDER_CLICK); - const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_HORIZONTAL_MAXIMIZE); - target_state->OnWMEvent(&wm_event); - event->StopPropagation(); - } - } -} - -} // namespace ash
diff --git a/ash/wm/workspace/workspace_event_handler.h b/ash/wm/workspace/workspace_event_handler.h deleted file mode 100644 index d400eeb..0000000 --- a/ash/wm/workspace/workspace_event_handler.h +++ /dev/null
@@ -1,61 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_H_ - -#include "ash/ash_export.h" -#include "ash/wm/workspace/multi_window_resize_controller.h" -#include "base/macros.h" - -namespace ui { -class GestureEvent; -class MouseEvent; -} - -namespace ash { -class WmWindow; -class WorkspaceEventHandlerTestHelper; - -namespace wm { -class WindowState; -} - -// ui::EventHandler like class installed on the window associated with -// WorkspaceLayoutManager. This handles various events happening on child -// windows and takes appropriate action. It is expected the environment specific -// file calls OnMouseEvent()/OnGestureEvent() as appropriate. -class ASH_EXPORT WorkspaceEventHandler { - public: - WorkspaceEventHandler(); - virtual ~WorkspaceEventHandler(); - - void OnMouseEvent(ui::MouseEvent* event, WmWindow* target); - void OnGestureEvent(ui::GestureEvent* event, WmWindow* target); - - private: - friend class WorkspaceEventHandlerTestHelper; - - // Determines if |event| corresponds to a double click on either the top or - // bottom vertical resize edge, and if so toggles the vertical height of the - // window between its restored state and the full available height of the - // workspace. - void HandleVerticalResizeDoubleClick(wm::WindowState* window_state, - ui::MouseEvent* event); - - MultiWindowResizeController multi_window_resize_controller_; - - // The non-client component for the target of a MouseEvent or GestureEvent. - // Events can be destructive to the window tree, which can cause the - // component of a ui::EF_IS_DOUBLE_CLICK event to no longer be the same as - // that of the initial click. Acting on a double click should only occur for - // matching components. This will be set for left clicks, and tap events. - int click_component_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceEventHandler); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_H_
diff --git a/ash/wm/workspace/workspace_event_handler_aura.h b/ash/wm/workspace/workspace_event_handler_aura.h index 28fcae58..a8e084d 100644 --- a/ash/wm/workspace/workspace_event_handler_aura.h +++ b/ash/wm/workspace/workspace_event_handler_aura.h
@@ -5,7 +5,7 @@ #ifndef ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_AURA_H_ #define ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_AURA_H_ -#include "ash/wm/workspace/workspace_event_handler.h" +#include "ash/common/wm/workspace/workspace_event_handler.h" #include "base/macros.h" #include "ui/events/event_handler.h"
diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc index 17fc85c..249c9c3c 100644 --- a/ash/wm/workspace/workspace_event_handler_unittest.cc +++ b/ash/wm/workspace/workspace_event_handler_unittest.cc
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/workspace/workspace_event_handler.h" +#include "ash/common/wm/workspace/workspace_event_handler.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/screen_util.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace_controller.h" #include "ash/wm/workspace_controller_test_helper.h" #include "base/threading/thread_task_runner_handle.h" #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc deleted file mode 100644 index ebfec663..0000000 --- a/ash/wm/workspace/workspace_layout_manager.cc +++ /dev/null
@@ -1,387 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/workspace_layout_manager.h" - -#include <algorithm> - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/always_on_top_controller.h" -#include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h" -#include "base/command_line.h" -#include "ui/aura/client/aura_constants.h" -#include "ui/base/ui_base_switches.h" -#include "ui/compositor/layer.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/keyboard/keyboard_controller.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace ash { - -WorkspaceLayoutManager::WorkspaceLayoutManager(WmWindow* window) - : window_(window), - root_window_(window->GetRootWindow()), - root_window_controller_(root_window_->GetRootWindowController()), - shell_(window_->GetShell()), - work_area_in_parent_(wm::GetDisplayWorkAreaBoundsInParent(window_)), - is_fullscreen_(wm::GetWindowForFullscreenMode(window) != nullptr) { - shell_->AddShellObserver(this); - shell_->AddActivationObserver(this); - root_window_->aura_window()->AddObserver(this); - display::Screen::GetScreen()->AddObserver(this); - DCHECK(window->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)); -} - -WorkspaceLayoutManager::~WorkspaceLayoutManager() { - if (root_window_) - root_window_->aura_window()->RemoveObserver(this); - for (WmWindow* window : windows_) { - wm::WindowState* window_state = window->GetWindowState(); - window_state->RemoveObserver(this); - window->aura_window()->RemoveObserver(this); - } - display::Screen::GetScreen()->RemoveObserver(this); - shell_->RemoveActivationObserver(this); - shell_->RemoveShellObserver(this); -} - -void WorkspaceLayoutManager::SetMaximizeBackdropDelegate( - std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate) { - backdrop_delegate_ = std::move(delegate); -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, aura::LayoutManager implementation: - -void WorkspaceLayoutManager::OnWindowResized() {} - -void WorkspaceLayoutManager::OnWindowAddedToLayout(WmWindow* child) { - wm::WindowState* window_state = child->GetWindowState(); - wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE); - window_state->OnWMEvent(&event); - windows_.insert(child); - child->aura_window()->AddObserver(this); - window_state->AddObserver(this); - UpdateShelfVisibility(); - UpdateFullscreenState(); - if (backdrop_delegate_) - backdrop_delegate_->OnWindowAddedToLayout(child); - WindowPositioner::RearrangeVisibleWindowOnShow(child); - if (WmShell::Get()->IsPinned()) - child->GetWindowState()->DisableAlwaysOnTop(nullptr); -} - -void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) { - windows_.erase(child); - child->aura_window()->RemoveObserver(this); - child->GetWindowState()->RemoveObserver(this); - - if (child->GetTargetVisibility()) - WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); -} - -void WorkspaceLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) { - UpdateShelfVisibility(); - UpdateFullscreenState(); - if (backdrop_delegate_) - backdrop_delegate_->OnWindowRemovedFromLayout(child); -} - -void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) { - wm::WindowState* window_state = child->GetWindowState(); - // Attempting to show a minimized window. Unminimize it. - if (visible && window_state->IsMinimized()) - window_state->Unminimize(); - - if (child->GetTargetVisibility()) - WindowPositioner::RearrangeVisibleWindowOnShow(child); - else - WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); - UpdateFullscreenState(); - UpdateShelfVisibility(); - if (backdrop_delegate_) - backdrop_delegate_->OnChildWindowVisibilityChanged(child, visible); -} - -void WorkspaceLayoutManager::SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) { - wm::SetBoundsEvent event(wm::WM_EVENT_SET_BOUNDS, requested_bounds); - child->GetWindowState()->OnWMEvent(&event); - UpdateShelfVisibility(); -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, keyboard::KeyboardControllerObserver implementation: - -void WorkspaceLayoutManager::OnKeyboardBoundsChanging( - const gfx::Rect& new_bounds) { - // If new window behavior flag enabled and in non-sticky mode, do not change - // the work area. - bool change_work_area = - (!base::CommandLine::ForCurrentProcess()->HasSwitch( - ::switches::kUseNewVirtualKeyboardBehavior) || - keyboard::KeyboardController::GetInstance()->keyboard_locked()); - if (!change_work_area) - return; - - WmWindow* window = shell_->GetActiveWindow(); - if (!window) - return; - - window = window->GetToplevelWindow(); - if (!window_->Contains(window)) - return; - - wm::WindowState* window_state = window->GetWindowState(); - if (window_state->ignore_keyboard_bounds_change()) - return; - - if (!new_bounds.IsEmpty()) { - // Store existing bounds to be restored before resizing for keyboard if it - // is not already stored. - if (!window_state->HasRestoreBounds()) - window_state->SaveCurrentBoundsForRestore(); - - gfx::Rect window_bounds = - window_->ConvertRectToScreen(window->GetTargetBounds()); - int vertical_displacement = - std::max(0, window_bounds.bottom() - new_bounds.y()); - int shift = std::min(vertical_displacement, - window_bounds.y() - work_area_in_parent_.y()); - if (shift > 0) { - gfx::Point origin(window_bounds.x(), window_bounds.y() - shift); - SetChildBounds(window, gfx::Rect(origin, window_bounds.size())); - } - } else if (window_state->HasRestoreBounds()) { - // Keyboard hidden, restore original bounds if they exist. If the user has - // resized or dragged the window in the meantime, WorkspaceWindowResizer - // will have cleared the restore bounds and this code will not accidentally - // override user intent. - window_state->SetAndClearRestoreBounds(); - } -} - -void WorkspaceLayoutManager::OnKeyboardClosed() {} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, aura::WindowObserver implementation: - -void WorkspaceLayoutManager::OnWindowHierarchyChanged( - const HierarchyChangeParams& params) { - if (!wm::GetWindowState(params.target)->IsActive()) - return; - // If the window is already tracked by the workspace this update would be - // redundant as the fullscreen and shelf state would have been handled in - // OnWindowAddedToLayout. - if (windows_.find(WmWindow::Get(params.target)) != windows_.end()) - return; - - // If the active window has moved to this root window then update the - // fullscreen state. - // TODO(flackr): Track the active window leaving this root window and update - // the fullscreen state accordingly. - if (params.new_parent && - WmWindow::Get(params.new_parent->GetRootWindow()) == root_window_) { - UpdateFullscreenState(); - UpdateShelfVisibility(); - } -} - -void WorkspaceLayoutManager::OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) { - if (key == aura::client::kAlwaysOnTopKey && - window->GetProperty(aura::client::kAlwaysOnTopKey)) { - WmWindow* container = - root_window_controller_->always_on_top_controller()->GetContainer( - WmWindow::Get(window)); - if (WmWindow::Get(window->parent()) != container) - container->AddChild(WmWindow::Get(window)); - } -} - -void WorkspaceLayoutManager::OnWindowStackingChanged(aura::Window* window) { - UpdateShelfVisibility(); - UpdateFullscreenState(); - if (backdrop_delegate_) - backdrop_delegate_->OnWindowStackingChanged(WmWindow::Get(window)); -} - -void WorkspaceLayoutManager::OnWindowDestroying(aura::Window* window) { - if (root_window_ == WmWindow::Get(window)) { - root_window_->aura_window()->RemoveObserver(this); - root_window_ = nullptr; - } -} - -void WorkspaceLayoutManager::OnWindowBoundsChanged( - aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) { - if (root_window_ == WmWindow::Get(window)) { - const wm::WMEvent wm_event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED); - AdjustAllWindowsBoundsForWorkAreaChange(&wm_event); - } -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, -// aura::client::ActivationChangeObserver implementation: - -void WorkspaceLayoutManager::OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) { - wm::WindowState* window_state = - gained_active ? gained_active->GetWindowState() : nullptr; - if (window_state && window_state->IsMinimized() && - !gained_active->IsVisible()) { - window_state->Unminimize(); - DCHECK(!window_state->IsMinimized()); - } - UpdateFullscreenState(); - UpdateShelfVisibility(); -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, wm::WindowStateObserver implementation: - -void WorkspaceLayoutManager::OnPostWindowStateTypeChange( - wm::WindowState* window_state, - wm::WindowStateType old_type) { - // Notify observers that fullscreen state may be changing. - if (window_state->IsFullscreen() || - old_type == wm::WINDOW_STATE_TYPE_FULLSCREEN) { - UpdateFullscreenState(); - } - - UpdateShelfVisibility(); - if (backdrop_delegate_) - backdrop_delegate_->OnPostWindowStateTypeChange(window_state, old_type); -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, display::DisplayObserver implementation: - -void WorkspaceLayoutManager::OnDisplayMetricsChanged( - const display::Display& display, - uint32_t changed_metrics) { - if (window_->GetDisplayNearestWindow().id() != display.id()) - return; - - const gfx::Rect work_area(wm::GetDisplayWorkAreaBoundsInParent(window_)); - if (work_area != work_area_in_parent_) { - const wm::WMEvent event(wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); - AdjustAllWindowsBoundsForWorkAreaChange(&event); - } - if (backdrop_delegate_) - backdrop_delegate_->OnDisplayWorkAreaInsetsChanged(); -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, ShellObserver implementation: - -void WorkspaceLayoutManager::OnFullscreenStateChanged(bool is_fullscreen, - WmWindow* root_window) { - if (root_window != root_window_ || is_fullscreen_ == is_fullscreen) - return; - - is_fullscreen_ = is_fullscreen; - if (WmShell::Get()->IsPinned()) { - // If this is in pinned mode, then this event does not trigger the - // always-on-top state change, because it is kept disabled regardless of - // the fullscreen state change. - return; - } - - UpdateAlwaysOnTop(is_fullscreen_ ? wm::GetWindowForFullscreenMode(window_) - : nullptr); -} - -void WorkspaceLayoutManager::OnPinnedStateChanged(WmWindow* pinned_window) { - if (!WmShell::Get()->IsPinned() && is_fullscreen_) { - // On exiting from pinned mode, if the workspace is still in fullscreen - // mode, then this event does not trigger the restoring yet. On exiting - // from fullscreen, the temporarily disabled always-on-top property will be - // restored. - return; - } - - UpdateAlwaysOnTop(WmShell::Get()->IsPinned() ? pinned_window : nullptr); -} - -////////////////////////////////////////////////////////////////////////////// -// WorkspaceLayoutManager, private: - -void WorkspaceLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange( - const wm::WMEvent* event) { - DCHECK(event->type() == wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED || - event->type() == wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED); - - work_area_in_parent_ = wm::GetDisplayWorkAreaBoundsInParent(window_); - - // Don't do any adjustments of the insets while we are in screen locked mode. - // This would happen if the launcher was auto hidden before the login screen - // was shown and then gets shown when the login screen gets presented. - if (event->type() == wm::WM_EVENT_WORKAREA_BOUNDS_CHANGED && - shell_->GetSessionStateDelegate()->IsScreenLocked()) - return; - - // If a user plugs an external display into a laptop running Aura the - // display size will change. Maximized windows need to resize to match. - // We also do this when developers running Aura on a desktop manually resize - // the host window. - // We also need to do this when the work area insets changes. - for (WmWindow* window : windows_) - window->GetWindowState()->OnWMEvent(event); -} - -void WorkspaceLayoutManager::UpdateShelfVisibility() { - if (root_window_controller_->HasShelf()) - root_window_controller_->GetShelf()->UpdateVisibilityState(); -} - -void WorkspaceLayoutManager::UpdateFullscreenState() { - // TODO(flackr): The fullscreen state is currently tracked per workspace - // but the shell notification implies a per root window state. Currently - // only windows in the default workspace container will go fullscreen but - // this should really be tracked by the RootWindowController since - // technically any container could get a fullscreen window. - if (window_->GetShellWindowId() != kShellWindowId_DefaultContainer) - return; - bool is_fullscreen = wm::GetWindowForFullscreenMode(window_) != nullptr; - if (is_fullscreen != is_fullscreen_) { - WmShell::Get()->NotifyFullscreenStateChanged(is_fullscreen, root_window_); - is_fullscreen_ = is_fullscreen; - } -} - -void WorkspaceLayoutManager::UpdateAlwaysOnTop(WmWindow* window_on_top) { - // Changing always on top state may change window's parent. Iterate on a copy - // of |windows_| to avoid invalidating an iterator. Since both workspace and - // always_on_top containers' layouts are managed by this class all the - // appropriate windows will be included in the iteration. - WindowSet windows(windows_); - for (auto* window : windows) { - wm::WindowState* window_state = window->GetWindowState(); - if (window_on_top) - window_state->DisableAlwaysOnTop(window_on_top); - else - window_state->RestoreAlwaysOnTop(); - } -} - -} // namespace ash
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h deleted file mode 100644 index e9410937..0000000 --- a/ash/wm/workspace/workspace_layout_manager.h +++ /dev/null
@@ -1,141 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_ - -#include <memory> -#include <set> - -#include "ash/ash_export.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_activation_observer.h" -#include "ash/common/wm_layout_manager.h" -#include "ash/wm/window_state_observer.h" -#include "ash/wm/wm_types.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" -#include "ui/display/display_observer.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/keyboard/keyboard_controller_observer.h" - -namespace ash { - -class RootWindowController; -class WmShell; -class WmWindow; -class WorkspaceLayoutManagerBackdropDelegate; - -namespace wm { -class WMEvent; -} - -// LayoutManager used on the window created for a workspace. -class ASH_EXPORT WorkspaceLayoutManager - : public WmLayoutManager, - public aura::WindowObserver, - public WmActivationObserver, - public keyboard::KeyboardControllerObserver, - public display::DisplayObserver, - public ShellObserver, - public wm::WindowStateObserver { - public: - // |window| is the container for this layout manager. - explicit WorkspaceLayoutManager(WmWindow* window); - ~WorkspaceLayoutManager() override; - - // A delegate which can be set to add a backdrop behind the top most visible - // window. With the call the ownership of the delegate will be transferred to - // the WorkspaceLayoutManager. - void SetMaximizeBackdropDelegate( - std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate); - - // Overridden from WmLayoutManager: - void OnWindowResized() override; - void OnWindowAddedToLayout(WmWindow* child) override; - void OnWillRemoveWindowFromLayout(WmWindow* child) override; - void OnWindowRemovedFromLayout(WmWindow* child) override; - void OnChildWindowVisibilityChanged(WmWindow* child, bool visibile) override; - void SetChildBounds(WmWindow* child, - const gfx::Rect& requested_bounds) override; - - // Overriden from aura::WindowObserver: - void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override; - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override; - void OnWindowStackingChanged(aura::Window* window) override; - void OnWindowDestroying(aura::Window* window) override; - void OnWindowBoundsChanged(aura::Window* window, - const gfx::Rect& old_bounds, - const gfx::Rect& new_bounds) override; - - // WmActivationObserver overrides: - void OnWindowActivated(WmWindow* gained_active, - WmWindow* lost_active) override; - - // keyboard::KeyboardControllerObserver overrides: - void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override; - void OnKeyboardClosed() override; - - // WindowStateObserver overrides: - void OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) override; - - // display::DisplayObserver overrides: - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) override; - - // ShellObserver overrides: - void OnFullscreenStateChanged(bool is_fullscreen, - WmWindow* root_window) override; - void OnPinnedStateChanged(WmWindow* pinned_window) override; - - private: - typedef std::set<WmWindow*> WindowSet; - - // Adjusts the bounds of all managed windows when the display area changes. - // This happens when the display size, work area insets has changed. - // If this is called for a display size change (i.e. |event| - // is DISPLAY_RESIZED), the non-maximized/non-fullscreen - // windows are readjusted to make sure the window is completely within the - // display region. Otherwise, it makes sure at least some parts of the window - // is on display. - void AdjustAllWindowsBoundsForWorkAreaChange(const wm::WMEvent* event); - - // Updates the visibility state of the shelf. - void UpdateShelfVisibility(); - - // Updates the fullscreen state of the workspace and notifies Shell if it - // has changed. - void UpdateFullscreenState(); - - // Updates the always-on-top state for windows managed by this layout - // manager. - void UpdateAlwaysOnTop(WmWindow* window_on_top); - - WmWindow* window_; - WmWindow* root_window_; - RootWindowController* root_window_controller_; - WmShell* shell_; - - // Set of windows we're listening to. - WindowSet windows_; - - // The work area in the coordinates of |window_|. - gfx::Rect work_area_in_parent_; - - // True if this workspace is currently in fullscreen mode. - bool is_fullscreen_; - - // A window which covers the full container and which gets inserted behind the - // topmost visible window. - std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> backdrop_delegate_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManager); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_H_
diff --git a/ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h b/ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h deleted file mode 100644 index ed20222..0000000 --- a/ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_ - -#include "ash/ash_export.h" -#include "ash/wm/wm_types.h" - -namespace ash { - -class WmWindow; - -namespace wm { -class WindowState; -} - -// A delegate which can be set to create and control a backdrop which gets -// placed below the top level window. -class ASH_EXPORT WorkspaceLayoutManagerBackdropDelegate { - public: - virtual ~WorkspaceLayoutManagerBackdropDelegate() {} - - // A window got added to the layout. - virtual void OnWindowAddedToLayout(WmWindow* child) = 0; - - // A window got removed from the layout. - virtual void OnWindowRemovedFromLayout(WmWindow* child) = 0; - - // The visibility of a window has changed. - virtual void OnChildWindowVisibilityChanged(WmWindow* child, - bool visible) = 0; - - // The stacking order of a window has changed. - virtual void OnWindowStackingChanged(WmWindow* window) = 0; - - // A window state type has changed. - virtual void OnPostWindowStateTypeChange(wm::WindowState* window_state, - wm::WindowStateType old_type) = 0; - - // The work area insets have changed, altering the total available space. - virtual void OnDisplayWorkAreaInsetsChanged() = 0; -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_BACKDROP_DELEGATE_H_
diff --git a/ash/wm/workspace/workspace_layout_manager_keyboard_unittest.cc b/ash/wm/workspace/workspace_layout_manager_keyboard_unittest.cc index d36493cc..d19b6718 100644 --- a/ash/wm/workspace/workspace_layout_manager_keyboard_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_keyboard_unittest.cc
@@ -2,28 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/workspace/workspace_layout_manager.h" +#include "ash/common/wm/workspace/workspace_layout_manager.h" #include <string> #include <utility> #include "ash/common/session/session_state_delegate.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/shell_observer.h" +#include "ash/common/test/ash_test.h" +#include "ash/common/wm/fullscreen_window_finder.h" +#include "ash/common/wm/maximize_mode/workspace_backdrop_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/wm_screen_util.h" +#include "ash/common/wm/workspace/workspace_window_resizer.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/test/ash_test.h" -#include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/maximize_mode/workspace_backdrop_delegate.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ash/wm/workspace/workspace_window_resizer.h" #include "base/command_line.h" #include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_types.h"
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc deleted file mode 100644 index 5035364..0000000 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ /dev/null
@@ -1,1268 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/workspace_layout_manager.h" - -#include <string> -#include <utility> - -#include "ash/common/session/session_state_delegate.h" -#include "ash/common/shell_observer.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/test/ash_test.h" -#include "ash/test/test_session_state_delegate.h" -#include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/maximize_mode/workspace_backdrop_delegate.h" -#include "ash/wm/window_state.h" -#include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ash/wm/workspace/workspace_window_resizer.h" -#include "base/command_line.h" -#include "base/run_loop.h" -#include "ui/aura/env.h" -#include "ui/base/ui_base_switches.h" -#include "ui/base/ui_base_types.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace ash { -namespace { - -class MaximizeDelegateView : public views::WidgetDelegateView { - public: - explicit MaximizeDelegateView(const gfx::Rect& initial_bounds) - : initial_bounds_(initial_bounds) {} - ~MaximizeDelegateView() override {} - - bool GetSavedWindowPlacement(const views::Widget* widget, - gfx::Rect* bounds, - ui::WindowShowState* show_state) const override { - *bounds = initial_bounds_; - *show_state = ui::SHOW_STATE_MAXIMIZED; - return true; - } - - private: - const gfx::Rect initial_bounds_; - - DISALLOW_COPY_AND_ASSIGN(MaximizeDelegateView); -}; - -class TestShellObserver : public ShellObserver { - public: - TestShellObserver() : call_count_(0), is_fullscreen_(false) { - WmShell::Get()->AddShellObserver(this); - } - - ~TestShellObserver() override { WmShell::Get()->RemoveShellObserver(this); } - - void OnFullscreenStateChanged(bool is_fullscreen, - WmWindow* root_window) override { - call_count_++; - is_fullscreen_ = is_fullscreen; - } - - int call_count() const { return call_count_; } - - bool is_fullscreen() const { return is_fullscreen_; } - - private: - int call_count_; - bool is_fullscreen_; - - DISALLOW_COPY_AND_ASSIGN(TestShellObserver); -}; - -} // namespace - -using WorkspaceLayoutManagerTest = AshTest; - -// Verifies that a window containing a restore coordinate will be restored to -// to the size prior to minimize, keeping the restore rectangle in tact (if -// there is one). -TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) { - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 3, 4))); - WmWindow* window = window_owner->window(); - gfx::Rect bounds(10, 15, 25, 35); - window->SetBounds(bounds); - - wm::WindowState* window_state = window->GetWindowState(); - - // This will not be used for un-minimizing window. - window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100)); - window_state->Minimize(); - window_state->Restore(); - EXPECT_EQ("0,0 100x100", window_state->GetRestoreBoundsInScreen().ToString()); - EXPECT_EQ("10,15 25x35", window->GetBounds().ToString()); - - UpdateDisplay("400x300,500x400"); - window->SetBoundsInScreen(gfx::Rect(600, 0, 100, 100), GetSecondaryDisplay()); - EXPECT_EQ(WmShell::Get()->GetAllRootWindows()[1], window->GetRootWindow()); - window_state->Minimize(); - // This will not be used for un-minimizing window. - window_state->SetRestoreBoundsInScreen(gfx::Rect(0, 0, 100, 100)); - window_state->Restore(); - EXPECT_EQ("600,0 100x100", window->GetBoundsInScreen().ToString()); - - // Make sure the unminimized window moves inside the display when - // 2nd display is disconnected. - window_state->Minimize(); - UpdateDisplay("400x300"); - window_state->Restore(); - EXPECT_EQ(WmShell::Get()->GetPrimaryRootWindow(), window->GetRootWindow()); - EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( - window->GetBounds())); -} - -TEST_F(WorkspaceLayoutManagerTest, KeepMinimumVisibilityInDisplays) { - UpdateDisplay("300x400,400x500"); - WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows(); - - if (!SetSecondaryDisplayPlacement(display::DisplayPlacement::TOP, 0)) - return; - - EXPECT_EQ("0,-500 400x500", root_windows[1]->GetBoundsInScreen().ToString()); - - std::unique_ptr<WindowOwner> window1_owner( - CreateTestWindow(gfx::Rect(10, -400, 200, 200))); - EXPECT_EQ("10,-400 200x200", - window1_owner->window()->GetBoundsInScreen().ToString()); - - // Make sure the caption is visible. - std::unique_ptr<WindowOwner> window2_owner( - CreateTestWindow(gfx::Rect(10, -600, 200, 200))); - EXPECT_EQ("10,-500 200x200", - window2_owner->window()->GetBoundsInScreen().ToString()); -} - -TEST_F(WorkspaceLayoutManagerTest, NoMinimumVisibilityForPopupWindows) { - UpdateDisplay("300x400"); - - // Create a popup window out of display boundaries and make sure it is not - // moved to have minimum visibility. - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(400, 100, 50, 50), ui::wm::WINDOW_TYPE_POPUP)); - EXPECT_EQ("400,100 50x50", - window_owner->window()->GetBoundsInScreen().ToString()); -} - -TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) { - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 30, 40))); - WmWindow* window = window_owner->window(); - wm::WindowState* window_state = window->GetWindowState(); - - // Maximized -> Normal transition. - window_state->Maximize(); - window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40)); - window_state->Restore(); - EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( - window->GetBounds())); - // Y bounds should not be negative. - EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString()); - - // Minimized -> Normal transition. - window->SetBounds(gfx::Rect(-100, -100, 30, 40)); - window_state->Minimize(); - EXPECT_FALSE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( - window->GetBounds())); - EXPECT_EQ("-100,-100 30x40", window->GetBounds().ToString()); - window->Show(); - EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( - window->GetBounds())); - // Y bounds should not be negative. - EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString()); - - // Fullscreen -> Normal transition. - window->SetBounds(gfx::Rect(0, 0, 30, 40)); // reset bounds. - ASSERT_EQ("0,0 30x40", window->GetBounds().ToString()); - window->SetShowState(ui::SHOW_STATE_FULLSCREEN); - EXPECT_EQ(window->GetBounds(), window->GetRootWindow()->GetBounds()); - window_state->SetRestoreBoundsInScreen(gfx::Rect(-100, -100, 30, 40)); - window_state->Restore(); - EXPECT_TRUE(WmShell::Get()->GetPrimaryRootWindow()->GetBounds().Intersects( - window->GetBounds())); - // Y bounds should not be negative. - EXPECT_EQ("-5,0 30x40", window->GetBounds().ToString()); -} - -TEST_F(WorkspaceLayoutManagerTest, MaximizeInDisplayToBeRestored) { - UpdateDisplay("300x400,400x500"); - - WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows(); - - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 30, 40))); - WmWindow* window = window_owner->window(); - EXPECT_EQ(root_windows[0], window->GetRootWindow()); - - wm::WindowState* window_state = window->GetWindowState(); - window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40)); - // Maximize the window in 2nd display as the restore bounds - // is inside 2nd display. - window_state->Maximize(); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ( - gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(), - window->GetBoundsInScreen().ToString()); - - window_state->Restore(); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString()); - - // If the restore bounds intersects with the current display, - // don't move. - window_state->SetRestoreBoundsInScreen(gfx::Rect(295, 0, 30, 40)); - window_state->Maximize(); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ( - gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(), - window->GetBoundsInScreen().ToString()); - - window_state->Restore(); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString()); - - // Restoring widget state. - std::unique_ptr<views::Widget> w1(new views::Widget); - views::Widget::InitParams params; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.delegate = new MaximizeDelegateView(gfx::Rect(400, 0, 30, 40)); - ConfigureWidgetInitParamsForDisplay(root_windows[0], ¶ms); - w1->Init(params); - EXPECT_EQ(root_windows[0], - WmWindow::Get(w1->GetNativeWindow())->GetRootWindow()); - w1->Show(); - EXPECT_TRUE(w1->IsMaximized()); - EXPECT_EQ(root_windows[1], - WmWindow::Get(w1->GetNativeWindow())->GetRootWindow()); - EXPECT_EQ( - gfx::Rect(300, 0, 400, 500 - GetShelfConstant(SHELF_SIZE)).ToString(), - w1->GetWindowBoundsInScreen().ToString()); - w1->Restore(); - EXPECT_EQ(root_windows[1], - WmWindow::Get(w1->GetNativeWindow())->GetRootWindow()); - EXPECT_EQ("400,0 30x40", w1->GetWindowBoundsInScreen().ToString()); -} - -TEST_F(WorkspaceLayoutManagerTest, FullscreenInDisplayToBeRestored) { - UpdateDisplay("300x400,400x500"); - - WmWindow::Windows root_windows = WmShell::Get()->GetAllRootWindows(); - - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 30, 40))); - WmWindow* window = window_owner->window(); - EXPECT_EQ(root_windows[0], window->GetRootWindow()); - - wm::WindowState* window_state = window->GetWindowState(); - window_state->SetRestoreBoundsInScreen(gfx::Rect(400, 0, 30, 40)); - // Maximize the window in 2nd display as the restore bounds - // is inside 2nd display. - window->SetShowState(ui::SHOW_STATE_FULLSCREEN); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString()); - - window_state->Restore(); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ("400,0 30x40", window->GetBoundsInScreen().ToString()); - - // If the restore bounds intersects with the current display, - // don't move. - window_state->SetRestoreBoundsInScreen(gfx::Rect(295, 0, 30, 40)); - window->SetShowState(ui::SHOW_STATE_FULLSCREEN); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ("300,0 400x500", window->GetBoundsInScreen().ToString()); - - window_state->Restore(); - EXPECT_EQ(root_windows[1], window->GetRootWindow()); - EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString()); -} - -// aura::WindowObserver implementation used by -// DontClobberRestoreBoundsWindowObserver. This code mirrors what -// BrowserFrameAsh does. In particular when this code sees the window was -// maximized it changes the bounds of a secondary window. The secondary window -// mirrors the status window. -class DontClobberRestoreBoundsWindowObserver : public aura::WindowObserver { - public: - DontClobberRestoreBoundsWindowObserver() : window_(nullptr) {} - - void set_window(WmWindow* window) { window_ = window; } - - // aura::WindowObserver: - void OnWindowPropertyChanged(aura::Window* window, - const void* key, - intptr_t old) override { - if (!window_) - return; - - if (wm::GetWindowState(window)->IsMaximized()) { - WmWindow* w = window_; - window_ = nullptr; - - gfx::Rect shelf_bounds(AshTest::GetPrimaryShelf()->GetIdealBounds()); - const gfx::Rect& window_bounds(w->GetBounds()); - w->SetBounds(gfx::Rect(window_bounds.x(), shelf_bounds.y() - 1, - window_bounds.width(), window_bounds.height())); - } - } - - private: - WmWindow* window_; - - DISALLOW_COPY_AND_ASSIGN(DontClobberRestoreBoundsWindowObserver); -}; - -// Creates a window, maximized the window and from within the maximized -// notification sets the bounds of a window to overlap the shelf. Verifies this -// doesn't effect the restore bounds. -TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) { - DontClobberRestoreBoundsWindowObserver window_observer; - WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, - ui::LAYER_TEXTURED)); - WmWindow* window = window_owner.window(); - window->SetBounds(gfx::Rect(10, 20, 30, 40)); - // NOTE: for this test to exercise the failure the observer needs to be added - // before the parent set. This mimics what BrowserFrameAsh does. - window->aura_window()->AddObserver(&window_observer); - ParentWindowInPrimaryRootWindow(window); - window->Show(); - - wm::WindowState* window_state = window->GetWindowState(); - window_state->Activate(); - - std::unique_ptr<WindowOwner> window2_owner( - CreateTestWindow(gfx::Rect(12, 20, 30, 40))); - WmWindow* window2 = window2_owner->window(); - AddTransientChild(window, window2); - window2->Show(); - - window_observer.set_window(window2); - window_state->Maximize(); - EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInScreen().ToString()); - window->aura_window()->RemoveObserver(&window_observer); -} - -// Verifies when a window is maximized all descendant windows have a size. -TEST_F(WorkspaceLayoutManagerTest, ChildBoundsResetOnMaximize) { - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(10, 20, 30, 40))); - WmWindow* window = window_owner->window(); - window->Show(); - wm::WindowState* window_state = window->GetWindowState(); - window_state->Activate(); - std::unique_ptr<WindowOwner> child_window_owner( - CreateChildWindow(window, gfx::Rect(5, 6, 7, 8))); - WmWindow* child_window = child_window_owner->window(); - window_state->Maximize(); - EXPECT_EQ("5,6 7x8", child_window->GetBounds().ToString()); -} - -// Verifies a window created with maximized state has the maximized -// bounds. -TEST_F(WorkspaceLayoutManagerTest, MaximizeWithEmptySize) { - WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, - ui::LAYER_TEXTURED)); - WmWindow* window = window_owner.window(); - window->GetWindowState()->Maximize(); - WmWindow* default_container = - WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer( - kShellWindowId_DefaultContainer); - default_container->AddChild(window); - window->Show(); - gfx::Rect work_area( - display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); - EXPECT_EQ(work_area.ToString(), window->GetBoundsInScreen().ToString()); -} - -TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) { - // TODO: fix. This test verifies that when a window is added the bounds are - // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes - // from NativeWidgetAura), which means this test now fails for aura-mus. - if (aura::Env::GetInstance()->mode() == aura::Env::Mode::MUS) - return; - - // Normal window bounds shouldn't be changed. - gfx::Rect window_bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(window_bounds)); - WmWindow* window = window_owner->window(); - EXPECT_EQ(window_bounds, window->GetBounds()); - - // If the window is out of the workspace, it would be moved on screen. - gfx::Rect root_window_bounds = - WmShell::Get()->GetPrimaryRootWindow()->GetBounds(); - window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height()); - ASSERT_FALSE(window_bounds.Intersects(root_window_bounds)); - std::unique_ptr<WindowOwner> out_window_owner( - CreateTestWindow(window_bounds)); - WmWindow* out_window = out_window_owner->window(); - EXPECT_EQ(window_bounds.size(), out_window->GetBounds().size()); - gfx::Rect bounds = out_window->GetBounds(); - bounds.Intersect(root_window_bounds); - - // 30% of the window edge must be visible. - EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); - EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); - - WmWindow* parent = out_window->GetParent(); - parent->RemoveChild(out_window); - out_window->SetBounds(gfx::Rect(-200, -200, 200, 200)); - // UserHasChangedWindowPositionOrSize flag shouldn't turn off this behavior. - window->GetWindowState()->set_bounds_changed_by_user(true); - parent->AddChild(out_window); - EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); - EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); - - // Make sure we always make more than 1/3 of the window edge visible even - // if the initial bounds intersects with display. - window_bounds.SetRect(-150, -150, 200, 200); - bounds = window_bounds; - bounds.Intersect(root_window_bounds); - - // Make sure that the initial bounds' visible area is less than 26% - // so that the auto adjustment logic kicks in. - ASSERT_LT(bounds.width(), out_window->GetBounds().width() * 0.26); - ASSERT_LT(bounds.height(), out_window->GetBounds().height() * 0.26); - ASSERT_TRUE(window_bounds.Intersects(root_window_bounds)); - - std::unique_ptr<WindowOwner> partially_out_window_owner( - CreateTestWindow(window_bounds)); - WmWindow* partially_out_window = partially_out_window_owner->window(); - EXPECT_EQ(window_bounds.size(), partially_out_window->GetBounds().size()); - bounds = partially_out_window->GetBounds(); - bounds.Intersect(root_window_bounds); - EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); - EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); - - // Make sure the window whose 30% width/height is bigger than display - // will be placed correctly. - window_bounds.SetRect(-1900, -1900, 3000, 3000); - std::unique_ptr<WindowOwner> window_bigger_than_display_owner( - CreateTestWindow(window_bounds)); - WmWindow* window_bigger_than_display = - window_bigger_than_display_owner->window(); - EXPECT_GE(root_window_bounds.width(), - window_bigger_than_display->GetBounds().width()); - EXPECT_GE(root_window_bounds.height(), - window_bigger_than_display->GetBounds().height()); - - bounds = window_bigger_than_display->GetBounds(); - bounds.Intersect(root_window_bounds); - EXPECT_GT(bounds.width(), out_window->GetBounds().width() * 0.29); - EXPECT_GT(bounds.height(), out_window->GetBounds().height() * 0.29); -} - -// Verifies the size of a window is enforced to be smaller than the work area. -TEST_F(WorkspaceLayoutManagerTest, SizeToWorkArea) { - // Normal window bounds shouldn't be changed. - gfx::Size work_area( - display::Screen::GetScreen()->GetPrimaryDisplay().work_area().size()); - const gfx::Rect window_bounds(100, 101, work_area.width() + 1, - work_area.height() + 2); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(window_bounds)); - WmWindow* window = window_owner->window(); - // TODO: fix. This test verifies that when a window is added the bounds are - // adjusted. CreateTestWindow() for mus adds, then sets the bounds (this comes - // from NativeWidgetAura), which means this test now fails for aura-mus. - if (aura::Env::GetInstance()->mode() != aura::Env::Mode::MUS) { - EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), - window->GetBounds().ToString()); - } - - // Directly setting the bounds triggers a slightly different code path. Verify - // that too. - window->SetBounds(window_bounds); - EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), - window->GetBounds().ToString()); -} - -TEST_F(WorkspaceLayoutManagerTest, NotifyFullscreenChanges) { - TestShellObserver observer; - std::unique_ptr<WindowOwner> window1_owner( - CreateTestWindow(gfx::Rect(1, 2, 30, 40))); - WmWindow* window1 = window1_owner->window(); - std::unique_ptr<WindowOwner> window2_owner( - CreateTestWindow(gfx::Rect(1, 2, 30, 40))); - WmWindow* window2 = window2_owner->window(); - wm::WindowState* window_state1 = window1->GetWindowState(); - wm::WindowState* window_state2 = window2->GetWindowState(); - window_state2->Activate(); - - const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN); - window_state2->OnWMEvent(&toggle_fullscreen_event); - EXPECT_EQ(1, observer.call_count()); - EXPECT_TRUE(observer.is_fullscreen()); - - // When window1 moves to the front the fullscreen state should change. - window_state1->Activate(); - EXPECT_EQ(2, observer.call_count()); - EXPECT_FALSE(observer.is_fullscreen()); - - // It should change back if window2 becomes active again. - window_state2->Activate(); - EXPECT_EQ(3, observer.call_count()); - EXPECT_TRUE(observer.is_fullscreen()); - - window_state2->OnWMEvent(&toggle_fullscreen_event); - EXPECT_EQ(4, observer.call_count()); - EXPECT_FALSE(observer.is_fullscreen()); - - window_state2->OnWMEvent(&toggle_fullscreen_event); - EXPECT_EQ(5, observer.call_count()); - EXPECT_TRUE(observer.is_fullscreen()); - - // Closing the window should change the fullscreen state. - window2_owner.reset(); - EXPECT_EQ(6, observer.call_count()); - EXPECT_FALSE(observer.is_fullscreen()); -} - -// For crbug.com/673803, snapped window may not adjust snapped bounds on work -// area changed properly if window's layer is doing animation. We should use -// GetTargetBounds to check if snapped bounds need to be changed. -TEST_F(WorkspaceLayoutManagerTest, - SnappedWindowMayNotAdjustBoundsOnWorkAreaChanged) { - UpdateDisplay("300x400"); - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(10, 20, 100, 200))); - WmWindow* window = window_owner->window(); - wm::WindowState* window_state = window->GetWindowState(); - gfx::Insets insets(0, 0, 50, 0); - WmShell::Get()->SetDisplayWorkAreaInsets(window, insets); - const wm::WMEvent snap_left(wm::WM_EVENT_SNAP_LEFT); - window_state->OnWMEvent(&snap_left); - EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType()); - const gfx::Rect kWorkAreaBounds = - display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); - gfx::Rect expected_bounds = - gfx::Rect(kWorkAreaBounds.x(), kWorkAreaBounds.y(), - kWorkAreaBounds.width() / 2, kWorkAreaBounds.height()); - EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString()); - - ui::ScopedAnimationDurationScaleMode test_duration_mode( - ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); - // The following two SetDisplayWorkAreaInsets calls simulate the case of - // crbug.com/673803 that work area first becomes fullscreen and then returns - // to the original state. - WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets(0, 0, 0, 0)); - ui::LayerAnimator* animator = window->GetLayer()->GetAnimator(); - EXPECT_TRUE(animator->is_animating()); - WmShell::Get()->SetDisplayWorkAreaInsets(window, insets); - animator->StopAnimating(); - EXPECT_FALSE(animator->is_animating()); - EXPECT_EQ(expected_bounds.ToString(), window->GetBounds().ToString()); -} - -// Do not adjust window bounds to ensure minimum visibility for transient -// windows (crbug.com/624806). -TEST_F(WorkspaceLayoutManagerTest, - DoNotAdjustTransientWindowBoundsToEnsureMinimumVisibility) { - UpdateDisplay("300x400"); - WindowOwner window_owner(WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, - ui::LAYER_TEXTURED)); - WmWindow* window = window_owner.window(); - window->SetBounds(gfx::Rect(10, 0, 100, 200)); - ParentWindowInPrimaryRootWindow(window); - window->Show(); - - std::unique_ptr<WindowOwner> window2_owner( - CreateTestWindow(gfx::Rect(10, 0, 40, 20))); - WmWindow* window2 = window2_owner->window(); - AddTransientChild(window, window2); - window2->Show(); - - gfx::Rect expected_bounds = window2->GetBounds(); - WmShell::Get()->SetDisplayWorkAreaInsets(window, gfx::Insets(50, 0, 0, 0)); - EXPECT_EQ(expected_bounds.ToString(), window2->GetBounds().ToString()); -} - -// Following "Solo" tests were originally written for BaseLayoutManager. -using WorkspaceLayoutManagerSoloTest = AshTest; - -// Tests normal->maximize->normal. -TEST_F(WorkspaceLayoutManagerSoloTest, Maximize) { - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); - WmWindow* window = window_owner->window(); - window->SetShowState(ui::SHOW_STATE_MAXIMIZED); - // Maximized window fills the work area, not the whole display. - EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), - window->GetBounds().ToString()); - window->SetShowState(ui::SHOW_STATE_NORMAL); - EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString()); -} - -// Tests normal->minimize->normal. -TEST_F(WorkspaceLayoutManagerSoloTest, Minimize) { - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); - WmWindow* window = window_owner->window(); - window->SetShowState(ui::SHOW_STATE_MINIMIZED); - EXPECT_FALSE(window->IsVisible()); - EXPECT_TRUE(window->GetWindowState()->IsMinimized()); - EXPECT_EQ(bounds, window->GetBounds()); - window->SetShowState(ui::SHOW_STATE_NORMAL); - EXPECT_TRUE(window->IsVisible()); - EXPECT_FALSE(window->GetWindowState()->IsMinimized()); - EXPECT_EQ(bounds, window->GetBounds()); -} - -// A aura::WindowObserver which sets the focus when the window becomes visible. -class FocusDuringUnminimizeWindowObserver : public aura::WindowObserver { - public: - FocusDuringUnminimizeWindowObserver() - : window_(nullptr), show_state_(ui::SHOW_STATE_END) {} - ~FocusDuringUnminimizeWindowObserver() override { SetWindow(nullptr); } - - void SetWindow(WmWindow* window) { - if (window_) - window_->aura_window()->RemoveObserver(this); - window_ = window; - if (window_) - window_->aura_window()->AddObserver(this); - } - - // aura::WindowObserver: - void OnWindowVisibilityChanged(aura::Window* window, bool visible) override { - if (window_) { - if (visible) - window_->SetFocused(); - show_state_ = window_->GetShowState(); - } - } - - ui::WindowShowState GetShowStateAndReset() { - ui::WindowShowState ret = show_state_; - show_state_ = ui::SHOW_STATE_END; - return ret; - } - - private: - WmWindow* window_; - ui::WindowShowState show_state_; - - DISALLOW_COPY_AND_ASSIGN(FocusDuringUnminimizeWindowObserver); -}; - -// Make sure that the window's show state is correct in -// WindowObserver::OnWindowTargetVisibilityChanged(), and setting focus in this -// callback doesn't cause DCHECK error. See crbug.com/168383. -TEST_F(WorkspaceLayoutManagerSoloTest, FocusDuringUnminimize) { - FocusDuringUnminimizeWindowObserver observer; - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(100, 100, 100, 100))); - WmWindow* window = window_owner->window(); - observer.SetWindow(window); - window->SetShowState(ui::SHOW_STATE_MINIMIZED); - EXPECT_FALSE(window->IsVisible()); - EXPECT_EQ(ui::SHOW_STATE_MINIMIZED, observer.GetShowStateAndReset()); - window->Show(); - EXPECT_TRUE(window->IsVisible()); - EXPECT_EQ(ui::SHOW_STATE_NORMAL, observer.GetShowStateAndReset()); - observer.SetWindow(nullptr); -} - -// Tests maximized window size during root window resize. -TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeRootWindowResize) { - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); - WmWindow* window = window_owner->window(); - window->SetShowState(ui::SHOW_STATE_MAXIMIZED); - gfx::Rect initial_work_area_bounds = - wm::GetMaximizedWindowBoundsInParent(window); - EXPECT_EQ(initial_work_area_bounds.ToString(), - window->GetBounds().ToString()); - // Enlarge the root window. We should still match the work area size. - UpdateDisplay("900x700"); - EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), - window->GetBounds().ToString()); - EXPECT_NE(initial_work_area_bounds.ToString(), - wm::GetMaximizedWindowBoundsInParent(window).ToString()); -} - -// Tests normal->fullscreen->normal. -TEST_F(WorkspaceLayoutManagerSoloTest, Fullscreen) { - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); - WmWindow* window = window_owner->window(); - window->SetShowState(ui::SHOW_STATE_FULLSCREEN); - // Fullscreen window fills the whole display. - EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(), - window->GetBounds().ToString()); - window->SetShowState(ui::SHOW_STATE_NORMAL); - EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString()); -} - -// Tests that fullscreen window causes always_on_top windows to stack below. -TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenSuspendsAlwaysOnTop) { - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> fullscreen_window_owner( - CreateTestWindow(bounds)); - WmWindow* fullscreen_window = fullscreen_window_owner->window(); - std::unique_ptr<WindowOwner> always_on_top_window1_owner( - CreateTestWindow(bounds)); - WmWindow* always_on_top_window1 = always_on_top_window1_owner->window(); - std::unique_ptr<WindowOwner> always_on_top_window2_owner( - CreateTestWindow(bounds)); - WmWindow* always_on_top_window2 = always_on_top_window2_owner->window(); - always_on_top_window1->SetAlwaysOnTop(true); - always_on_top_window2->SetAlwaysOnTop(true); - // Making a window fullscreen temporarily suspends always on top state. - fullscreen_window->SetShowState(ui::SHOW_STATE_FULLSCREEN); - EXPECT_FALSE(always_on_top_window1->IsAlwaysOnTop()); - EXPECT_FALSE(always_on_top_window2->IsAlwaysOnTop()); - EXPECT_NE(nullptr, wm::GetWindowForFullscreenMode(fullscreen_window)); - - // Adding a new always-on-top window is not affected by fullscreen. - std::unique_ptr<WindowOwner> always_on_top_window3_owner( - CreateTestWindow(bounds)); - WmWindow* always_on_top_window3 = always_on_top_window3_owner->window(); - always_on_top_window3->SetAlwaysOnTop(true); - EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop()); - - // Making fullscreen window normal restores always on top windows. - fullscreen_window->SetShowState(ui::SHOW_STATE_NORMAL); - EXPECT_TRUE(always_on_top_window1->IsAlwaysOnTop()); - EXPECT_TRUE(always_on_top_window2->IsAlwaysOnTop()); - EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop()); - EXPECT_EQ(nullptr, wm::GetWindowForFullscreenMode(fullscreen_window)); -} - -// Similary, pinned window causes always_on_top_ windows to stack below. -TEST_F(WorkspaceLayoutManagerSoloTest, PinnedSuspendsAlwaysOnTop) { - // TODO: mash doesn't support pinning yet http://crbug.com/622486. - if (WmShell::Get()->IsRunningInMash()) - return; - - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> pinned_window_owner(CreateTestWindow(bounds)); - WmWindow* pinned_window = pinned_window_owner->window(); - std::unique_ptr<WindowOwner> always_on_top_window1_owner( - CreateTestWindow(bounds)); - WmWindow* always_on_top_window1 = always_on_top_window1_owner->window(); - std::unique_ptr<WindowOwner> always_on_top_window2_owner( - CreateTestWindow(bounds)); - WmWindow* always_on_top_window2 = always_on_top_window2_owner->window(); - always_on_top_window1->SetAlwaysOnTop(true); - always_on_top_window2->SetAlwaysOnTop(true); - - // Making a window pinned temporarily suspends always on top state. - const bool trusted = false; - pinned_window->SetPinned(trusted); - EXPECT_FALSE(always_on_top_window1->IsAlwaysOnTop()); - EXPECT_FALSE(always_on_top_window2->IsAlwaysOnTop()); - - // Adding a new always-on-top window also is affected by pinned mode. - std::unique_ptr<WindowOwner> always_on_top_window3_owner( - CreateTestWindow(bounds)); - WmWindow* always_on_top_window3 = always_on_top_window3_owner->window(); - always_on_top_window3->SetAlwaysOnTop(true); - EXPECT_FALSE(always_on_top_window3->IsAlwaysOnTop()); - - // Making pinned window normal restores always on top windows. - pinned_window->GetWindowState()->Restore(); - EXPECT_TRUE(always_on_top_window1->IsAlwaysOnTop()); - EXPECT_TRUE(always_on_top_window2->IsAlwaysOnTop()); - EXPECT_TRUE(always_on_top_window3->IsAlwaysOnTop()); -} - -// Tests fullscreen window size during root window resize. -TEST_F(WorkspaceLayoutManagerSoloTest, FullscreenRootWindowResize) { - gfx::Rect bounds(100, 100, 200, 200); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(bounds)); - WmWindow* window = window_owner->window(); - // Fullscreen window fills the whole display. - window->SetShowState(ui::SHOW_STATE_FULLSCREEN); - EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(), - window->GetBounds().ToString()); - // Enlarge the root window. We should still match the display size. - UpdateDisplay("800x600"); - EXPECT_EQ(window->GetDisplayNearestWindow().bounds().ToString(), - window->GetBounds().ToString()); -} - -// Tests that when the screen gets smaller the windows aren't bigger than -// the screen. -TEST_F(WorkspaceLayoutManagerSoloTest, RootWindowResizeShrinksWindows) { - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(10, 20, 500, 400))); - WmWindow* window = window_owner->window(); - gfx::Rect work_area = window->GetDisplayNearestWindow().work_area(); - // Invariant: Window is smaller than work area. - EXPECT_LE(window->GetBounds().width(), work_area.width()); - EXPECT_LE(window->GetBounds().height(), work_area.height()); - - // Make the root window narrower than our window. - UpdateDisplay("300x400"); - work_area = window->GetDisplayNearestWindow().work_area(); - EXPECT_LE(window->GetBounds().width(), work_area.width()); - EXPECT_LE(window->GetBounds().height(), work_area.height()); - - // Make the root window shorter than our window. - UpdateDisplay("300x200"); - work_area = window->GetDisplayNearestWindow().work_area(); - EXPECT_LE(window->GetBounds().width(), work_area.width()); - EXPECT_LE(window->GetBounds().height(), work_area.height()); - - // Enlarging the root window does not change the window bounds. - gfx::Rect old_bounds = window->GetBounds(); - UpdateDisplay("800x600"); - EXPECT_EQ(old_bounds.width(), window->GetBounds().width()); - EXPECT_EQ(old_bounds.height(), window->GetBounds().height()); -} - -// Verifies maximizing sets the restore bounds, and restoring -// restores the bounds. -TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeSetsRestoreBounds) { - const gfx::Rect initial_bounds(10, 20, 30, 40); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(initial_bounds)); - WmWindow* window = window_owner->window(); - EXPECT_EQ(initial_bounds, window->GetBounds()); - wm::WindowState* window_state = window->GetWindowState(); - - // Maximize it, which will keep the previous restore bounds. - window->SetShowState(ui::SHOW_STATE_MAXIMIZED); - EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInParent().ToString()); - - // Restore it, which should restore bounds and reset restore bounds. - window->SetShowState(ui::SHOW_STATE_NORMAL); - EXPECT_EQ("10,20 30x40", window->GetBounds().ToString()); - EXPECT_FALSE(window_state->HasRestoreBounds()); -} - -// Verifies maximizing keeps the restore bounds if set. -TEST_F(WorkspaceLayoutManagerSoloTest, MaximizeResetsRestoreBounds) { - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 3, 4))); - WmWindow* window = window_owner->window(); - wm::WindowState* window_state = window->GetWindowState(); - window_state->SetRestoreBoundsInParent(gfx::Rect(10, 11, 12, 13)); - - // Maximize it, which will keep the previous restore bounds. - window->SetShowState(ui::SHOW_STATE_MAXIMIZED); - EXPECT_EQ("10,11 12x13", window_state->GetRestoreBoundsInParent().ToString()); -} - -// Verifies that the restore bounds do not get reset when restoring to a -// maximzied state from a minimized state. -TEST_F(WorkspaceLayoutManagerSoloTest, - BoundsAfterRestoringToMaximizeFromMinimize) { - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 3, 4))); - WmWindow* window = window_owner->window(); - gfx::Rect bounds(10, 15, 25, 35); - window->SetBounds(bounds); - - wm::WindowState* window_state = window->GetWindowState(); - // Maximize it, which should reset restore bounds. - window_state->Maximize(); - EXPECT_EQ(bounds.ToString(), - window_state->GetRestoreBoundsInParent().ToString()); - // Minimize the window. The restore bounds should not change. - window_state->Minimize(); - EXPECT_EQ(bounds.ToString(), - window_state->GetRestoreBoundsInParent().ToString()); - - // Show the window again. The window should be maximized, and the restore - // bounds should not change. - window->Show(); - EXPECT_EQ(bounds.ToString(), - window_state->GetRestoreBoundsInParent().ToString()); - EXPECT_TRUE(window_state->IsMaximized()); - - window_state->Restore(); - EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString()); -} - -// Verify if the window is not resized during screen lock. See: crbug.com/173127 -TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) { - test::TestSessionStateDelegate::SetCanLockScreen(true); - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 3, 4))); - WmWindow* window = window_owner->window(); - // window with AlwaysOnTop will be managed by BaseLayoutManager. - window->SetAlwaysOnTop(true); - window->Show(); - - WmShelf* shelf = GetPrimaryShelf(); - shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); - - window->SetBounds(wm::GetMaximizedWindowBoundsInParent(window)); - gfx::Rect window_bounds = window->GetBounds(); - EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), - window_bounds.ToString()); - - // The window size should not get touched while we are in lock screen. - WmShell::Get()->GetSessionStateDelegate()->LockScreen(); - ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager(); - shelf_layout_manager->UpdateVisibilityState(); - EXPECT_EQ(window_bounds.ToString(), window->GetBounds().ToString()); - - // Coming out of the lock screen the window size should still remain. - WmShell::Get()->GetSessionStateDelegate()->UnlockScreen(); - shelf_layout_manager->UpdateVisibilityState(); - EXPECT_EQ(wm::GetMaximizedWindowBoundsInParent(window).ToString(), - window_bounds.ToString()); - EXPECT_EQ(window_bounds.ToString(), window->GetBounds().ToString()); -} - -// Following tests are written to test the backdrop functionality. - -namespace { - -WorkspaceLayoutManager* GetWorkspaceLayoutManager(WmWindow* container) { - return static_cast<WorkspaceLayoutManager*>(container->GetLayoutManager()); -} - -class WorkspaceLayoutManagerBackdropTest : public AshTest { - public: - WorkspaceLayoutManagerBackdropTest() : default_container_(nullptr) {} - ~WorkspaceLayoutManagerBackdropTest() override {} - - void SetUp() override { - AshTest::SetUp(); - UpdateDisplay("800x600"); - default_container_ = - WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer( - kShellWindowId_DefaultContainer); - } - - // Turn the top window back drop on / off. - void ShowTopWindowBackdrop(bool show) { - std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> backdrop; - if (show) - backdrop.reset(new WorkspaceBackdropDelegate(default_container_)); - GetWorkspaceLayoutManager(default_container_) - ->SetMaximizeBackdropDelegate(std::move(backdrop)); - // Closing and / or opening can be a delayed operation. - base::RunLoop().RunUntilIdle(); - } - - // Return the default container. - WmWindow* default_container() { return default_container_; } - - // Return the order of windows (top most first) as they are in the default - // container. If the window is visible it will be a big letter, otherwise a - // small one. The backdrop will be an X and unknown windows will be shown as - // '!'. - std::string GetWindowOrderAsString(WmWindow* backdrop, - WmWindow* wa, - WmWindow* wb, - WmWindow* wc) { - std::string result; - WmWindow::Windows children = default_container()->GetChildren(); - for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) { - if (!result.empty()) - result += ","; - if (children[i] == wa) - result += children[i]->IsVisible() ? "A" : "a"; - else if (children[i] == wb) - result += children[i]->IsVisible() ? "B" : "b"; - else if (children[i] == wc) - result += children[i]->IsVisible() ? "C" : "c"; - else if (children[i] == backdrop) - result += children[i]->IsVisible() ? "X" : "x"; - else - result += "!"; - } - return result; - } - - private: - // The default container. - WmWindow* default_container_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerBackdropTest); -}; - -} // namespace - -// Check that creating the BackDrop without destroying it does not lead into -// a crash. -TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropCrashTest) { - ShowTopWindowBackdrop(true); -} - -// Verify basic assumptions about the backdrop. -TEST_F(WorkspaceLayoutManagerBackdropTest, BasicBackdropTests) { - // Create a backdrop and see that there is one window (the backdrop) and - // that the size is the same as the default container as well as that it is - // not visible. - ShowTopWindowBackdrop(true); - ASSERT_EQ(1U, default_container()->GetChildren().size()); - EXPECT_FALSE(default_container()->GetChildren()[0]->IsVisible()); - - { - // Add a window and make sure that the backdrop is the second child. - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(gfx::Rect(1, 2, 3, 4))); - WmWindow* window = window_owner->window(); - window->Show(); - ASSERT_EQ(2U, default_container()->GetChildren().size()); - EXPECT_TRUE(default_container()->GetChildren()[0]->IsVisible()); - EXPECT_TRUE(default_container()->GetChildren()[1]->IsVisible()); - EXPECT_EQ(window, default_container()->GetChildren()[1]); - EXPECT_EQ(default_container()->GetBounds().ToString(), - default_container()->GetChildren()[0]->GetBounds().ToString()); - } - - // With the window gone the backdrop should be invisible again. - ASSERT_EQ(1U, default_container()->GetChildren().size()); - EXPECT_FALSE(default_container()->GetChildren()[0]->IsVisible()); - - // Destroying the Backdrop should empty the container. - ShowTopWindowBackdrop(false); - ASSERT_EQ(0U, default_container()->GetChildren().size()); -} - -// Verify that the backdrop gets properly created and placed. -TEST_F(WorkspaceLayoutManagerBackdropTest, VerifyBackdropAndItsStacking) { - std::unique_ptr<WindowOwner> window1_owner( - CreateTestWindow(gfx::Rect(1, 2, 3, 4))); - WmWindow* window1 = window1_owner->window(); - window1->Show(); - - // Get the default container and check that only a single window is in there. - ASSERT_EQ(1U, default_container()->GetChildren().size()); - EXPECT_EQ(window1, default_container()->GetChildren()[0]); - EXPECT_EQ("A", GetWindowOrderAsString(nullptr, window1, nullptr, nullptr)); - - // Create 2 more windows and check that they are also in the container. - std::unique_ptr<WindowOwner> window2_owner( - CreateTestWindow(gfx::Rect(10, 2, 3, 4))); - WmWindow* window2 = window2_owner->window(); - std::unique_ptr<WindowOwner> window3_owner( - CreateTestWindow(gfx::Rect(20, 2, 3, 4))); - WmWindow* window3 = window3_owner->window(); - window2->Show(); - window3->Show(); - - WmWindow* backdrop = nullptr; - EXPECT_EQ("C,B,A", - GetWindowOrderAsString(backdrop, window1, window2, window3)); - - // Turn on the backdrop mode and check that the window shows up where it - // should be (second highest number). - ShowTopWindowBackdrop(true); - backdrop = default_container()->GetChildren()[2]; - EXPECT_EQ("C,X,B,A", - GetWindowOrderAsString(backdrop, window1, window2, window3)); - - // Switch the order of windows and check that it still remains in that - // location. - default_container()->StackChildAtTop(window2); - EXPECT_EQ("B,X,C,A", - GetWindowOrderAsString(backdrop, window1, window2, window3)); - - // Make the top window invisible and check. - window2->Hide(); - EXPECT_EQ("b,C,X,A", - GetWindowOrderAsString(backdrop, window1, window2, window3)); - // Then delete window after window and see that everything is in order. - window1_owner.reset(); - EXPECT_EQ("b,C,X", - GetWindowOrderAsString(backdrop, window1, window2, window3)); - window3_owner.reset(); - EXPECT_EQ("b,x", GetWindowOrderAsString(backdrop, window1, window2, window3)); - ShowTopWindowBackdrop(false); - EXPECT_EQ("b", GetWindowOrderAsString(nullptr, window1, window2, window3)); -} - -// Tests that when hidding the shelf, that the backdrop resizes to fill the -// entire workspace area. -TEST_F(WorkspaceLayoutManagerBackdropTest, ShelfVisibilityChangesBounds) { - WmShelf* shelf = GetPrimaryShelf(); - ShelfLayoutManager* shelf_layout_manager = shelf->shelf_layout_manager(); - ShowTopWindowBackdrop(true); - RunAllPendingInMessageLoop(); - - ASSERT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state()); - gfx::Rect initial_bounds = default_container()->GetChildren()[0]->GetBounds(); - shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); - shelf_layout_manager->UpdateVisibilityState(); - - // When the shelf is re-shown WorkspaceLayoutManager shrinks all children - // including the backdrop. - shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); - shelf_layout_manager->UpdateVisibilityState(); - gfx::Rect reduced_bounds = default_container()->GetChildren()[0]->GetBounds(); - EXPECT_LT(reduced_bounds.height(), initial_bounds.height()); - - shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN); - shelf_layout_manager->UpdateVisibilityState(); - - EXPECT_GT(default_container()->GetChildren()[0]->GetBounds().height(), - reduced_bounds.height()); -} - -class WorkspaceLayoutManagerKeyboardTest : public AshTest { - public: - WorkspaceLayoutManagerKeyboardTest() : layout_manager_(nullptr) {} - ~WorkspaceLayoutManagerKeyboardTest() override {} - - void SetUp() override { - AshTest::SetUp(); - UpdateDisplay("800x600"); - WmWindow* default_container = - WmShell::Get()->GetPrimaryRootWindowController()->GetWmContainer( - kShellWindowId_DefaultContainer); - layout_manager_ = GetWorkspaceLayoutManager(default_container); - } - - void ShowKeyboard() { - layout_manager_->OnKeyboardBoundsChanging(keyboard_bounds_); - restore_work_area_insets_ = - display::Screen::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets(); - WmShell::Get()->SetDisplayWorkAreaInsets( - WmShell::Get()->GetPrimaryRootWindow(), - gfx::Insets(0, 0, keyboard_bounds_.height(), 0)); - } - - void HideKeyboard() { - WmShell::Get()->SetDisplayWorkAreaInsets( - WmShell::Get()->GetPrimaryRootWindow(), restore_work_area_insets_); - layout_manager_->OnKeyboardBoundsChanging(gfx::Rect()); - } - - // Initializes the keyboard bounds using the bottom half of the work area. - void InitKeyboardBounds() { - gfx::Rect work_area( - display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); - keyboard_bounds_.SetRect(work_area.x(), - work_area.y() + work_area.height() / 2, - work_area.width(), work_area.height() / 2); - } - - void EnableNewVKMode() { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (!command_line->HasSwitch(::switches::kUseNewVirtualKeyboardBehavior)) - command_line->AppendSwitch(::switches::kUseNewVirtualKeyboardBehavior); - } - - const gfx::Rect& keyboard_bounds() const { return keyboard_bounds_; } - - private: - gfx::Insets restore_work_area_insets_; - gfx::Rect keyboard_bounds_; - WorkspaceLayoutManager* layout_manager_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerKeyboardTest); -}; - -// Tests that when a child window gains focus the top level window containing it -// is resized to fit the remaining workspace area. -TEST_F(WorkspaceLayoutManagerKeyboardTest, ChildWindowFocused) { - InitKeyboardBounds(); - - gfx::Rect work_area( - display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); - - std::unique_ptr<WindowOwner> parent_window_owner( - CreateToplevelTestWindow(work_area)); - WmWindow* parent_window = parent_window_owner->window(); - std::unique_ptr<WindowOwner> window_owner(CreateTestWindow(work_area)); - WmWindow* window = window_owner->window(); - parent_window->AddChild(window); - - window->Activate(); - - int available_height = - display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height() - - keyboard_bounds().height(); - - gfx::Rect initial_window_bounds(50, 50, 100, 500); - parent_window->SetBounds(initial_window_bounds); - EXPECT_EQ(initial_window_bounds.ToString(), - parent_window->GetBounds().ToString()); - ShowKeyboard(); - EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(), - parent_window->GetBounds().ToString()); - HideKeyboard(); - EXPECT_EQ(initial_window_bounds.ToString(), - parent_window->GetBounds().ToString()); -} - -TEST_F(WorkspaceLayoutManagerKeyboardTest, AdjustWindowForA11yKeyboard) { - InitKeyboardBounds(); - gfx::Rect work_area( - display::Screen::GetScreen()->GetPrimaryDisplay().work_area()); - - std::unique_ptr<WindowOwner> window_owner( - CreateToplevelTestWindow(work_area)); - WmWindow* window = window_owner->window(); - // The additional SetBounds() is needed as the aura-mus case uses Widget, - // which alters the supplied bounds. - window->SetBounds(work_area); - - int available_height = - display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height() - - keyboard_bounds().height(); - - window->Activate(); - - EXPECT_EQ(gfx::Rect(work_area).ToString(), window->GetBounds().ToString()); - ShowKeyboard(); - EXPECT_EQ(gfx::Rect(work_area.origin(), - gfx::Size(work_area.width(), available_height)) - .ToString(), - window->GetBounds().ToString()); - HideKeyboard(); - EXPECT_EQ(gfx::Rect(work_area).ToString(), window->GetBounds().ToString()); - - gfx::Rect small_window_bound(50, 50, 100, 500); - window->SetBounds(small_window_bound); - EXPECT_EQ(small_window_bound.ToString(), window->GetBounds().ToString()); - ShowKeyboard(); - EXPECT_EQ(gfx::Rect(50, 0, 100, available_height).ToString(), - window->GetBounds().ToString()); - HideKeyboard(); - EXPECT_EQ(small_window_bound.ToString(), window->GetBounds().ToString()); - - gfx::Rect occluded_window_bounds( - 50, keyboard_bounds().y() + keyboard_bounds().height() / 2, 50, - keyboard_bounds().height() / 2); - window->SetBounds(occluded_window_bounds); - EXPECT_EQ(occluded_window_bounds.ToString(), - occluded_window_bounds.ToString()); - ShowKeyboard(); - EXPECT_EQ( - gfx::Rect(50, keyboard_bounds().y() - keyboard_bounds().height() / 2, - occluded_window_bounds.width(), occluded_window_bounds.height()) - .ToString(), - window->GetBounds().ToString()); - HideKeyboard(); - EXPECT_EQ(occluded_window_bounds.ToString(), window->GetBounds().ToString()); -} - -TEST_F(WorkspaceLayoutManagerKeyboardTest, IgnoreKeyboardBoundsChange) { - InitKeyboardBounds(); - - std::unique_ptr<WindowOwner> window_owner( - CreateTestWindow(keyboard_bounds())); - WmWindow* window = window_owner->window(); - // The additional SetBounds() is needed as the aura-mus case uses Widget, - // which alters the supplied bounds. - window->SetBounds(keyboard_bounds()); - window->GetWindowState()->set_ignore_keyboard_bounds_change(true); - window->Activate(); - - EXPECT_EQ(keyboard_bounds(), window->GetBounds()); - ShowKeyboard(); - EXPECT_EQ(keyboard_bounds(), window->GetBounds()); -} - -} // namespace ash
diff --git a/ash/wm/workspace/workspace_types.h b/ash/wm/workspace/workspace_types.h deleted file mode 100644 index c6b7f1b6..0000000 --- a/ash/wm/workspace/workspace_types.h +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_WORKSPACE_TYPES_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_TYPES_H_ - -namespace ash { -namespace wm { - -// Enumeration of the possible window states. -enum WorkspaceWindowState { - // There's a full screen window. - WORKSPACE_WINDOW_STATE_FULL_SCREEN, - - // There's a maximized window. - WORKSPACE_WINDOW_STATE_MAXIMIZED, - - // At least one window overlaps the shelf. - WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF, - - // None of the windows are fullscreen, maximized or touch the shelf. - WORKSPACE_WINDOW_STATE_DEFAULT, -}; - -} // namespace wm -} // namespace ash - -#endif // ASH_WM_WORKSPACE_WORKSPACE_TYPES_H_
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc deleted file mode 100644 index 208b400..0000000 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ /dev/null
@@ -1,1021 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace/workspace_window_resizer.h" - -#include <algorithm> -#include <cmath> -#include <utility> -#include <vector> - -#include "ash/common/ash_switches.h" -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/metrics/user_metrics_action.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shell.h" -#include "ash/wm/default_window_resizer.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/dock/docked_window_resizer.h" -#include "ash/wm/panels/panel_window_resizer.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/wm_screen_util.h" -#include "ash/wm/workspace/phantom_window_controller.h" -#include "ash/wm/workspace/two_step_edge_cycler.h" -#include "base/memory/ptr_util.h" -#include "base/memory/weak_ptr.h" -#include "ui/base/hit_test.h" -#include "ui/compositor/layer.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/transform.h" -#include "ui/wm/public/window_types.h" - -namespace ash { - -std::unique_ptr<WindowResizer> CreateWindowResizer( - WmWindow* window, - const gfx::Point& point_in_parent, - int window_component, - aura::client::WindowMoveSource source) { - DCHECK(window); - wm::WindowState* window_state = window->GetWindowState(); - // No need to return a resizer when the window cannot get resized or when a - // resizer already exists for this window. - if ((!window_state->CanResize() && window_component != HTCAPTION) || - window_state->drag_details()) { - return nullptr; - } - - if (window_component == HTCAPTION && !window_state->can_be_dragged()) - return nullptr; - - // TODO(varkha): The chaining of window resizers causes some of the logic - // to be repeated and the logic flow difficult to control. With some windows - // classes using reparenting during drag operations it becomes challenging to - // implement proper transition from one resizer to another during or at the - // end of the drag. This also causes http://crbug.com/247085. - // It seems the only thing the panel or dock resizer needs to do is notify the - // layout manager when a docked window is being dragged. We should have a - // better way of doing this, perhaps by having a way of observing drags or - // having a generic drag window wrapper which informs a layout manager that a - // drag has started or stopped. - // It may be possible to refactor and eliminate chaining. - std::unique_ptr<WindowResizer> window_resizer; - - if (!window_state->IsNormalOrSnapped() && !window_state->IsDocked()) - return std::unique_ptr<WindowResizer>(); - - int bounds_change = - WindowResizer::GetBoundsChangeForWindowComponent(window_component); - if (bounds_change == WindowResizer::kBoundsChangeDirection_None) - return std::unique_ptr<WindowResizer>(); - - window_state->CreateDragDetails(point_in_parent, window_component, source); - const int parent_shell_window_id = - window->GetParent() ? window->GetParent()->GetShellWindowId() : -1; - if (window->GetParent() && - (parent_shell_window_id == kShellWindowId_DefaultContainer || - parent_shell_window_id == kShellWindowId_DockedContainer || - parent_shell_window_id == kShellWindowId_PanelContainer)) { - window_resizer.reset( - WorkspaceWindowResizer::Create(window_state, std::vector<WmWindow*>())); - } else { - window_resizer.reset(DefaultWindowResizer::Create(window_state)); - } - window_resizer = window->GetShell()->CreateDragWindowResizer( - std::move(window_resizer), window_state); - if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL) - window_resizer.reset( - PanelWindowResizer::Create(window_resizer.release(), window_state)); - if (window_resizer && window->GetParent() && !window->GetTransientParent() && - (parent_shell_window_id == kShellWindowId_DefaultContainer || - parent_shell_window_id == kShellWindowId_DockedContainer || - parent_shell_window_id == kShellWindowId_PanelContainer)) { - window_resizer.reset( - DockedWindowResizer::Create(window_resizer.release(), window_state)); - } - return window_resizer; -} - -namespace { - -// Snapping distance used instead of WorkspaceWindowResizer::kScreenEdgeInset -// when resizing a window using touchscreen. -const int kScreenEdgeInsetForTouchDrag = 32; - -// Current instance for use by the WorkspaceWindowResizerTest. -WorkspaceWindowResizer* instance = NULL; - -// Returns true if the window should stick to the edge. -bool ShouldStickToEdge(int distance_from_edge, int sticky_size) { - return distance_from_edge < sticky_size && - distance_from_edge > -sticky_size * 2; -} - -// Returns the coordinate along the secondary axis to snap to. -int CoordinateAlongSecondaryAxis(SecondaryMagnetismEdge edge, - int leading, - int trailing, - int none) { - switch (edge) { - case SECONDARY_MAGNETISM_EDGE_LEADING: - return leading; - case SECONDARY_MAGNETISM_EDGE_TRAILING: - return trailing; - case SECONDARY_MAGNETISM_EDGE_NONE: - return none; - } - NOTREACHED(); - return none; -} - -// Returns the origin for |src| when magnetically attaching to |attach_to| along -// the edges |edges|. |edges| is a bitmask of the MagnetismEdges. -gfx::Point OriginForMagneticAttach(const gfx::Rect& src, - const gfx::Rect& attach_to, - const MatchedEdge& edge) { - int x = 0, y = 0; - switch (edge.primary_edge) { - case MAGNETISM_EDGE_TOP: - y = attach_to.bottom(); - break; - case MAGNETISM_EDGE_LEFT: - x = attach_to.right(); - break; - case MAGNETISM_EDGE_BOTTOM: - y = attach_to.y() - src.height(); - break; - case MAGNETISM_EDGE_RIGHT: - x = attach_to.x() - src.width(); - break; - } - switch (edge.primary_edge) { - case MAGNETISM_EDGE_TOP: - case MAGNETISM_EDGE_BOTTOM: - x = CoordinateAlongSecondaryAxis(edge.secondary_edge, attach_to.x(), - attach_to.right() - src.width(), - src.x()); - break; - case MAGNETISM_EDGE_LEFT: - case MAGNETISM_EDGE_RIGHT: - y = CoordinateAlongSecondaryAxis(edge.secondary_edge, attach_to.y(), - attach_to.bottom() - src.height(), - src.y()); - break; - } - return gfx::Point(x, y); -} - -// Returns the bounds for a magnetic attach when resizing. |src| is the bounds -// of window being resized, |attach_to| the bounds of the window to attach to -// and |edge| identifies the edge to attach to. -gfx::Rect BoundsForMagneticResizeAttach(const gfx::Rect& src, - const gfx::Rect& attach_to, - const MatchedEdge& edge) { - int x = src.x(); - int y = src.y(); - int w = src.width(); - int h = src.height(); - gfx::Point attach_origin(OriginForMagneticAttach(src, attach_to, edge)); - switch (edge.primary_edge) { - case MAGNETISM_EDGE_LEFT: - x = attach_origin.x(); - w = src.right() - x; - break; - case MAGNETISM_EDGE_RIGHT: - w += attach_origin.x() - src.x(); - break; - case MAGNETISM_EDGE_TOP: - y = attach_origin.y(); - h = src.bottom() - y; - break; - case MAGNETISM_EDGE_BOTTOM: - h += attach_origin.y() - src.y(); - break; - } - switch (edge.primary_edge) { - case MAGNETISM_EDGE_LEFT: - case MAGNETISM_EDGE_RIGHT: - if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_LEADING) { - y = attach_origin.y(); - h = src.bottom() - y; - } else if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_TRAILING) { - h += attach_origin.y() - src.y(); - } - break; - case MAGNETISM_EDGE_TOP: - case MAGNETISM_EDGE_BOTTOM: - if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_LEADING) { - x = attach_origin.x(); - w = src.right() - x; - } else if (edge.secondary_edge == SECONDARY_MAGNETISM_EDGE_TRAILING) { - w += attach_origin.x() - src.x(); - } - break; - } - return gfx::Rect(x, y, w, h); -} - -// Converts a window component edge to the magnetic edge to snap to. -uint32_t WindowComponentToMagneticEdge(int window_component) { - switch (window_component) { - case HTTOPLEFT: - return MAGNETISM_EDGE_LEFT | MAGNETISM_EDGE_TOP; - case HTTOPRIGHT: - return MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_RIGHT; - case HTBOTTOMLEFT: - return MAGNETISM_EDGE_LEFT | MAGNETISM_EDGE_BOTTOM; - case HTBOTTOMRIGHT: - return MAGNETISM_EDGE_RIGHT | MAGNETISM_EDGE_BOTTOM; - case HTTOP: - return MAGNETISM_EDGE_TOP; - case HTBOTTOM: - return MAGNETISM_EDGE_BOTTOM; - case HTRIGHT: - return MAGNETISM_EDGE_RIGHT; - case HTLEFT: - return MAGNETISM_EDGE_LEFT; - default: - break; - } - return 0; -} - -} // namespace - -// static -const int WorkspaceWindowResizer::kMinOnscreenSize = 20; - -// static -const int WorkspaceWindowResizer::kMinOnscreenHeight = 32; - -// static -const int WorkspaceWindowResizer::kScreenEdgeInset = 8; - -WorkspaceWindowResizer* WorkspaceWindowResizer::GetInstanceForTest() { - return instance; -} - -// Represents the width or height of a window with constraints on its minimum -// and maximum size. 0 represents a lack of a constraint. -class WindowSize { - public: - WindowSize(int size, int min, int max) : size_(size), min_(min), max_(max) { - // Grow the min/max bounds to include the starting size. - if (is_underflowing()) - min_ = size_; - if (is_overflowing()) - max_ = size_; - } - - bool is_at_capacity(bool shrinking) const { - return size_ == (shrinking ? min_ : max_); - } - - int size() const { return size_; } - - bool has_min() const { return min_ != 0; } - - bool has_max() const { return max_ != 0; } - - bool is_valid() const { return !is_overflowing() && !is_underflowing(); } - - bool is_overflowing() const { return has_max() && size_ > max_; } - - bool is_underflowing() const { return has_min() && size_ < min_; } - - // Add |amount| to this WindowSize not exceeding min or max size constraints. - // Returns by how much |size_| + |amount| exceeds the min/max constraints. - int Add(int amount) { - DCHECK(is_valid()); - int new_value = size_ + amount; - - if (has_min() && new_value < min_) { - size_ = min_; - return new_value - min_; - } - - if (has_max() && new_value > max_) { - size_ = max_; - return new_value - max_; - } - - size_ = new_value; - return 0; - } - - private: - int size_; - int min_; - int max_; -}; - -WorkspaceWindowResizer::~WorkspaceWindowResizer() { - if (did_lock_cursor_) - shell_->UnlockCursor(); - - if (instance == this) - instance = NULL; -} - -// static -WorkspaceWindowResizer* WorkspaceWindowResizer::Create( - wm::WindowState* window_state, - const std::vector<WmWindow*>& attached_windows) { - return new WorkspaceWindowResizer(window_state, attached_windows); -} - -void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_parent, - int event_flags) { - last_mouse_location_ = location_in_parent; - - int sticky_size; - if (event_flags & ui::EF_CONTROL_DOWN) { - sticky_size = 0; - } else if ((details().bounds_change & kBoundsChange_Resizes) && - details().source == aura::client::WINDOW_MOVE_SOURCE_TOUCH) { - sticky_size = kScreenEdgeInsetForTouchDrag; - } else { - sticky_size = kScreenEdgeInset; - } - // |bounds| is in |GetTarget()->parent()|'s coordinates. - gfx::Rect bounds = CalculateBoundsForDrag(location_in_parent); - AdjustBoundsForMainWindow(sticky_size, &bounds); - - if (bounds != GetTarget()->GetBounds()) { - if (!did_move_or_resize_) { - if (!details().restore_bounds.IsEmpty()) - window_state()->ClearRestoreBounds(); - RestackWindows(); - } - did_move_or_resize_ = true; - } - - gfx::Point location_in_screen = - GetTarget()->GetParent()->ConvertPointToScreen(location_in_parent); - - WmWindow* root = nullptr; - display::Display display = - display::Screen::GetScreen()->GetDisplayNearestPoint(location_in_screen); - // Track the last screen that the pointer was on to keep the snap phantom - // window there. - if (display.bounds().Contains(location_in_screen)) { - root = - Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow(); - } - if (!attached_windows_.empty()) - LayoutAttachedWindows(&bounds); - if (bounds != GetTarget()->GetBounds()) { - // SetBounds needs to be called to update the layout which affects where the - // phantom window is drawn. Keep track if the window was destroyed during - // the drag and quit early if so. - base::WeakPtr<WorkspaceWindowResizer> resizer( - weak_ptr_factory_.GetWeakPtr()); - GetTarget()->SetBounds(bounds); - if (!resizer) - return; - } - const bool in_original_root = !root || root == GetTarget()->GetRootWindow(); - // Hide a phantom window for snapping if the cursor is in another root window. - if (in_original_root) { - UpdateSnapPhantomWindow(location_in_parent, bounds); - } else { - snap_type_ = SNAP_NONE; - snap_phantom_window_controller_.reset(); - edge_cycler_.reset(); - SetDraggedWindowDocked(false); - } -} - -void WorkspaceWindowResizer::CompleteDrag() { - if (!did_move_or_resize_) - return; - - window_state()->set_bounds_changed_by_user(true); - snap_phantom_window_controller_.reset(); - - // If the window's state type changed over the course of the drag do not snap - // the window. This happens when the user minimizes or maximizes the window - // using a keyboard shortcut while dragging it. - if (window_state()->GetStateType() != details().initial_state_type) - return; - - bool snapped = false; - if (snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT) { - if (!window_state()->HasRestoreBounds()) { - gfx::Rect initial_bounds = GetTarget()->GetParent()->ConvertRectToScreen( - details().initial_bounds_in_parent); - window_state()->SetRestoreBoundsInScreen( - details().restore_bounds.IsEmpty() ? initial_bounds - : details().restore_bounds); - } - if (!dock_layout_->is_dragged_window_docked()) { - // TODO(oshima): Add event source type to WMEvent and move - // metrics recording inside WindowState::OnWMEvent. - const wm::WMEvent event(snap_type_ == SNAP_LEFT - ? wm::WM_EVENT_SNAP_LEFT - : wm::WM_EVENT_SNAP_RIGHT); - window_state()->OnWMEvent(&event); - shell_->RecordUserMetricsAction(snap_type_ == SNAP_LEFT - ? UMA_DRAG_MAXIMIZE_LEFT - : UMA_DRAG_MAXIMIZE_RIGHT); - snapped = true; - } - } - - if (!snapped) { - if (window_state()->IsSnapped()) { - // Keep the window snapped if the user resizes the window such that the - // window has valid bounds for a snapped window. Always unsnap the window - // if the user dragged the window via the caption area because doing this - // is slightly less confusing. - if (details().window_component == HTCAPTION || - !AreBoundsValidSnappedBounds(window_state()->GetStateType(), - GetTarget()->GetBounds())) { - // Set the window to WINDOW_STATE_TYPE_NORMAL but keep the - // window at the bounds that the user has moved/resized the - // window to. - window_state()->SaveCurrentBoundsForRestore(); - window_state()->Restore(); - } - } else if (!dock_layout_->is_dragged_window_docked()) { - // The window was not snapped and is not snapped. This is a user - // resize/drag and so the current bounds should be maintained, clearing - // any prior restore bounds. When the window is docked the restore bound - // must be kept so the docked state can be reverted properly. - window_state()->ClearRestoreBounds(); - } - } -} - -void WorkspaceWindowResizer::RevertDrag() { - window_state()->set_bounds_changed_by_user(initial_bounds_changed_by_user_); - snap_phantom_window_controller_.reset(); - - if (!did_move_or_resize_) - return; - - GetTarget()->SetBounds(details().initial_bounds_in_parent); - if (!details().restore_bounds.IsEmpty()) - window_state()->SetRestoreBoundsInScreen(details().restore_bounds); - - if (details().window_component == HTRIGHT) { - int last_x = details().initial_bounds_in_parent.right(); - for (size_t i = 0; i < attached_windows_.size(); ++i) { - gfx::Rect bounds(attached_windows_[i]->GetBounds()); - bounds.set_x(last_x); - bounds.set_width(initial_size_[i]); - attached_windows_[i]->SetBounds(bounds); - last_x = attached_windows_[i]->GetBounds().right(); - } - } else { - int last_y = details().initial_bounds_in_parent.bottom(); - for (size_t i = 0; i < attached_windows_.size(); ++i) { - gfx::Rect bounds(attached_windows_[i]->GetBounds()); - bounds.set_y(last_y); - bounds.set_height(initial_size_[i]); - attached_windows_[i]->SetBounds(bounds); - last_y = attached_windows_[i]->GetBounds().bottom(); - } - } -} - -WorkspaceWindowResizer::WorkspaceWindowResizer( - wm::WindowState* window_state, - const std::vector<WmWindow*>& attached_windows) - : WindowResizer(window_state), - attached_windows_(attached_windows), - shell_(window_state->window()->GetShell()), - did_lock_cursor_(false), - did_move_or_resize_(false), - initial_bounds_changed_by_user_(window_state_->bounds_changed_by_user()), - total_min_(0), - total_initial_size_(0), - snap_type_(SNAP_NONE), - num_mouse_moves_since_bounds_change_(0), - magnetism_window_(NULL), - weak_ptr_factory_(this) { - DCHECK(details().is_resizable); - - // A mousemove should still show the cursor even if the window is - // being moved or resized with touch, so do not lock the cursor. - if (details().source != aura::client::WINDOW_MOVE_SOURCE_TOUCH) { - shell_->LockCursor(); - did_lock_cursor_ = true; - } - - dock_layout_ = DockedWindowLayoutManager::Get(GetTarget()); - - // Only support attaching to the right/bottom. - DCHECK(attached_windows_.empty() || (details().window_component == HTRIGHT || - details().window_component == HTBOTTOM)); - - // TODO: figure out how to deal with window going off the edge. - - // Calculate sizes so that we can maintain the ratios if we need to resize. - int total_available = 0; - for (size_t i = 0; i < attached_windows_.size(); ++i) { - gfx::Size min(attached_windows_[i]->GetMinimumSize()); - int initial_size = - PrimaryAxisSize(attached_windows_[i]->GetBounds().size()); - initial_size_.push_back(initial_size); - // If current size is smaller than the min, use the current size as the min. - // This way we don't snap on resize. - int min_size = std::min(initial_size, - std::max(PrimaryAxisSize(min), kMinOnscreenSize)); - total_min_ += min_size; - total_initial_size_ += initial_size; - total_available += std::max(min_size, initial_size) - min_size; - } - instance = this; -} - -void WorkspaceWindowResizer::LayoutAttachedWindows(gfx::Rect* bounds) { - gfx::Rect work_area(wm::GetDisplayWorkAreaBoundsInParent(GetTarget())); - int initial_size = PrimaryAxisSize(details().initial_bounds_in_parent.size()); - int current_size = PrimaryAxisSize(bounds->size()); - int start = PrimaryAxisCoordinate(bounds->right(), bounds->bottom()); - int end = PrimaryAxisCoordinate(work_area.right(), work_area.bottom()); - - int delta = current_size - initial_size; - int available_size = end - start; - std::vector<int> sizes; - int leftovers = CalculateAttachedSizes(delta, available_size, &sizes); - - // leftovers > 0 means that the attached windows can't grow to compensate for - // the shrinkage of the main window. This line causes the attached windows to - // be moved so they are still flush against the main window, rather than the - // main window being prevented from shrinking. - leftovers = std::min(0, leftovers); - // Reallocate any leftover pixels back into the main window. This is - // necessary when, for example, the main window shrinks, but none of the - // attached windows can grow without exceeding their max size constraints. - // Adding the pixels back to the main window effectively prevents the main - // window from resizing too far. - if (details().window_component == HTRIGHT) - bounds->set_width(bounds->width() + leftovers); - else - bounds->set_height(bounds->height() + leftovers); - - DCHECK_EQ(attached_windows_.size(), sizes.size()); - int last = PrimaryAxisCoordinate(bounds->right(), bounds->bottom()); - for (size_t i = 0; i < attached_windows_.size(); ++i) { - gfx::Rect attached_bounds(attached_windows_[i]->GetBounds()); - if (details().window_component == HTRIGHT) { - attached_bounds.set_x(last); - attached_bounds.set_width(sizes[i]); - } else { - attached_bounds.set_y(last); - attached_bounds.set_height(sizes[i]); - } - attached_windows_[i]->SetBounds(attached_bounds); - last += sizes[i]; - } -} - -int WorkspaceWindowResizer::CalculateAttachedSizes( - int delta, - int available_size, - std::vector<int>* sizes) const { - std::vector<WindowSize> window_sizes; - CreateBucketsForAttached(&window_sizes); - - // How much we need to grow the attached by (collectively). - int grow_attached_by = 0; - if (delta > 0) { - // If the attached windows don't fit when at their initial size, we will - // have to shrink them by how much they overflow. - if (total_initial_size_ >= available_size) - grow_attached_by = available_size - total_initial_size_; - } else { - // If we're shrinking, we grow the attached so the total size remains - // constant. - grow_attached_by = -delta; - } - - int leftover_pixels = 0; - while (grow_attached_by != 0) { - int leftovers = GrowFairly(grow_attached_by, &window_sizes); - if (leftovers == grow_attached_by) { - leftover_pixels = leftovers; - break; - } - grow_attached_by = leftovers; - } - - for (size_t i = 0; i < window_sizes.size(); ++i) - sizes->push_back(window_sizes[i].size()); - - return leftover_pixels; -} - -int WorkspaceWindowResizer::GrowFairly(int pixels, - std::vector<WindowSize>* sizes) const { - bool shrinking = pixels < 0; - std::vector<WindowSize*> nonfull_windows; - for (size_t i = 0; i < sizes->size(); ++i) { - WindowSize& current_window_size = (*sizes)[i]; - if (!current_window_size.is_at_capacity(shrinking)) - nonfull_windows.push_back(¤t_window_size); - } - std::vector<float> ratios; - CalculateGrowthRatios(nonfull_windows, &ratios); - - int remaining_pixels = pixels; - bool add_leftover_pixels_to_last = true; - for (size_t i = 0; i < nonfull_windows.size(); ++i) { - int grow_by = pixels * ratios[i]; - // Put any leftover pixels into the last window. - if (i == nonfull_windows.size() - 1 && add_leftover_pixels_to_last) - grow_by = remaining_pixels; - int remainder = nonfull_windows[i]->Add(grow_by); - int consumed = grow_by - remainder; - remaining_pixels -= consumed; - if (nonfull_windows[i]->is_at_capacity(shrinking) && remainder > 0) { - // Because this window overflowed, some of the pixels in - // |remaining_pixels| aren't there due to rounding errors. Rather than - // unfairly giving all those pixels to the last window, we refrain from - // allocating them so that this function can be called again to distribute - // the pixels fairly. - add_leftover_pixels_to_last = false; - } - } - return remaining_pixels; -} - -void WorkspaceWindowResizer::CalculateGrowthRatios( - const std::vector<WindowSize*>& sizes, - std::vector<float>* out_ratios) const { - DCHECK(out_ratios->empty()); - int total_value = 0; - for (size_t i = 0; i < sizes.size(); ++i) - total_value += sizes[i]->size(); - - for (size_t i = 0; i < sizes.size(); ++i) - out_ratios->push_back((static_cast<float>(sizes[i]->size())) / total_value); -} - -void WorkspaceWindowResizer::CreateBucketsForAttached( - std::vector<WindowSize>* sizes) const { - for (size_t i = 0; i < attached_windows_.size(); i++) { - int initial_size = initial_size_[i]; - int min = PrimaryAxisSize(attached_windows_[i]->GetMinimumSize()); - int max = PrimaryAxisSize(attached_windows_[i]->GetMaximumSize()); - - sizes->push_back(WindowSize(initial_size, min, max)); - } -} - -void WorkspaceWindowResizer::MagneticallySnapToOtherWindows(gfx::Rect* bounds) { - if (UpdateMagnetismWindow(*bounds, kAllMagnetismEdges)) { - gfx::Point point = OriginForMagneticAttach( - GetTarget()->GetParent()->ConvertRectToScreen(*bounds), - magnetism_window_->GetBoundsInScreen(), magnetism_edge_); - point = GetTarget()->GetParent()->ConvertPointFromScreen(point); - bounds->set_origin(point); - } -} - -void WorkspaceWindowResizer::MagneticallySnapResizeToOtherWindows( - gfx::Rect* bounds) { - const uint32_t edges = - WindowComponentToMagneticEdge(details().window_component); - if (UpdateMagnetismWindow(*bounds, edges)) { - *bounds = GetTarget()->GetParent()->ConvertRectFromScreen( - BoundsForMagneticResizeAttach( - GetTarget()->GetParent()->ConvertRectToScreen(*bounds), - magnetism_window_->GetBoundsInScreen(), magnetism_edge_)); - } -} - -bool WorkspaceWindowResizer::UpdateMagnetismWindow(const gfx::Rect& bounds, - uint32_t edges) { - // |bounds| are in coordinates of original window's parent. - gfx::Rect bounds_in_screen = - GetTarget()->GetParent()->ConvertRectToScreen(bounds); - MagnetismMatcher matcher(bounds_in_screen, edges); - - // If we snapped to a window then check it first. That way we don't bounce - // around when close to multiple edges. - if (magnetism_window_) { - if (window_tracker_.Contains(magnetism_window_->aura_window()) && - matcher.ShouldAttach(magnetism_window_->GetBoundsInScreen(), - &magnetism_edge_)) { - return true; - } - window_tracker_.Remove(magnetism_window_->aura_window()); - magnetism_window_ = NULL; - } - - // Avoid magnetically snapping windows that are not resizable. - // TODO(oshima): change this to window.type() == TYPE_NORMAL. - if (!window_state()->CanResize()) - return false; - - for (WmWindow* root_window : shell_->GetAllRootWindows()) { - // Test all children from the desktop in each root window. - const std::vector<WmWindow*> children = - root_window->GetChildByShellWindowId(kShellWindowId_DefaultContainer) - ->GetChildren(); - for (auto i = children.rbegin(); - i != children.rend() && !matcher.AreEdgesObscured(); ++i) { - wm::WindowState* other_state = (*i)->GetWindowState(); - if (other_state->window() == GetTarget() || - !other_state->window()->IsVisible() || - !other_state->IsNormalOrSnapped() || !other_state->CanResize()) { - continue; - } - if (matcher.ShouldAttach(other_state->window()->GetBoundsInScreen(), - &magnetism_edge_)) { - magnetism_window_ = other_state->window(); - window_tracker_.Add(magnetism_window_->aura_window()); - return true; - } - } - } - return false; -} - -void WorkspaceWindowResizer::AdjustBoundsForMainWindow(int sticky_size, - gfx::Rect* bounds) { - gfx::Point last_mouse_location_in_screen = - GetTarget()->GetParent()->ConvertPointToScreen(last_mouse_location_); - display::Display display = - display::Screen::GetScreen()->GetDisplayNearestPoint( - last_mouse_location_in_screen); - gfx::Rect work_area = - GetTarget()->GetParent()->ConvertRectFromScreen(display.work_area()); - if (details().window_component == HTCAPTION) { - // Adjust the bounds to the work area where the mouse cursor is located. - // Always keep kMinOnscreenHeight or the window height (whichever is less) - // on the bottom. - int max_y = - work_area.bottom() - std::min(kMinOnscreenHeight, bounds->height()); - if (bounds->y() > max_y) { - bounds->set_y(max_y); - } else if (bounds->y() <= work_area.y()) { - // Don't allow dragging above the top of the display until the mouse - // cursor reaches the work area above if any. - bounds->set_y(work_area.y()); - } - - if (sticky_size > 0) { - // Possibly stick to edge except when a mouse pointer is outside the - // work area. - if (display.work_area().Contains(last_mouse_location_in_screen)) - StickToWorkAreaOnMove(work_area, sticky_size, bounds); - MagneticallySnapToOtherWindows(bounds); - } - } else if (sticky_size > 0) { - MagneticallySnapResizeToOtherWindows(bounds); - if (!magnetism_window_ && sticky_size > 0) - StickToWorkAreaOnResize(work_area, sticky_size, bounds); - } - - if (attached_windows_.empty()) - return; - - if (details().window_component == HTRIGHT) { - bounds->set_width(std::min(bounds->width(), - work_area.right() - total_min_ - bounds->x())); - } else { - DCHECK_EQ(HTBOTTOM, details().window_component); - bounds->set_height(std::min(bounds->height(), - work_area.bottom() - total_min_ - bounds->y())); - } -} - -bool WorkspaceWindowResizer::StickToWorkAreaOnMove(const gfx::Rect& work_area, - int sticky_size, - gfx::Rect* bounds) const { - const int left_edge = work_area.x(); - const int right_edge = work_area.right(); - const int top_edge = work_area.y(); - const int bottom_edge = work_area.bottom(); - bool updated = false; - if (ShouldStickToEdge(bounds->x() - left_edge, sticky_size)) { - bounds->set_x(left_edge); - updated = true; - } else if (ShouldStickToEdge(right_edge - bounds->right(), sticky_size)) { - bounds->set_x(right_edge - bounds->width()); - updated = true; - } - if (ShouldStickToEdge(bounds->y() - top_edge, sticky_size)) { - bounds->set_y(top_edge); - updated = true; - } else if (ShouldStickToEdge(bottom_edge - bounds->bottom(), sticky_size) && - bounds->height() < (bottom_edge - top_edge)) { - // Only snap to the bottom if the window is smaller than the work area. - // Doing otherwise can lead to window snapping in weird ways as it bounces - // between snapping to top then bottom. - bounds->set_y(bottom_edge - bounds->height()); - updated = true; - } - return updated; -} - -void WorkspaceWindowResizer::StickToWorkAreaOnResize(const gfx::Rect& work_area, - int sticky_size, - gfx::Rect* bounds) const { - const uint32_t edges = - WindowComponentToMagneticEdge(details().window_component); - const int left_edge = work_area.x(); - const int right_edge = work_area.right(); - const int top_edge = work_area.y(); - const int bottom_edge = work_area.bottom(); - if (edges & MAGNETISM_EDGE_TOP && - ShouldStickToEdge(bounds->y() - top_edge, sticky_size)) { - bounds->set_height(bounds->bottom() - top_edge); - bounds->set_y(top_edge); - } - if (edges & MAGNETISM_EDGE_LEFT && - ShouldStickToEdge(bounds->x() - left_edge, sticky_size)) { - bounds->set_width(bounds->right() - left_edge); - bounds->set_x(left_edge); - } - if (edges & MAGNETISM_EDGE_BOTTOM && - ShouldStickToEdge(bottom_edge - bounds->bottom(), sticky_size)) { - bounds->set_height(bottom_edge - bounds->y()); - } - if (edges & MAGNETISM_EDGE_RIGHT && - ShouldStickToEdge(right_edge - bounds->right(), sticky_size)) { - bounds->set_width(right_edge - bounds->x()); - } -} - -int WorkspaceWindowResizer::PrimaryAxisSize(const gfx::Size& size) const { - return PrimaryAxisCoordinate(size.width(), size.height()); -} - -int WorkspaceWindowResizer::PrimaryAxisCoordinate(int x, int y) const { - switch (details().window_component) { - case HTRIGHT: - return x; - case HTBOTTOM: - return y; - default: - NOTREACHED(); - } - return 0; -} - -void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, - const gfx::Rect& bounds) { - if (!did_move_or_resize_ || details().window_component != HTCAPTION) - return; - - SnapType last_type = snap_type_; - snap_type_ = GetSnapType(location); - if (snap_type_ == SNAP_NONE || snap_type_ != last_type) { - snap_phantom_window_controller_.reset(); - edge_cycler_.reset(); - if (snap_type_ == SNAP_NONE) { - SetDraggedWindowDocked(false); - return; - } - } - - DCHECK(snap_type_ == SNAP_LEFT || snap_type_ == SNAP_RIGHT); - DockedAlignment desired_alignment = (snap_type_ == SNAP_LEFT) - ? DOCKED_ALIGNMENT_LEFT - : DOCKED_ALIGNMENT_RIGHT; - const bool can_dock = - ash::switches::DockedWindowsEnabled() && - dock_layout_->CanDockWindow(GetTarget(), desired_alignment) && - dock_layout_->GetAlignmentOfWindow(GetTarget()) != DOCKED_ALIGNMENT_NONE; - if (!can_dock) { - // If the window cannot be docked, undock the window. This may change the - // workspace bounds and hence |snap_type_|. - SetDraggedWindowDocked(false); - snap_type_ = GetSnapType(location); - } - const bool can_snap = snap_type_ != SNAP_NONE && window_state()->CanSnap(); - if (!can_snap && !can_dock) { - snap_type_ = SNAP_NONE; - snap_phantom_window_controller_.reset(); - edge_cycler_.reset(); - return; - } - if (!edge_cycler_) { - edge_cycler_.reset(new TwoStepEdgeCycler( - location, snap_type_ == SNAP_LEFT - ? TwoStepEdgeCycler::DIRECTION_LEFT - : TwoStepEdgeCycler::DIRECTION_RIGHT)); - } else { - edge_cycler_->OnMove(location); - } - - // Update phantom window with snapped or docked guide bounds. - // Windows that cannot be snapped or are less wide than kMaxDockWidth can get - // docked without going through a snapping sequence. - gfx::Rect phantom_bounds; - const bool should_dock = - can_dock && (!can_snap || - GetTarget()->GetBounds().width() <= - DockedWindowLayoutManager::kMaxDockWidth || - edge_cycler_->use_second_mode() || - dock_layout_->is_dragged_window_docked()); - if (should_dock) { - SetDraggedWindowDocked(true); - phantom_bounds = GetTarget()->GetParent()->ConvertRectFromScreen( - dock_layout_->dragged_bounds()); - } else { - phantom_bounds = - (snap_type_ == SNAP_LEFT) - ? wm::GetDefaultLeftSnappedWindowBoundsInParent(GetTarget()) - : wm::GetDefaultRightSnappedWindowBoundsInParent(GetTarget()); - } - - if (!snap_phantom_window_controller_) { - snap_phantom_window_controller_.reset( - new PhantomWindowController(GetTarget())); - } - snap_phantom_window_controller_->Show( - GetTarget()->GetParent()->ConvertRectToScreen(phantom_bounds)); -} - -void WorkspaceWindowResizer::RestackWindows() { - if (attached_windows_.empty()) - return; - // Build a map from index in children to window, returning if there is a - // window with a different parent. - using IndexToWindowMap = std::map<size_t, WmWindow*>; - IndexToWindowMap map; - WmWindow* parent = GetTarget()->GetParent(); - const std::vector<WmWindow*> windows(parent->GetChildren()); - map[std::find(windows.begin(), windows.end(), GetTarget()) - - windows.begin()] = GetTarget(); - for (auto i = attached_windows_.begin(); i != attached_windows_.end(); ++i) { - if ((*i)->GetParent() != parent) - return; - size_t index = - std::find(windows.begin(), windows.end(), *i) - windows.begin(); - map[index] = *i; - } - - // Reorder the windows starting at the topmost. - parent->StackChildAtTop(map.rbegin()->second); - for (auto i = map.rbegin(); i != map.rend();) { - WmWindow* window = i->second; - ++i; - if (i != map.rend()) - parent->StackChildBelow(i->second, window); - } -} - -WorkspaceWindowResizer::SnapType WorkspaceWindowResizer::GetSnapType( - const gfx::Point& location) const { - // TODO: this likely only wants total display area, not the area of a single - // display. - gfx::Rect area(wm::GetDisplayWorkAreaBoundsInParent(GetTarget())); - if (details().source == aura::client::WINDOW_MOVE_SOURCE_TOUCH) { - // Increase tolerance for touch-snapping near the screen edges. This is only - // necessary when the work area left or right edge is same as screen edge. - gfx::Rect display_bounds(wm::GetDisplayBoundsInParent(GetTarget())); - int inset_left = 0; - if (area.x() == display_bounds.x()) - inset_left = kScreenEdgeInsetForTouchDrag; - int inset_right = 0; - if (area.right() == display_bounds.right()) - inset_right = kScreenEdgeInsetForTouchDrag; - area.Inset(inset_left, 0, inset_right, 0); - } - if (location.x() <= area.x()) - return SNAP_LEFT; - if (location.x() >= area.right() - 1) - return SNAP_RIGHT; - return SNAP_NONE; -} - -void WorkspaceWindowResizer::SetDraggedWindowDocked(bool should_dock) { - if (should_dock) { - if (!dock_layout_->is_dragged_window_docked()) { - window_state()->set_bounds_changed_by_user(false); - dock_layout_->DockDraggedWindow(GetTarget()); - } - } else { - if (dock_layout_->is_dragged_window_docked()) { - dock_layout_->UndockDraggedWindow(); - window_state()->set_bounds_changed_by_user(true); - } - } -} - -bool WorkspaceWindowResizer::AreBoundsValidSnappedBounds( - wm::WindowStateType snapped_type, - const gfx::Rect& bounds_in_parent) const { - DCHECK(snapped_type == wm::WINDOW_STATE_TYPE_LEFT_SNAPPED || - snapped_type == wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED); - gfx::Rect snapped_bounds = wm::GetDisplayWorkAreaBoundsInParent(GetTarget()); - if (snapped_type == wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED) - snapped_bounds.set_x(snapped_bounds.right() - bounds_in_parent.width()); - snapped_bounds.set_width(bounds_in_parent.width()); - return bounds_in_parent == snapped_bounds; -} - -} // namespace ash
diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h deleted file mode 100644 index 13edf62..0000000 --- a/ash/wm/workspace/workspace_window_resizer.h +++ /dev/null
@@ -1,230 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_ -#define ASH_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_ - -#include <stdint.h> - -#include <memory> -#include <vector> - -#include "ash/wm/window_resizer.h" -#include "ash/wm/workspace/magnetism_matcher.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "ui/aura/window_tracker.h" - -namespace ash { -class DockedWindowLayoutManager; -class PhantomWindowController; -class TwoStepEdgeCycler; -class WindowSize; -class WmShell; - -namespace wm { -class WindowState; -} - -// WindowResizer implementation for workspaces. This enforces that windows are -// not allowed to vertically move or resize outside of the work area. As windows -// are moved outside the work area they are shrunk. We remember the height of -// the window before it was moved so that if the window is again moved up we -// attempt to restore the old height. -class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { - public: - // When dragging an attached window this is the min size we'll make sure is - // visible. In the vertical direction we take the max of this and that from - // the delegate. - static const int kMinOnscreenSize; - - // Min height we'll force on screen when dragging the caption. - // TODO: this should come from a property on the window. - static const int kMinOnscreenHeight; - - // Snap region when dragging close to the edges. That is, as the window gets - // this close to an edge of the screen it snaps to the edge. - static const int kScreenEdgeInset; - - // Distance in pixels that the cursor must move past an edge for a window - // to move or resize beyond that edge. - static const int kStickyDistancePixels; - - ~WorkspaceWindowResizer() override; - - static WorkspaceWindowResizer* Create( - wm::WindowState* window_state, - const std::vector<WmWindow*>& attached_windows); - - // WindowResizer: - void Drag(const gfx::Point& location_in_parent, int event_flags) override; - void CompleteDrag() override; - void RevertDrag() override; - - private: - friend class WorkspaceWindowResizerTest; - - // The edge to which the window should be snapped at the end of the drag. - enum SnapType { SNAP_LEFT, SNAP_RIGHT, SNAP_NONE }; - - WorkspaceWindowResizer(wm::WindowState* window_state, - const std::vector<WmWindow*>& attached_windows); - - // Lays out the attached windows. |bounds| is the bounds of the main window. - void LayoutAttachedWindows(gfx::Rect* bounds); - - // Calculates the new sizes of the attached windows, given that the main - // window has been resized (along the primary axis) by |delta|. - // |available_size| is the maximum length of the space that the attached - // windows are allowed to occupy (ie: the distance between the right/bottom - // edge of the primary window and the right/bottom of the desktop area). - // Populates |sizes| with the desired sizes of the attached windows, and - // returns the number of pixels that couldn't be allocated to the attached - // windows (due to min/max size constraints). - // Note the return value can be positive or negative, a negative value - // indicating that that many pixels couldn't be removed from the attached - // windows. - int CalculateAttachedSizes(int delta, - int available_size, - std::vector<int>* sizes) const; - - // Divides |amount| evenly between |sizes|. If |amount| is negative it - // indicates how many pixels |sizes| should be shrunk by. - // Returns how many pixels failed to be allocated/removed from |sizes|. - int GrowFairly(int amount, std::vector<WindowSize>* sizes) const; - - // Calculate the ratio of pixels that each WindowSize in |sizes| should - // receive when growing or shrinking. - void CalculateGrowthRatios(const std::vector<WindowSize*>& sizes, - std::vector<float>* out_ratios) const; - - // Adds a WindowSize to |sizes| for each attached window. - void CreateBucketsForAttached(std::vector<WindowSize>* sizes) const; - - // If possible snaps the window to a neary window. Updates |bounds| if there - // was a close enough window. - void MagneticallySnapToOtherWindows(gfx::Rect* bounds); - - // If possible snaps the resize to a neary window. Updates |bounds| if there - // was a close enough window. - void MagneticallySnapResizeToOtherWindows(gfx::Rect* bounds); - - // Finds the neareset window to magentically snap to. Updates - // |magnetism_window_| and |magnetism_edge_| appropriately. |edges| is a - // bitmask of the MagnetismEdges to match again. Returns true if a match is - // found. - bool UpdateMagnetismWindow(const gfx::Rect& bounds, uint32_t edges); - - // Adjusts the bounds of the window: magnetically snapping, ensuring the - // window has enough on screen... |snap_size| is the distance from an edge of - // the work area before the window is snapped. A value of 0 results in no - // snapping. - void AdjustBoundsForMainWindow(int snap_size, gfx::Rect* bounds); - - // Stick the window bounds to the work area during a move. - bool StickToWorkAreaOnMove(const gfx::Rect& work_area, - int sticky_size, - gfx::Rect* bounds) const; - - // Stick the window bounds to the work area during a resize. - void StickToWorkAreaOnResize(const gfx::Rect& work_area, - int sticky_size, - gfx::Rect* bounds) const; - - // Returns a coordinate along the primary axis. Used to share code for - // left/right multi window resize and top/bottom resize. - int PrimaryAxisSize(const gfx::Size& size) const; - int PrimaryAxisCoordinate(int x, int y) const; - - // Updates the bounds of the phantom window for window snapping. - void UpdateSnapPhantomWindow(const gfx::Point& location, - const gfx::Rect& bounds); - - // Restacks the windows z-order position so that one of the windows is at the - // top of the z-order, and the rest directly underneath it. - void RestackWindows(); - - // Returns the edge to which the window should be snapped to if the user does - // no more dragging. SNAP_NONE is returned if the window should not be - // snapped. - SnapType GetSnapType(const gfx::Point& location) const; - - // Returns true if |bounds_in_parent| are valid bounds for snapped state type - // |snapped_type|. - bool AreBoundsValidSnappedBounds(wm::WindowStateType snapped_type, - const gfx::Rect& bounds_in_parent) const; - - // Docks or undocks the dragged window. - void SetDraggedWindowDocked(bool should_dock); - - wm::WindowState* window_state() { return window_state_; } - - const std::vector<WmWindow*> attached_windows_; - - WmShell* shell_; - - // Returns the currently used instance for test. - static WorkspaceWindowResizer* GetInstanceForTest(); - - bool did_lock_cursor_; - - // Set to true once Drag() is invoked and the bounds of the window change. - bool did_move_or_resize_; - - // True if the window initially had |bounds_changed_by_user_| set in state. - bool initial_bounds_changed_by_user_; - - // The initial size of each of the windows in |attached_windows_| along the - // primary axis. - std::vector<int> initial_size_; - - // Sum of the minimum sizes of the attached windows. - int total_min_; - - // Sum of the sizes in |initial_size_|. - int total_initial_size_; - - // Gives a previews of where the the window will end up. Only used if there - // is a grid and the caption is being dragged. - std::unique_ptr<PhantomWindowController> snap_phantom_window_controller_; - - // Used to determine whether the window should be snapped or docked when - // the user drags a window to the edge of the screen. - std::unique_ptr<TwoStepEdgeCycler> edge_cycler_; - - // The edge to which the window should be snapped to at the end of the drag. - SnapType snap_type_; - - // Number of mouse moves since the last bounds change. Only used for phantom - // placement to track when the mouse is moved while pushed against the edge of - // the screen. - int num_mouse_moves_since_bounds_change_; - - // The mouse location passed to Drag(). - gfx::Point last_mouse_location_; - - // Window the drag has magnetically attached to. - WmWindow* magnetism_window_; - - // Used to verify |magnetism_window_| is still valid. - aura::WindowTracker window_tracker_; - - // If |magnetism_window_| is non-NULL this indicates how the two windows - // should attach. - MatchedEdge magnetism_edge_; - - // Dock container window layout manager. - DockedWindowLayoutManager* dock_layout_; - - // Used to determine if this has been deleted during a drag such as when a tab - // gets dragged into another browser window. - base::WeakPtrFactory<WorkspaceWindowResizer> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizer); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_WORKSPACE_WINDOW_RESIZER_H_
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc index 992bf67c..8979daa14 100644 --- a/ash/wm/workspace/workspace_window_resizer_unittest.cc +++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -2,24 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/workspace/workspace_window_resizer.h" +#include "ash/common/wm/workspace/workspace_window_resizer.h" #include "ash/common/ash_switches.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_positioning_utils.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace/phantom_window_controller.h" +#include "ash/common/wm/workspace_controller.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/screen_util.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_positioning_utils.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace/phantom_window_controller.h" -#include "ash/wm/workspace_controller.h" #include "base/command_line.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h"
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc deleted file mode 100644 index feb3e61b..0000000 --- a/ash/wm/workspace_controller.cc +++ /dev/null
@@ -1,134 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/wm/workspace_controller.h" - -#include <utility> - -#include "ash/common/wm_shell.h" -#include "ash/common/wm_window.h" -#include "ash/public/cpp/shell_window_ids.h" -#include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/dock/docked_window_layout_manager.h" -#include "ash/wm/fullscreen_window_finder.h" -#include "ash/wm/window_state.h" -#include "ash/wm/wm_window_animations.h" -#include "ash/wm/workspace/workspace_event_handler.h" -#include "ash/wm/workspace/workspace_layout_manager.h" -#include "ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h" -#include "base/memory/ptr_util.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/scoped_layer_animation_settings.h" - -namespace ash { -namespace { - -// Amount of time to pause before animating anything. Only used during initial -// animation (when logging in). -const int kInitialPauseTimeMS = 750; - -// The duration of the animation that occurs on first login. -const int kInitialAnimationDurationMS = 200; - -} // namespace - -WorkspaceController::WorkspaceController(WmWindow* viewport) - : viewport_(viewport), - event_handler_(WmShell::Get()->CreateWorkspaceEventHandler(viewport)), - layout_manager_(new WorkspaceLayoutManager(viewport)) { - viewport_->aura_window()->AddObserver(this); - viewport_->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE); - viewport_->SetLayoutManager(base::WrapUnique(layout_manager_)); -} - -WorkspaceController::~WorkspaceController() { - if (!viewport_) - return; - - viewport_->aura_window()->RemoveObserver(this); - viewport_->SetLayoutManager(nullptr); -} - -wm::WorkspaceWindowState WorkspaceController::GetWindowState() const { - if (!viewport_ || !viewport_->GetRootWindowController()->HasShelf()) - return wm::WORKSPACE_WINDOW_STATE_DEFAULT; - - const WmWindow* fullscreen = wm::GetWindowForFullscreenMode(viewport_); - if (fullscreen && !fullscreen->GetWindowState()->ignored_by_shelf()) - return wm::WORKSPACE_WINDOW_STATE_FULL_SCREEN; - - // These are the container ids of containers which may contain windows that - // may overlap the launcher shelf and affect its transparency. - const int kWindowContainerIds[] = { - kShellWindowId_DefaultContainer, kShellWindowId_DockedContainer, - }; - const gfx::Rect shelf_bounds(WmShelf::ForWindow(viewport_)->GetIdealBounds()); - bool window_overlaps_launcher = false; - for (size_t i = 0; i < arraysize(kWindowContainerIds); i++) { - WmWindow* container = viewport_->GetRootWindow()->GetChildByShellWindowId( - kWindowContainerIds[i]); - for (WmWindow* window : container->GetChildren()) { - wm::WindowState* window_state = window->GetWindowState(); - if (window_state->ignored_by_shelf() || - (window->GetLayer() && !window->GetLayer()->GetTargetVisibility())) { - continue; - } - if (window_state->IsMaximized()) - return wm::WORKSPACE_WINDOW_STATE_MAXIMIZED; - window_overlaps_launcher |= window->GetBounds().Intersects(shelf_bounds); - } - } - - // Check if there are visible docked windows in the same display. - DockedWindowLayoutManager* dock = DockedWindowLayoutManager::Get(viewport_); - const bool docked_area_visible = dock && !dock->docked_bounds().IsEmpty(); - return (window_overlaps_launcher || docked_area_visible) - ? wm::WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF - : wm::WORKSPACE_WINDOW_STATE_DEFAULT; -} - -void WorkspaceController::DoInitialAnimation() { - viewport_->Show(); - - ui::Layer* layer = viewport_->GetLayer(); - layer->SetOpacity(0.0f); - SetTransformForScaleAnimation(layer, LAYER_SCALE_ANIMATION_ABOVE); - - // In order for pause to work we need to stop animations. - layer->GetAnimator()->StopAnimating(); - - { - ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); - - settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); - layer->GetAnimator()->SchedulePauseForProperties( - base::TimeDelta::FromMilliseconds(kInitialPauseTimeMS), - ui::LayerAnimationElement::TRANSFORM | - ui::LayerAnimationElement::OPACITY | - ui::LayerAnimationElement::BRIGHTNESS | - ui::LayerAnimationElement::VISIBILITY); - settings.SetTweenType(gfx::Tween::EASE_OUT); - settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kInitialAnimationDurationMS)); - layer->SetTransform(gfx::Transform()); - layer->SetOpacity(1.0f); - } -} - -void WorkspaceController::SetMaximizeBackdropDelegate( - std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate) { - layout_manager_->SetMaximizeBackdropDelegate(std::move(delegate)); -} - -void WorkspaceController::OnWindowDestroying(aura::Window* window) { - DCHECK_EQ(WmWindow::Get(window), viewport_); - viewport_->aura_window()->RemoveObserver(this); - viewport_ = nullptr; - // Destroy |event_handler_| too as it depends upon |window|. - event_handler_.reset(); - layout_manager_ = nullptr; -} - -} // namespace ash
diff --git a/ash/wm/workspace_controller.h b/ash/wm/workspace_controller.h deleted file mode 100644 index 22bf5bb..0000000 --- a/ash/wm/workspace_controller.h +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef ASH_WM_WORKSPACE_CONTROLLER_H_ -#define ASH_WM_WORKSPACE_CONTROLLER_H_ - -#include <memory> - -#include "ash/ash_export.h" -#include "ash/wm/workspace/workspace_types.h" -#include "base/macros.h" -#include "ui/aura/window_observer.h" - -namespace ash { -class WmWindow; -class WorkspaceControllerTestHelper; -class WorkspaceEventHandler; -class WorkspaceLayoutManager; -class WorkspaceLayoutManagerBackdropDelegate; - -// WorkspaceController acts as a central place that ties together all the -// various workspace pieces. -class ASH_EXPORT WorkspaceController : public aura::WindowObserver { - public: - // Installs WorkspaceLayoutManager on |viewport|. - explicit WorkspaceController(WmWindow* viewport); - ~WorkspaceController() override; - - // Returns the current window state. - wm::WorkspaceWindowState GetWindowState() const; - - // Starts the animation that occurs on first login. - void DoInitialAnimation(); - - // Add a delegate which adds a backdrop behind the top window of the default - // workspace. - void SetMaximizeBackdropDelegate( - std::unique_ptr<WorkspaceLayoutManagerBackdropDelegate> delegate); - - WorkspaceLayoutManager* layout_manager() { return layout_manager_; } - - private: - friend class WorkspaceControllerTestHelper; - - // aura::WindowObserver: - void OnWindowDestroying(aura::Window* window) override; - - WmWindow* viewport_; - std::unique_ptr<WorkspaceEventHandler> event_handler_; - - // Owned by |viewport_|. - WorkspaceLayoutManager* layout_manager_; - - DISALLOW_COPY_AND_ASSIGN(WorkspaceController); -}; - -} // namespace ash - -#endif // ASH_WM_WORKSPACE_CONTROLLER_H_
diff --git a/ash/wm/workspace_controller_test_helper.cc b/ash/wm/workspace_controller_test_helper.cc index a0c704f8..5ecb0d0 100644 --- a/ash/wm/workspace_controller_test_helper.cc +++ b/ash/wm/workspace_controller_test_helper.cc
@@ -4,8 +4,8 @@ #include "ash/wm/workspace_controller_test_helper.h" -#include "ash/test/workspace_event_handler_test_helper.h" -#include "ash/wm/workspace_controller.h" +#include "ash/common/test/workspace_event_handler_test_helper.h" +#include "ash/common/wm/workspace_controller.h" #include "ui/aura/window.h" namespace ash {
diff --git a/ash/wm/workspace_controller_test_helper.h b/ash/wm/workspace_controller_test_helper.h index a5aeb44..f5d6e6a 100644 --- a/ash/wm/workspace_controller_test_helper.h +++ b/ash/wm/workspace_controller_test_helper.h
@@ -5,7 +5,7 @@ #ifndef ASH_WM_WORKSPACE_CONTROLLER_TEST_HELPER_H_ #define ASH_WM_WORKSPACE_CONTROLLER_TEST_HELPER_H_ -#include "ash/wm/workspace_controller.h" +#include "ash/common/wm/workspace_controller.h" #include "base/macros.h" namespace ash {
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc index 50c4c4c12..e51dedc49 100644 --- a/ash/wm/workspace_controller_unittest.cc +++ b/ash/wm/workspace_controller_unittest.cc
@@ -2,29 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/workspace_controller.h" +#include "ash/common/wm/workspace_controller.h" #include <map> #include "ash/common/session/session_controller.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/test/test_shelf_delegate.h" +#include "ash/common/wm/panels/panel_layout_manager.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" +#include "ash/common/wm/workspace/workspace_window_resizer.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/screen_util.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/status_area_widget.h" #include "ash/test/ash_test_base.h" #include "ash/test/shell_test_api.h" -#include "ash/test/test_shelf_delegate.h" -#include "ash/wm/panels/panel_layout_manager.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" -#include "ash/wm/workspace/workspace_window_resizer.h" #include "base/strings/string_number_conversions.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/test/test_window_delegate.h"
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc index 198fc23..23b1832 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -13,12 +13,12 @@ #include "ash/autoclick/autoclick_controller.h" #include "ash/autoclick/mus/public/interfaces/autoclick.mojom.h" #include "ash/common/ash_constants.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/high_contrast/high_contrast_controller.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/sticky_keys/sticky_keys_controller.h" #include "base/callback.h"
diff --git a/chrome/browser/chromeos/accessibility/chromevox_panel.cc b/chrome/browser/chromeos/accessibility/chromevox_panel.cc index 5a008416..abfc07aa 100644 --- a/chrome/browser/chromeos/accessibility/chromevox_panel.cc +++ b/chrome/browser/chromeos/accessibility/chromevox_panel.cc
@@ -3,11 +3,11 @@ // found in the LICENSE file. #include "ash/common/accessibility_types.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "base/macros.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc index fea2d160..8cc8410c 100644 --- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -4,12 +4,12 @@ #include <queue> -#include "ash/accelerators/accelerator_controller.h" -#include "ash/accelerators/accelerator_table.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_table.h" #include "ash/common/accessibility_types.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "base/command_line.h" #include "base/macros.h" #include "base/strings/pattern.h"
diff --git a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc index 73f19ee..986be19 100644 --- a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc +++ b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
@@ -4,11 +4,11 @@ #include <stddef.h> +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" #include "ash/sticky_keys/sticky_keys_controller.h" #include "ash/sticky_keys/sticky_keys_overlay.h" -#include "ash/system/tray/system_tray.h" #include "base/command_line.h" #include "base/macros.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
diff --git a/chrome/browser/chromeos/arc/arc_auth_notification.cc b/chrome/browser/chromeos/arc/arc_auth_notification.cc index 905a511..ced355f 100644 --- a/chrome/browser/chromeos/arc/arc_auth_notification.cc +++ b/chrome/browser/chromeos/arc/arc_auth_notification.cc
@@ -8,7 +8,7 @@ #include <string> #include <utility> -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc index 342d4ba..4e8a5eba 100644 --- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc +++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler.h" +#include "ash/common/shelf/shelf_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_delegate.h" #include "base/bind.h" #include "base/command_line.h" #include "base/logging.h"
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc index 5d8b8603..f82e67c 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -6,8 +6,8 @@ #include <utility> +#include "ash/common/shelf/shelf_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_delegate.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/command_line.h"
diff --git a/chrome/browser/chromeos/arc/arc_support_host.cc b/chrome/browser/chromeos/arc/arc_support_host.cc index 0d8bb148..5ce98ef2 100644 --- a/chrome/browser/chromeos/arc/arc_support_host.cc +++ b/chrome/browser/chromeos/arc/arc_support_host.cc
@@ -7,7 +7,7 @@ #include <string> #include <utility> -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/bind.h" #include "base/i18n/timezone.h" #include "base/json/json_reader.h"
diff --git a/chrome/browser/chromeos/background/ash_wallpaper_delegate.cc b/chrome/browser/chromeos/background/ash_wallpaper_delegate.cc index 765df3e..78010610 100644 --- a/chrome/browser/chromeos/background/ash_wallpaper_delegate.cc +++ b/chrome/browser/chromeos/background/ash_wallpaper_delegate.cc
@@ -5,8 +5,8 @@ #include "chrome/browser/chromeos/background/ash_wallpaper_delegate.h" #include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/window_animation_types.h" #include "ash/shell.h" -#include "ash/wm/window_animation_types.h" #include "ash/wm/window_animations.h" #include "base/command_line.h" #include "base/logging.h"
diff --git a/chrome/browser/chromeos/dbus/chrome_display_power_service_provider_delegate.cc b/chrome/browser/chromeos/dbus/chrome_display_power_service_provider_delegate.cc index cf01c24..5ab6c10c 100644 --- a/chrome/browser/chromeos/dbus/chrome_display_power_service_provider_delegate.cc +++ b/chrome/browser/chromeos/dbus/chrome_display_power_service_provider_delegate.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/dbus/chrome_display_power_service_provider_delegate.h" +#include "ash/common/wm/screen_dimmer.h" #include "ash/shell.h" -#include "ash/wm/screen_dimmer.h" #include "base/memory/ptr_util.h" #include "ui/base/user_activity/user_activity_detector.h" #include "ui/display/manager/chromeos/display_configurator.h"
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc index f28681f..d9b080d 100644 --- a/chrome/browser/chromeos/display/display_preferences_unittest.cc +++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/display/display_util.h" #include "ash/display/json_converter.h" @@ -18,7 +19,6 @@ #include "ash/display/window_tree_host_manager.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h"
diff --git a/chrome/browser/chromeos/events/event_rewriter.cc b/chrome/browser/chromeos/events/event_rewriter.cc index 62431c3..5a68721 100644 --- a/chrome/browser/chromeos/events/event_rewriter.cc +++ b/chrome/browser/chromeos/events/event_rewriter.cc
@@ -8,8 +8,8 @@ #include <vector> +#include "ash/common/wm/window_state.h" #include "ash/sticky_keys/sticky_keys_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/logging.h"
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc index d7a2ff2..da755cd 100644 --- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc +++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -6,11 +6,11 @@ #include <vector> +#include "ash/common/wm/window_state.h" #include "ash/shell.h" #include "ash/sticky_keys/sticky_keys_controller.h" #include "ash/sticky_keys/sticky_keys_overlay.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc index fbf1e9d..c9eac15 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -11,11 +11,11 @@ #include <utility> #include <vector> +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/shell.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/command_line.h"
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc index a7014fc..0d2eec4e 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -6,8 +6,8 @@ #include <memory> +#include "ash/common/wm/window_state.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc b/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc index 4801d507..4a23cbff 100644 --- a/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc +++ b/chrome/browser/chromeos/first_run/chromeos_first_run_browsertest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/system/tray/system_tray.h" #include "ash/first_run/first_run_helper.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "chrome/browser/chromeos/first_run/first_run.h" #include "chrome/browser/chromeos/first_run/first_run_controller.h" #include "chrome/browser/chromeos/first_run/step_names.h"
diff --git a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc index b69a6885..a7f3422 100644 --- a/chrome/browser/chromeos/first_run/drive_first_run_controller.cc +++ b/chrome/browser/chromeos/first_run/drive_first_run_controller.cc
@@ -7,8 +7,8 @@ #include <stdint.h> #include <utility> +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "base/callback.h" #include "base/location.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/first_run/steps/tray_step.cc b/chrome/browser/chromeos/first_run/steps/tray_step.cc index 53e59d9..e232d32 100644 --- a/chrome/browser/chromeos/first_run/steps/tray_step.cc +++ b/chrome/browser/chromeos/first_run/steps/tray_step.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/chromeos/first_run/steps/tray_step.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_shell.h" #include "ash/first_run/first_run_helper.h" -#include "ash/shelf/wm_shelf.h" #include "base/i18n/rtl.h" #include "chrome/browser/chromeos/first_run/step_names.h" #include "chrome/browser/ui/webui/chromeos/first_run/first_run_actor.h"
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.cc b/chrome/browser/chromeos/hats/hats_notification_controller.cc index 5f38250..2fb3b74 100644 --- a/chrome/browser/chromeos/hats/hats_notification_controller.cc +++ b/chrome/browser/chromeos/hats/hats_notification_controller.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/hats/hats_notification_controller.h" +#include "ash/common/system/system_notifier.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc index 198e31b..9e6b0fc 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -8,13 +8,13 @@ #include <vector> #include "ash/common/wallpaper/wallpaper_controller.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" #include "ash/wm/lock_state_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/bind.h" #include "base/command_line.h" #include "base/lazy_instance.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc index 193c616..cb42e44b 100644 --- a/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc +++ b/chrome/browser/chromeos/login/lock/screen_locker_browsertest.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "ash/wm/window_state.h" +#include "ash/common/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc index 43360baa..659e0f4 100644 --- a/chrome/browser/chromeos/login/lock/webui_screen_locker.cc +++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.cc
@@ -6,7 +6,7 @@ #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/power/power_event_observer.h" +#include "ash/system/chromeos/power/power_event_observer.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/metrics/histogram_macros.h"
diff --git a/chrome/browser/chromeos/login/lock/webui_screen_locker.h b/chrome/browser/chromeos/login/lock/webui_screen_locker.h index 2e7bfdf..7f5f64d 100644 --- a/chrome/browser/chromeos/login/lock/webui_screen_locker.h +++ b/chrome/browser/chromeos/login/lock/webui_screen_locker.h
@@ -11,7 +11,7 @@ #include <string> #include "ash/common/shell_observer.h" -#include "ash/wm/lock_state_observer.h" +#include "ash/common/wm/lock_state_observer.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h"
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc index ab912aa..8444d612 100644 --- a/chrome/browser/chromeos/login/login_browsertest.cc +++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -4,10 +4,10 @@ #include <string> +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_window.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "base/command_line.h" #include "base/location.h" #include "base/single_thread_task_runner.h"
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc index ba4730c..b7f5181 100644 --- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc +++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.h" +#include "ash/common/system/system_notifier.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc index dd5e660..6fa45d35 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc
@@ -4,8 +4,8 @@ #include <string> -#include "ash/system/status_area_widget.h" -#include "ash/system/web_notification/web_notification_tray.h" +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/web_notification/web_notification_tray.h" #include "ash/test/status_area_widget_test_helper.h" #include "base/compiler_specific.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc index b89722b..763dc93 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -7,12 +7,12 @@ #include <utility> #include <vector> +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wallpaper/wallpaper_controller.h" #include "ash/common/wallpaper/wallpaper_delegate.h" #include "ash/common/wm_shell.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "base/bind.h" #include "base/command_line.h" #include "base/location.h"
diff --git a/chrome/browser/chromeos/login/ui/user_adding_screen.cc b/chrome/browser/chromeos/login/ui/user_adding_screen.cc index ca94976..92897ba8 100644 --- a/chrome/browser/chromeos/login/ui/user_adding_screen.cc +++ b/chrome/browser/chromeos/login/ui/user_adding_screen.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "base/bind.h" #include "base/memory/singleton.h" #include "base/observer_list.h"
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc index ecee0155..1c69151 100644 --- a/chrome/browser/chromeos/login/ui/webui_login_view.cc +++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -5,9 +5,9 @@ #include "chrome/browser/chromeos/login/ui/webui_login_view.h" #include "ash/common/focus_cycler.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" #include "base/bind.h" #include "base/callback.h" #include "base/i18n/rtl.h"
diff --git a/chrome/browser/chromeos/net/DEPS b/chrome/browser/chromeos/net/DEPS index 1776e3d..3da1b0c0 100644 --- a/chrome/browser/chromeos/net/DEPS +++ b/chrome/browser/chromeos/net/DEPS
@@ -8,12 +8,12 @@ specific_include_rules = { # TODO(jamescook): Eliminate these. "network_portal_notification_controller\.cc": [ - "+ash/system/system_notifier.h", - "+ash/system/tray/system_tray_notifier.h", + "+ash/common/system/system_notifier.h", + "+ash/common/system/tray/system_tray_notifier.h", "+ash/common/wm_shell.h", ], "network_state_notifier\.cc": [ - "+ash/system/system_notifier.h", + "+ash/common/system/system_notifier.h", "+ash/resources/grit/ash_resources.h", ], }
diff --git a/chrome/browser/chromeos/net/network_portal_notification_controller.cc b/chrome/browser/chromeos/net/network_portal_notification_controller.cc index ebf12e9..a25aaa2 100644 --- a/chrome/browser/chromeos/net/network_portal_notification_controller.cc +++ b/chrome/browser/chromeos/net/network_portal_notification_controller.cc
@@ -9,9 +9,9 @@ #include <memory> #include <vector> +#include "ash/common/system/system_notifier.h" +#include "ash/common/system/tray/system_tray_notifier.h" #include "ash/common/wm_shell.h" -#include "ash/system/system_notifier.h" -#include "ash/system/tray/system_tray_notifier.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/net/network_state_notifier.cc b/chrome/browser/chromeos/net/network_state_notifier.cc index ce2fc793..5d54ad0 100644 --- a/chrome/browser/chromeos/net/network_state_notifier.cc +++ b/chrome/browser/chromeos/net/network_state_notifier.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/net/network_state_notifier.h" +#include "ash/common/system/system_notifier.h" #include "ash/resources/grit/ash_resources.h" -#include "ash/system/system_notifier.h" #include "base/bind.h" #include "base/location.h" #include "base/strings/string16.h"
diff --git a/chrome/browser/chromeos/note_taking_helper.cc b/chrome/browser/chromeos/note_taking_helper.cc index 191fb45..159af5e 100644 --- a/chrome/browser/chromeos/note_taking_helper.cc +++ b/chrome/browser/chromeos/note_taking_helper.cc
@@ -8,7 +8,7 @@ #include <utility> #include "apps/launcher.h" -#include "ash/system/palette/palette_utils.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h"
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index 3a43b35..1d48467f 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -13,9 +13,9 @@ #include <utility> #include <vector> +#include "ash/common/system/chromeos/session/logout_confirmation_controller.h" +#include "ash/common/system/chromeos/session/logout_confirmation_dialog.h" #include "ash/common/wm_shell.h" -#include "ash/system/session/logout_confirmation_controller.h" -#include "ash/system/session/logout_confirmation_dialog.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h"
diff --git a/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc b/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc index 4f778be..dbeb6870 100644 --- a/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_system_use_24hour_clock_browsertest.cc
@@ -3,13 +3,13 @@ // found in the LICENSE file. #include "ash/common/login_status.h" +#include "ash/common/system/date/date_default_view.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/date/system_info_default_view.h" +#include "ash/common/system/date/tray_system_info.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/date/date_default_view.h" -#include "ash/system/date/date_view.h" -#include "ash/system/date/system_info_default_view.h" -#include "ash/system/date/tray_system_info.h" -#include "ash/system/tray/system_tray.h" #include "base/command_line.h" #include "base/location.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc index 6ea96f65..924ed4a 100644 --- a/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc +++ b/chrome/browser/chromeos/policy/force_maximize_on_first_run_chromeos_browsertest.cc
@@ -4,8 +4,8 @@ #include <string> +#include "ash/common/wm/window_positioner.h" #include "ash/shell.h" -#include "ash/wm/window_positioner.h" #include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/values.h"
diff --git a/chrome/browser/chromeos/power/login_lock_state_notifier.cc b/chrome/browser/chromeos/power/login_lock_state_notifier.cc index f0e79cf..1be0f74b 100644 --- a/chrome/browser/chromeos/power/login_lock_state_notifier.cc +++ b/chrome/browser/chromeos/power/login_lock_state_notifier.cc
@@ -5,9 +5,9 @@ #include "chrome/browser/chromeos/power/login_lock_state_notifier.h" #include "ash/common/login_status.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "base/logging.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/lock/screen_locker.h"
diff --git a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc index 843ad2a..6682213 100644 --- a/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc +++ b/chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.cc
@@ -5,8 +5,8 @@ #include "chrome/browser/chromeos/profiles/avatar_menu_actions_chromeos.h" #include "ash/common/multi_profile_uma.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/chromeos/profiles/multiprofiles_session_aborted_dialog.cc b/chrome/browser/chromeos/profiles/multiprofiles_session_aborted_dialog.cc index 098c45a..c9a5ddf 100644 --- a/chrome/browser/chromeos/profiles/multiprofiles_session_aborted_dialog.cc +++ b/chrome/browser/chromeos/profiles/multiprofiles_session_aborted_dialog.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/profiles/multiprofiles_session_aborted_dialog.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/root_window_controller.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/chromeos/shutdown_policy_browsertest.cc b/chrome/browser/chromeos/shutdown_policy_browsertest.cc index 75eb4ec..35d9cd7 100644 --- a/chrome/browser/chromeos/shutdown_policy_browsertest.cc +++ b/chrome/browser/chromeos/shutdown_policy_browsertest.cc
@@ -6,13 +6,13 @@ #include <string> #include "ash/common/login_status.h" +#include "ash/common/system/date/date_default_view.h" +#include "ash/common/system/date/tray_date.h" +#include "ash/common/system/tiles/tiles_default_view.h" +#include "ash/common/system/tiles/tray_tiles.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/date/date_default_view.h" -#include "ash/system/date/tray_date.h" -#include "ash/system/tiles/tiles_default_view.h" -#include "ash/system/tiles/tray_tiles.h" -#include "ash/system/tray/system_tray.h" #include "base/command_line.h" #include "base/location.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/status/data_promo_notification.cc b/chrome/browser/chromeos/status/data_promo_notification.cc index b4c139ad..633b8c3 100644 --- a/chrome/browser/chromeos/status/data_promo_notification.cc +++ b/chrome/browser/chromeos/status/data_promo_notification.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/status/data_promo_notification.h" +#include "ash/common/system/system_notifier.h" #include "ash/resources/grit/ash_resources.h" -#include "ash/system/system_notifier.h" #include "base/command_line.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc index ef51c2f..f2c59afd 100644 --- a/chrome/browser/chromeos/status/network_menu.cc +++ b/chrome/browser/chromeos/status/network_menu.cc
@@ -8,8 +8,8 @@ #include <algorithm> +#include "ash/common/system/chromeos/network/network_icon.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_icon.h" #include "base/bind.h" #include "base/logging.h" #include "base/macros.h"
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc index 580144f..9deeea1 100644 --- a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc +++ b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
@@ -4,12 +4,12 @@ #include "ash/common/accessibility_types.h" #include "ash/common/login_status.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray_accessibility.h" +#include "ash/common/test/test_session_state_delegate.h" #include "ash/magnifier/magnification_controller.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray_accessibility.h" #include "ash/test/shell_test_api.h" -#include "ash/test/test_session_state_delegate.h" #include "base/callback.h" #include "base/command_line.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/chromeos/ui/focus_ring_controller.cc b/chrome/browser/chromeos/ui/focus_ring_controller.cc index 6251afbb..c80e761 100644 --- a/chrome/browser/chromeos/ui/focus_ring_controller.cc +++ b/chrome/browser/chromeos/ui/focus_ring_controller.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/chromeos/ui/focus_ring_controller.h" -#include "ash/system/tray/actionable_view.h" -#include "ash/system/tray/tray_background_view.h" -#include "ash/system/tray/tray_popup_header_button.h" +#include "ash/common/system/tray/actionable_view.h" +#include "ash/common/system/tray/tray_background_view.h" +#include "ash/common/system/tray/tray_popup_header_button.h" #include "ash/wm/window_util.h" #include "chrome/browser/chromeos/ui/focus_ring_layer.h" #include "ui/aura/window.h"
diff --git a/chrome/browser/chromeos/ui/low_disk_notification.cc b/chrome/browser/chromeos/ui/low_disk_notification.cc index ffe662d..2da7089 100644 --- a/chrome/browser/chromeos/ui/low_disk_notification.cc +++ b/chrome/browser/chromeos/ui/low_disk_notification.cc
@@ -6,7 +6,7 @@ #include <stdint.h> -#include "ash/system/system_notifier.h" +#include "ash/common/system/system_notifier.h" #include "base/bind.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc b/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc index ede233a..f3d3c09 100644 --- a/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc +++ b/chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/chromeos/ui/screen_capture_notification_ui_chromeos.h" +#include "ash/common/system/tray/system_tray_notifier.h" #include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_notifier.h" namespace chromeos {
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc index c4fa962b6..b498453 100644 --- a/chrome/browser/extensions/api/automation/automation_apitest.cc +++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -33,7 +33,7 @@ #include "ui/accessibility/tree_generator.h" #if defined(OS_CHROMEOS) -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/wm_shell.h" #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" #endif
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc index d16a80cc..840f60d3 100644 --- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc +++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -53,7 +53,7 @@ #include "ui/gfx/range/range.h" #if defined(OS_CHROMEOS) -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h" #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h" #include "components/user_manager/user.h"
diff --git a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc index dc9b3ded..61aac818 100644 --- a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc +++ b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
@@ -30,7 +30,7 @@ #include "ui/base/webui/web_ui_util.h" #if defined(OS_CHROMEOS) -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #endif namespace extensions {
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc index d1a8dbbe..7a73d7867 100644 --- a/chrome/browser/extensions/bookmark_app_helper.cc +++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -76,8 +76,8 @@ #endif // defined(OS_WIN) #if defined(USE_ASH) +#include "ash/common/shelf/shelf_delegate.h" // nogncheck #include "ash/common/wm_shell.h" // nogncheck -#include "ash/shelf/shelf_delegate.h" // nogncheck #endif namespace {
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc index c5787c3..2dabbd35 100644 --- a/chrome/browser/extensions/component_loader.cc +++ b/chrome/browser/extensions/component_loader.cc
@@ -46,7 +46,7 @@ #include "ui/base/resource/resource_bundle.h" #if defined(OS_CHROMEOS) -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "chromeos/chromeos_switches.h" #include "components/chrome_apps/grit/chrome_apps_resources.h" #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc index 3c797009..f744840 100644 --- a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc +++ b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
@@ -6,11 +6,11 @@ #include <stdint.h> +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/display/screen_orientation_controller_chromeos.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/command_line.h" #include "base/macros.h" #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/extensions/global_shortcut_listener_chromeos.cc b/chrome/browser/extensions/global_shortcut_listener_chromeos.cc index fec16ba9..900dccd0e 100644 --- a/chrome/browser/extensions/global_shortcut_listener_chromeos.cc +++ b/chrome/browser/extensions/global_shortcut_listener_chromeos.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/extensions/global_shortcut_listener_chromeos.h" -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/wm_shell.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/notifications/fullscreen_notification_blocker.cc b/chrome/browser/notifications/fullscreen_notification_blocker.cc index a45e4ea9..feb4122 100644 --- a/chrome/browser/notifications/fullscreen_notification_blocker.cc +++ b/chrome/browser/notifications/fullscreen_notification_blocker.cc
@@ -13,10 +13,10 @@ #include "ui/message_center/notifier_settings.h" #if defined(USE_ASH) +#include "ash/common/system/system_notifier.h" +#include "ash/common/wm/window_state.h" #include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/system/system_notifier.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc index 86de30c..6b74bf0 100644 --- a/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc +++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/notifications/login_state_notification_blocker_chromeos.h" +#include "ash/common/system/system_notifier.h" #include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" -#include "ash/system/system_notifier.h" #include "ash/wm/window_properties.h" #include "chrome/browser/chrome_notification_types.h" #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc index 0fa930da..00cb63dbb 100644 --- a/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc +++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/system/system_notifier.h" #include "ash/shell.h" -#include "ash/system/system_notifier.h" #include "base/command_line.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc b/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc index 3b0d385..e28ed29 100644 --- a/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc +++ b/chrome/browser/notifications/login_state_notification_blocker_chromeos_unittest.cc
@@ -6,8 +6,8 @@ #include <memory> +#include "ash/common/system/system_notifier.h" #include "ash/shell.h" -#include "ash/system/system_notifier.h" #include "ash/test/ash_test_base.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc index 998f0e52..4902811 100644 --- a/chrome/browser/notifications/message_center_notification_manager.cc +++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -34,8 +34,8 @@ #endif #if defined(USE_ASH) +#include "ash/common/system/web_notification/web_notification_tray.h" #include "ash/shell.h" -#include "ash/system/web_notification/web_notification_tray.h" #endif using message_center::NotifierId;
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc index d7c7133..4326ff8 100644 --- a/chrome/browser/notifications/message_center_settings_controller_unittest.cc +++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -27,7 +27,7 @@ #include "ui/message_center/notifier_settings.h" #if defined(OS_CHROMEOS) -#include "ash/system/system_notifier.h" +#include "ash/common/system/system_notifier.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" #endif
diff --git a/chrome/browser/notifications/system_component_notifier_source_chromeos.cc b/chrome/browser/notifications/system_component_notifier_source_chromeos.cc index 9017d5f6..66a82e92 100644 --- a/chrome/browser/notifications/system_component_notifier_source_chromeos.cc +++ b/chrome/browser/notifications/system_component_notifier_source_chromeos.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/notifications/system_component_notifier_source_chromeos.h" -#include "ash/system/system_notifier.h" +#include "ash/common/system/system_notifier.h" #include "chrome/browser/notifications/notifier_state_tracker.h" #include "chrome/browser/notifications/notifier_state_tracker_factory.h" #include "chrome/grit/theme_resources.h"
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index a3b281c..cf6f84c3 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc
@@ -195,8 +195,8 @@ #include "url/origin.h" #if defined(OS_CHROMEOS) -#include "ash/accelerators/accelerator_controller.h" -#include "ash/accelerators/accelerator_table.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_table.h" #include "ash/common/accessibility_types.h" #include "ash/common/wm_shell.h" #include "ash/shell.h"
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc index 0a8b760..b632fab8 100644 --- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc +++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
@@ -15,7 +15,7 @@ #include "ui/base/l10n/l10n_util.h" #if defined(OS_CHROMEOS) -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #endif using proximity_auth::ScreenlockState;
diff --git a/chrome/browser/signin/signin_error_notifier_ash.cc b/chrome/browser/signin/signin_error_notifier_ash.cc index a60b0333..89c2a652 100644 --- a/chrome/browser/signin/signin_error_notifier_ash.cc +++ b/chrome/browser/signin/signin_error_notifier_ash.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/signin/signin_error_notifier_ash.h" -#include "ash/system/system_notifier.h" +#include "ash/common/system/system_notifier.h" #include "base/logging.h" #include "base/macros.h" #include "base/strings/string16.h"
diff --git a/chrome/browser/sync/sync_error_notifier_ash.cc b/chrome/browser/sync/sync_error_notifier_ash.cc index 743c048e..2a679129 100644 --- a/chrome/browser/sync/sync_error_notifier_ash.cc +++ b/chrome/browser/sync/sync_error_notifier_ash.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/sync/sync_error_notifier_ash.h" -#include "ash/system/system_notifier.h" +#include "ash/common/system/system_notifier.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.cc b/chrome/browser/ui/apps/chrome_app_delegate.cc index e66f6ae..5b90605 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.cc +++ b/chrome/browser/ui/apps/chrome_app_delegate.cc
@@ -41,7 +41,7 @@ #include "printing/features/features.h" #if defined(USE_ASH) -#include "ash/shelf/shelf_constants.h" // nogncheck +#include "ash/common/shelf/shelf_constants.h" // nogncheck #endif #if BUILDFLAG(ENABLE_PRINTING)
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc index 079059c..40d7547 100644 --- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc +++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_commands.h" +#include "ash/common/accelerators/accelerator_commands.h" #include "ash/accelerators/accelerator_commands_aura.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/accelerator_controller_browsertest.cc b/chrome/browser/ui/ash/accelerator_controller_browsertest.cc index 9c94c65d..f381e1b 100644 --- a/chrome/browser/ui/ash/accelerator_controller_browsertest.cc +++ b/chrome/browser/ui/ash/accelerator_controller_browsertest.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "build/build_config.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc index b13fc15..c83d8d0 100644 --- a/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc +++ b/chrome/browser/ui/ash/app_list/app_list_controller_ash.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/ui/ash/app_list/app_list_controller_ash.h" +#include "ash/common/shelf/shelf_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_delegate.h" #include "ash/shell.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
diff --git a/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc b/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc index 0e97237..a4386b1f 100644 --- a/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc +++ b/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
@@ -4,12 +4,12 @@ #include <memory> +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "base/run_loop.h" #include "chrome/test/base/in_process_browser_test.h" #include "ui/app_list/presenter/app_list.h"
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc index fe09e3ae..b29a791 100644 --- a/chrome/browser/ui/ash/ash_init.cc +++ b/chrome/browser/ui/ash/ash_init.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/ui/ash/ash_init.h" -#include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_controller_delegate_aura.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/accessibility_types.h" #include "ash/common/wm_shell.h" #include "ash/high_contrast/high_contrast_controller.h"
diff --git a/chrome/browser/ui/ash/ash_util.cc b/chrome/browser/ui/ash/ash_util.cc index 059b59e..591c9d55 100644 --- a/chrome/browser/ui/ash/ash_util.cc +++ b/chrome/browser/ui/ash/ash_util.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/ash_util.h" -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/common/mojo_interface_factory.h" #include "ash/common/wm_shell.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc index e3cad592..e977749 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber.cc
@@ -6,9 +6,9 @@ #include <stddef.h> +#include "ash/common/system/system_notifier.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/system_notifier.h" #include "base/base64.h" #include "base/bind.h" #include "base/callback.h"
diff --git a/chrome/browser/ui/ash/chrome_screenshot_grabber_unittest.cc b/chrome/browser/ui/ash/chrome_screenshot_grabber_unittest.cc index a152f96..465c770 100644 --- a/chrome/browser/ui/ash/chrome_screenshot_grabber_unittest.cc +++ b/chrome/browser/ui/ash/chrome_screenshot_grabber_unittest.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/chrome_screenshot_grabber.h" -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/bind.h"
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc index 7f5914c9cc..42db34a 100644 --- a/chrome/browser/ui/ash/chrome_shell_delegate.cc +++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -13,12 +13,12 @@ #include "ash/common/accessibility_delegate.h" #include "ash/common/accessibility_types.h" #include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/content/gpu_support_impl.h" #include "ash/shell.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc index 8b0fe5c..ffe1363 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/shelf/shelf_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_delegate.h" #include "ash/wm/window_util.h" #include "base/macros.h" #include "base/run_loop.h"
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc index 586c3a95..f20d0993 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -5,15 +5,15 @@ #include <string> +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/display/screen_orientation_controller_chromeos.h" #include "ash/shared/app_types.h" -#include "ash/shelf/shelf_delegate.h" #include "ash/shell.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/bind.h"
diff --git a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc index 36fdb8a..294f9df6 100644 --- a/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/arc_launcher_context_menu.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/launcher/arc_launcher_context_menu.h" -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc index cd6e7b79..dc3ddfd 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -7,12 +7,12 @@ #include <limits> #include <vector> +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_model.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shelf_application_menu_item.h" #include "ash/resources/grit/ash_resources.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_model.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc index 8859cd4..4c7e7c2b 100644 --- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc +++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h" -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_types.h" #include "ash/shell.h" #include "ash/wm/window_util.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h index a206459..fb29db9 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -9,10 +9,10 @@ #include <string> #include <vector> +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_item_types.h" #include "ash/public/cpp/shelf_application_menu_item.h" #include "ash/public/interfaces/shelf.mojom.h" -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_item_types.h" #include "chrome/browser/ui/app_icon_loader.h" #include "chrome/browser/ui/app_icon_loader_delegate.h" #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc index a3e2171..fa29d04 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
@@ -9,15 +9,15 @@ #include <vector> #include "ash/common/multi_profile_uma.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/resources/grit/ash_resources.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h index 9ad76028..037a222 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
@@ -8,10 +8,10 @@ #include <list> #include <memory> +#include "ash/common/shelf/shelf_delegate.h" +#include "ash/common/shelf/shelf_model_observer.h" #include "ash/display/window_tree_host_manager.h" #include "ash/public/cpp/shelf_types.h" -#include "ash/shelf/shelf_delegate.h" -#include "ash/shelf/shelf_model_observer.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc index bae868fc0..7a473e0 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -6,20 +6,20 @@ #include <stddef.h> +#include "ash/common/shelf/app_list_button.h" +#include "ash/common/shelf/shelf_button.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/window_properties.h" -#include "ash/shelf/app_list_button.h" -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/shelf_view_test_api.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc index 2e35e27..4b5b8ad5 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -14,18 +14,18 @@ #include <utility> #include <vector> +#include "ash/common/shelf/shelf_application_menu_model.h" +#include "ash/common/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_controller.h" +#include "ash/common/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/shelf_model_observer.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/display/screen_orientation_controller_chromeos.h" -#include "ash/shelf/shelf_application_menu_model.h" -#include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_item_types.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_model_observer.h" #include "ash/shell.h" #include "ash/test/ash_test_helper.h" #include "ash/test/test_shell_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/window_util.h" #include "base/command_line.h" #include "base/compiler_specific.h"
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc index 61e577bb..dd059dc 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h" +#include "ash/common/shelf/shelf_delegate.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" -#include "ash/shelf/shelf_delegate.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" #include "base/stl_util.h"
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc index 25b6ace3..e885823a 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.h" -#include "ash/wm/window_state.h" +#include "ash/common/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc index ec28364..7dc7522 100644 --- a/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/extension_launcher_context_menu.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/ui/ash/launcher/extension_launcher_context_menu.h" +#include "ash/common/shelf/shelf_item_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/shelf_item_delegate.h" #include "base/bind.h" #include "chrome/browser/extensions/context_menu_matcher.h" #include "chrome/browser/extensions/extension_util.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc index 42c6bef..30d381525 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -6,11 +6,11 @@ #include <string> +#include "ash/common/shelf/shelf_model.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wallpaper/wallpaper_delegate.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/wm_shelf.h" #include "ash/strings/grit/ash_strings.h" #include "build/build_config.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.h b/chrome/browser/ui/ash/launcher/launcher_context_menu.h index 6ae3e77..e913717d 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu.h +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.h
@@ -5,8 +5,8 @@ #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_CONTEXT_MENU_H_ #define CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_CONTEXT_MENU_H_ -#include "ash/shelf/shelf_alignment_menu.h" -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_alignment_menu.h" +#include "ash/common/shelf/shelf_item_types.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "ui/base/models/simple_menu_model.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc index f9d27c9..7868df6 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -6,10 +6,10 @@ #include <memory> +#include "ash/common/shelf/shelf_item_types.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_item_types.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc b/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc index 974fa1b..8894ff3 100644 --- a/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc +++ b/chrome/browser/ui/ash/launcher/launcher_favicon_loader.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h" -#include "ash/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_constants.h" #include "base/bind.h" #include "base/logging.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc b/chrome/browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc index a4f999a7..2606e66d 100644 --- a/chrome/browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc
@@ -8,7 +8,7 @@ #include <memory> -#include "ash/shelf/shelf_constants.h" +#include "ash/common/shelf/shelf_constants.h" #include "base/macros.h" #include "base/strings/stringprintf.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_item_controller.h b/chrome/browser/ui/ash/launcher/launcher_item_controller.h index 1ce11f7b..5c1c538 100644 --- a/chrome/browser/ui/ash/launcher/launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
@@ -7,8 +7,8 @@ #include <string> -#include "ash/shelf/shelf_item_delegate.h" -#include "ash/shelf/shelf_item_types.h" +#include "ash/common/shelf/shelf_item_delegate.h" +#include "ash/common/shelf/shelf_item_types.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "ui/events/event.h"
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc index 4dd7f76..30e3df69 100644 --- a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc +++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h" +#include "ash/common/shelf/shelf_item_types.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/window_properties.h" -#include "ash/shelf/shelf_item_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
diff --git a/chrome/browser/ui/ash/launcher/settings_window_observer.cc b/chrome/browser/ui/ash/launcher/settings_window_observer.cc index 1ae904e..f07ebd2 100644 --- a/chrome/browser/ui/ash/launcher/settings_window_observer.cc +++ b/chrome/browser/ui/ash/launcher/settings_window_observer.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ui/ash/launcher/settings_window_observer.h" +#include "ash/common/shelf/shelf_item_types.h" #include "ash/public/cpp/window_properties.h" #include "ash/resources/grit/ash_resources.h" -#include "ash/shelf/shelf_item_types.h" #include "base/feature_list.h" #include "base/memory/ptr_util.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc index 7c048fc0..fc0b03f2 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h" -#include "ash/system/system_notifier.h" +#include "ash/common/system/system_notifier.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" #include "components/signin/core/account_id/account_id.h" #include "ui/message_center/message_center.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc index 0c1ec15..9ba0898a 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/system/system_notifier.h" #include "ash/common/wm_shell.h" -#include "ash/system/system_notifier.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_shell_delegate.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc index eae23e6..79ec452 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -6,12 +6,12 @@ #include "ash/common/media_controller.h" #include "ash/common/multi_profile_uma.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/auto_reset.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc index 542ac6b..103ea8b 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -4,24 +4,24 @@ #include <stddef.h> +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" +#include "ash/common/wm/maximize_mode/maximize_mode_window_manager.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/content/shell_content_state.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_environment_content.h" #include "ash/test/ash_test_helper.h" #include "ash/test/test_shell_delegate.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" -#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" -#include "ash/wm/wm_event.h" #include "base/compiler_specific.h" #include "base/logging.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc index a11acf62..1d5ba25 100644 --- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc +++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
@@ -4,17 +4,17 @@ #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h" +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/shelf_widget.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wallpaper/wallpaper_delegate.h" +#include "ash/common/wm/mru_window_tracker.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_widget.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" -#include "ash/wm/mru_window_tracker.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_util.cc b/chrome/browser/ui/ash/multi_user/user_switch_util.cc index 81d62d8..e00dbdcfa 100644 --- a/chrome/browser/ui/ash/multi_user/user_switch_util.cc +++ b/chrome/browser/ui/ash/multi_user/user_switch_util.cc
@@ -4,12 +4,12 @@ #include "chrome/browser/ui/ash/multi_user/user_switch_util.h" +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/screen_security/screen_tray_item.h" -#include "ash/system/tray/system_tray.h" -#include "ash/wm/overview/window_selector_controller.h" #include "chrome/browser/ui/simple_message_box.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_util_unittest.cc b/chrome/browser/ui/ash/multi_user/user_switch_util_unittest.cc index e7e825b..6182167c 100644 --- a/chrome/browser/ui/ash/multi_user/user_switch_util_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/user_switch_util_unittest.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/system/chromeos/screen_security/screen_tray_item.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/wm/overview/window_selector_controller.h" #include "ash/common/wm_shell.h" -#include "ash/system/screen_security/screen_tray_item.h" -#include "ash/system/tray/system_tray.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/overview/window_selector_controller.h" #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/ui/ash/multi_user/user_switch_util.h"
diff --git a/chrome/browser/ui/ash/networking_config_delegate_chromeos.h b/chrome/browser/ui/ash/networking_config_delegate_chromeos.h index 09e959c..9b388b31 100644 --- a/chrome/browser/ui/ash/networking_config_delegate_chromeos.h +++ b/chrome/browser/ui/ash/networking_config_delegate_chromeos.h
@@ -7,7 +7,7 @@ #include <string> -#include "ash/system/networking_config_delegate.h" +#include "ash/common/system/networking_config_delegate.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "content/public/browser/browser_context.h"
diff --git a/chrome/browser/ui/ash/networking_config_delegate_chromeos_browsertest.cc b/chrome/browser/ui/ash/networking_config_delegate_chromeos_browsertest.cc index e28a3a73..cfd60cc 100644 --- a/chrome/browser/ui/ash/networking_config_delegate_chromeos_browsertest.cc +++ b/chrome/browser/ui/ash/networking_config_delegate_chromeos_browsertest.cc
@@ -5,12 +5,12 @@ #include "chrome/browser/ui/ash/networking_config_delegate_chromeos.h" #include "ash/common/login_status.h" +#include "ash/common/system/chromeos/network/network_detailed_view.h" +#include "ash/common/system/chromeos/network/tray_network.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" #include "ash/strings/grit/ash_strings.h" -#include "ash/system/network/network_detailed_view.h" -#include "ash/system/network/tray_network.h" -#include "ash/system/tray/system_tray.h" #include "base/macros.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/ash/palette_delegate_chromeos.cc b/chrome/browser/ui/ash/palette_delegate_chromeos.cc index 4cdfb24..99443ac 100644 --- a/chrome/browser/ui/ash/palette_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/palette_delegate_chromeos.cc
@@ -5,9 +5,9 @@ #include "chrome/browser/ui/ash/palette_delegate_chromeos.h" #include "ash/accelerators/accelerator_controller_delegate_aura.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" #include "ash/screenshot_delegate.h" #include "ash/shell.h" -#include "ash/system/palette/palette_utils.h" #include "ash/utility/screenshot_controller.h" #include "base/memory/ptr_util.h" #include "chrome/browser/chrome_notification_types.h"
diff --git a/chrome/browser/ui/ash/shelf_browsertest.cc b/chrome/browser/ui/ash/shelf_browsertest.cc index 1c12f73..f39d951 100644 --- a/chrome/browser/ui/ash/shelf_browsertest.cc +++ b/chrome/browser/ui/ash/shelf_browsertest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/shelf/shelf_layout_manager.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_window.h" -#include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/wm_shelf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h"
diff --git a/chrome/browser/ui/ash/system_tray_client_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_browsertest.cc index 0db45993..1789e3a 100644 --- a/chrome/browser/ui/ash/system_tray_client_browsertest.cc +++ b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
@@ -4,10 +4,10 @@ #include "chrome/browser/ui/ash/system_tray_client.h" +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/update/tray_update.h" #include "ash/common/wm_shell.h" #include "ash/root_window_controller.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/update/tray_update.h" #include "chrome/browser/upgrade_detector.h" #include "chrome/test/base/in_process_browser_test.h" #include "content/public/test/test_utils.h"
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc index 8ece5852..722d71a8 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -15,16 +15,16 @@ #include "ash/common/login_status.h" #include "ash/common/shell_delegate.h" +#include "ash/common/system/chromeos/bluetooth/bluetooth_observer.h" +#include "ash/common/system/chromeos/power/power_status.h" +#include "ash/common/system/chromeos/session/logout_button_observer.h" +#include "ash/common/system/date/clock_observer.h" +#include "ash/common/system/ime/ime_observer.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/system/tray_accessibility.h" +#include "ash/common/system/user/user_observer.h" #include "ash/common/wm_shell.h" -#include "ash/system/bluetooth/bluetooth_observer.h" -#include "ash/system/date/clock_observer.h" -#include "ash/system/ime/ime_observer.h" -#include "ash/system/power/power_status.h" -#include "ash/system/rotation/tray_rotation_lock.h" -#include "ash/system/session/logout_button_observer.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/system/tray_accessibility.h" -#include "ash/system/user/user_observer.h" +#include "ash/system/chromeos/rotation/tray_rotation_lock.h" #include "base/bind_helpers.h" #include "base/callback.h" #include "base/logging.h"
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h index 8d4a5b98..db7841e 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -12,9 +12,9 @@ #include <vector> #include "ash/common/accessibility_types.h" -#include "ash/system/supervised/custodian_info_tray_observer.h" -#include "ash/system/tray/ime_info.h" -#include "ash/system/tray/system_tray_delegate.h" +#include "ash/common/system/chromeos/supervised/custodian_info_tray_observer.h" +#include "ash/common/system/tray/ime_info.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "base/callback_forward.h" #include "base/callback_list.h" #include "base/compiler_specific.h"
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos_browsertest_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos_browsertest_chromeos.cc index 239de59e..a64eb66 100644 --- a/chrome/browser/ui/ash/system_tray_delegate_chromeos_browsertest_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos_browsertest_chromeos.cc
@@ -6,13 +6,13 @@ #include <string> +#include "ash/common/system/date/date_default_view.h" +#include "ash/common/system/date/date_view.h" +#include "ash/common/system/date/system_info_default_view.h" +#include "ash/common/system/date/tray_date.h" +#include "ash/common/system/date/tray_system_info.h" +#include "ash/common/system/tray/system_tray.h" #include "ash/shell.h" -#include "ash/system/date/date_default_view.h" -#include "ash/system/date/date_view.h" -#include "ash/system/date/system_info_default_view.h" -#include "ash/system/date/tray_date.h" -#include "ash/system/date/tray_system_info.h" -#include "ash/system/tray/system_tray.h" #include "base/macros.h" #include "chrome/browser/chromeos/login/login_manager_test.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h"
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc index bc33b114..eb20ef7 100644 --- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc +++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -4,10 +4,10 @@ #include <vector> +#include "ash/common/system/tray/system_tray.h" +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray.h" -#include "ash/system/tray/system_tray_delegate.h" #include "ash/test/tray_cast_test_api.h" #include "base/macros.h" #include "chrome/browser/media/router/media_routes_observer.h"
diff --git a/chrome/browser/ui/ash/window_positioner_unittest.cc b/chrome/browser/ui/ash/window_positioner_unittest.cc index c758b6c..a71dd18 100644 --- a/chrome/browser/ui/ash/window_positioner_unittest.cc +++ b/chrome/browser/ui/ash/window_positioner_unittest.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/wm/window_positioner.h" +#include "ash/common/wm/window_positioner.h" #include <utility> +#include "ash/common/wm/window_resizer.h" #include "ash/common/wm_shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_resizer.h" #include "base/logging.h" #include "base/macros.h" #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc index 52b6cb7..1cd8dbb 100644 --- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc +++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -46,7 +46,7 @@ #endif #if defined(USE_ASH) -#include "ash/accelerators/accelerator_table.h" // nogncheck +#include "ash/common/accelerators/accelerator_table.h" // nogncheck #endif // defined(USE_ASH) namespace {
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc index b539183..43a54894 100644 --- a/chrome/browser/ui/views/accelerator_table.cc +++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -14,7 +14,7 @@ #include "ui/events/event_constants.h" #if defined(USE_ASH) -#include "ash/accelerators/accelerator_table.h" // nogncheck +#include "ash/common/accelerators/accelerator_table.h" // nogncheck #endif namespace {
diff --git a/chrome/browser/ui/views/accelerator_table_unittest.cc b/chrome/browser/ui/views/accelerator_table_unittest.cc index 31bf6e49..6b05bc2 100644 --- a/chrome/browser/ui/views/accelerator_table_unittest.cc +++ b/chrome/browser/ui/views/accelerator_table_unittest.cc
@@ -12,7 +12,7 @@ #include "ui/events/event_constants.h" #if defined(USE_ASH) -#include "ash/accelerators/accelerator_table.h" +#include "ash/common/accelerators/accelerator_table.h" #endif // USE_ASH namespace chrome {
diff --git a/chrome/browser/ui/views/accelerator_utils_aura.cc b/chrome/browser/ui/views/accelerator_utils_aura.cc index 8c6414c9..55093f8 100644 --- a/chrome/browser/ui/views/accelerator_utils_aura.cc +++ b/chrome/browser/ui/views/accelerator_utils_aura.cc
@@ -9,7 +9,7 @@ #include "ui/base/accelerators/accelerator.h" #if defined(USE_ASH) -#include "ash/accelerators/accelerator_table.h" // nogncheck +#include "ash/common/accelerators/accelerator_table.h" // nogncheck #endif // USE_ASH namespace chrome {
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc index ca1e73f3..2a1b343 100644 --- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc +++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
@@ -21,8 +21,8 @@ #include "ui/views/widget/widget.h" #if defined(USE_ASH) +#include "ash/common/shelf/shelf_delegate.h" // nogncheck #include "ash/common/wm_shell.h" // nogncheck -#include "ash/shelf/shelf_delegate.h" // nogncheck #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" // nogncheck #endif
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc index 78abdfe..8ba36e52 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -7,20 +7,20 @@ #include "apps/ui/views/app_window_frame_view.h" #include "ash/common/ash_constants.h" #include "ash/common/ash_switches.h" +#include "ash/common/frame/custom_frame_view_ash.h" +#include "ash/common/shelf/shelf_item_types.h" +#include "ash/common/wm/panels/panel_frame_view.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_delegate.h" +#include "ash/common/wm/window_state_observer.h" #include "ash/common/wm_window.h" -#include "ash/frame/custom_frame_view_ash.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/shared/app_types.h" #include "ash/shared/immersive_fullscreen_controller.h" -#include "ash/shelf/shelf_item_types.h" #include "ash/shell.h" -#include "ash/wm/panels/panel_frame_view.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/window_state_delegate.h" -#include "ash/wm/window_state_observer.h" #include "chrome/browser/chromeos/note_taking_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/ash_util.h"
diff --git a/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc b/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc index 1db6f37e..acf1470a 100644 --- a/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc +++ b/chrome/browser/ui/views/chrome_views_delegate_chromeos.cc
@@ -4,10 +4,10 @@ #include "chrome/browser/ui/views/chrome_views_delegate.h" -#include "ash/accelerators/accelerator_controller.h" +#include "ash/common/accelerators/accelerator_controller.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/bind.h" #include "base/message_loop/message_loop.h"
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc index 3d73ee2..d40bb822 100644 --- a/chrome/browser/ui/views/frame/browser_frame_ash.cc +++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc
@@ -5,11 +5,11 @@ #include "chrome/browser/ui/views/frame/browser_frame_ash.h" #include "ash/common/ash_switches.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/window_state_delegate.h" #include "ash/shell.h" #include "ash/wm/window_properties.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/window_state_delegate.h" #include "ash/wm/window_util.h" #include "base/macros.h" #include "build/build_config.h"
diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc index 3142cbd6..ba9f1f3 100644 --- a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc +++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
@@ -5,8 +5,8 @@ #include "chrome/browser/ui/views/frame/browser_header_painter_ash.h" #include "ash/common/ash_layout_constants.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/header_painter_util.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/header_painter_util.h" #include "ash/resources/vector_icons/vector_icons.h" #include "base/logging.h" // DCHECK #include "chrome/browser/themes/theme_properties.h"
diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.h b/chrome/browser/ui/views/frame/browser_header_painter_ash.h index 96fedaf0..f6e6c41 100644 --- a/chrome/browser/ui/views/frame/browser_header_painter_ash.h +++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/frame/header_painter.h" +#include "ash/common/frame/header_painter.h" #include "base/compiler_specific.h" // override #include "base/macros.h" #include "ui/gfx/animation/animation_delegate.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 708d0a2..8f383f9 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -7,12 +7,12 @@ #include <algorithm> #include "ash/common/ash_layout_constants.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/default_header_painter.h" +#include "ash/common/frame/frame_border_hit_test.h" +#include "ash/common/frame/header_painter_util.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/default_header_painter.h" -#include "ash/frame/frame_border_hit_test.h" -#include "ash/frame/header_painter_util.h" #include "base/feature_list.h" #include "build/build_config.h" #include "chrome/browser/profiles/profiles_state.h"
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index ec29999..931f739 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -5,12 +5,12 @@ #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h" #include "ash/common/ash_constants.h" +#include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h" +#include "ash/common/frame/header_painter.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" -#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" -#include "ash/frame/header_painter.h" #include "ash/shell.h" #include "ash/test/immersive_fullscreen_controller_test_api.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/command_line.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile_avatar_icon_util.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc index 59966b1..8e1cd9d 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -5,9 +5,9 @@ #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" #include "ash/common/material_design/material_design_controller.h" +#include "ash/common/wm/window_state.h" #include "ash/shared/immersive_revealed_lock.h" #include "ash/shell.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/macros.h" #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h index 6a6d51e7..b47321e86 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -7,9 +7,9 @@ #include <memory> +#include "ash/common/wm/window_state_observer.h" #include "ash/shared/immersive_fullscreen_controller.h" #include "ash/shared/immersive_fullscreen_controller_delegate.h" -#include "ash/wm/window_state_observer.h" #include "base/macros.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" #include "content/public/browser/notification_observer.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc index d9894e6..9f3f0759 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h" +#include "ash/common/shelf/shelf_layout_manager.h" #include "ash/public/cpp/shelf_types.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_layout_manager.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/test/immersive_fullscreen_controller_test_api.h"
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc b/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc index 0a59b0c..f1b5dad 100644 --- a/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc +++ b/chrome/browser/ui/views/message_center/web_notification_tray_browsertest.cc
@@ -8,9 +8,9 @@ #include <set> +#include "ash/common/system/status_area_widget.h" +#include "ash/common/system/tray/system_tray_item.h" #include "ash/root_window_controller.h" -#include "ash/system/status_area_widget.h" -#include "ash/system/tray/system_tray_item.h" #include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h"
diff --git a/chrome/browser/ui/views/status_bubble_views.cc b/chrome/browser/ui/views/status_bubble_views.cc index 63ae424..5aea784 100644 --- a/chrome/browser/ui/views/status_bubble_views.cc +++ b/chrome/browser/ui/views/status_bubble_views.cc
@@ -41,7 +41,7 @@ #include "url/gurl.h" #if defined(USE_ASH) -#include "ash/wm/window_state.h" // nogncheck +#include "ash/common/wm/window_state.h" // nogncheck #include "ash/wm/window_state_aura.h" // nogncheck #endif
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc index 734c9bc3..7e52331 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -41,10 +41,10 @@ #include "ui/views/widget/widget.h" #if defined(USE_ASH) -#include "ash/accelerators/accelerator_commands.h" // nogncheck +#include "ash/common/accelerators/accelerator_commands.h" // nogncheck +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" // nogncheck +#include "ash/common/wm/window_state.h" // nogncheck #include "ash/common/wm_shell.h" // nogncheck -#include "ash/wm/maximize_mode/maximize_mode_controller.h" // nogncheck -#include "ash/wm/window_state.h" // nogncheck #include "ash/wm/window_state_aura.h" // nogncheck #include "ui/wm/core/coordinate_conversion.h" // nogncheck #endif
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index 768e71b..244c71de 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -63,12 +63,12 @@ #if defined(USE_ASH) #include "ash/common/ash_switches.h" +#include "ash/common/wm/root_window_finder.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/shell.h" #include "ash/test/cursor_manager_test_api.h" #include "ash/test/immersive_fullscreen_controller_test_api.h" -#include "ash/wm/root_window_finder.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
diff --git a/chrome/browser/ui/views/tabs/window_finder_ash.cc b/chrome/browser/ui/views/tabs/window_finder_ash.cc index ab91890d..4b828121 100644 --- a/chrome/browser/ui/views/tabs/window_finder_ash.cc +++ b/chrome/browser/ui/views/tabs/window_finder_ash.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ui/views/tabs/window_finder.h" +#include "ash/common/wm/root_window_finder.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/root_window_finder.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h"
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc index 0e56187..b9a1be79 100644 --- a/chrome/browser/ui/views/task_manager_view.cc +++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -35,9 +35,9 @@ #if defined(USE_ASH) // Note: gn check complains here, despite the correct conditional //ash dep. +#include "ash/common/shelf/shelf_item_types.h" // nogncheck #include "ash/public/cpp/window_properties.h" // nogncheck #include "ash/resources/grit/ash_resources.h" // nogncheck -#include "ash/shelf/shelf_item_types.h" // nogncheck #include "ash/wm/window_util.h" // nogncheck #include "chrome/browser/ui/ash/ash_util.h" // nogncheck #include "ui/aura/client/aura_constants.h"
diff --git a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc index 0454650..b356b01c 100644 --- a/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc +++ b/chrome/browser/ui/webui/chromeos/emulator/device_emulator_message_handler.cc
@@ -7,8 +7,8 @@ #include <stdint.h> #include <utility> +#include "ash/common/system/tray/system_tray_delegate.h" #include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_delegate.h" #include "base/bind.h" #include "base/macros.h" #include "base/strings/string_number_conversions.h"
diff --git a/chrome/browser/ui/webui/chromeos/first_run/first_run_ui.cc b/chrome/browser/ui/webui/chromeos/first_run/first_run_ui.cc index 3e36a293..13cc57dd 100644 --- a/chrome/browser/ui/webui/chromeos/first_run/first_run_ui.cc +++ b/chrome/browser/ui/webui/chromeos/first_run/first_run_ui.cc
@@ -4,8 +4,8 @@ #include "chrome/browser/ui/webui/chromeos/first_run/first_run_ui.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_shell.h" -#include "ash/shelf/wm_shelf.h" #include "base/command_line.h" #include "base/memory/ptr_util.h" #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index 1936a6e..f516642 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -6,7 +6,7 @@ #include <algorithm> -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/file_util.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc index af75d9e..e93b4ddc 100644 --- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/message_loop/message_loop.h" #include "base/time/time.h" #include "chrome/browser/chromeos/login/screens/error_screen.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 20e6b917..d847e257 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/bind.h" #include "base/callback.h" #include "base/guid.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc b/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc index 1b75775..9b6bd696 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc +++ b/chrome/browser/ui/webui/chromeos/login/network_dropdown.cc
@@ -8,8 +8,8 @@ #include <string> #include <utility> -#include "ash/system/network/network_icon.h" -#include "ash/system/network/network_icon_animation.h" +#include "ash/common/system/chromeos/network/network_icon.h" +#include "ash/common/system/chromeos/network/network_icon_animation.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/string_util.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/network_dropdown.h b/chrome/browser/ui/webui/chromeos/login/network_dropdown.h index 3eaddd0..1ab6009 100644 --- a/chrome/browser/ui/webui/chromeos/login/network_dropdown.h +++ b/chrome/browser/ui/webui/chromeos/login/network_dropdown.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/system/network/network_icon_animation_observer.h" +#include "ash/common/system/chromeos/network/network_icon_animation_observer.h" #include "base/macros.h" #include "base/timer/timer.h" #include "chrome/browser/chromeos/status/network_menu.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc index d84a98b..84e4b4f 100644 --- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -8,7 +8,7 @@ #include <memory> -#include "ash/wm/screen_dimmer.h" +#include "ash/common/wm/screen_dimmer.h" #include "base/command_line.h" #include "base/logging.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 6ce4766..c03f474 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -9,9 +9,9 @@ #include <algorithm> #include <vector> +#include "ash/common/system/chromeos/devicetype_utils.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/shell.h" -#include "ash/system/devicetype_utils.h" #include "ash/wm/lock_state_controller.h" #include "base/bind.h" #include "base/i18n/number_formatting.h"
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc index 0413e591c..de91108 100644 --- a/chrome/browser/ui/webui/help/help_handler.cc +++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -8,7 +8,7 @@ #include <string> -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/base_switches.h" #include "base/bind.h" #include "base/bind_helpers.h"
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index e2f43eb..c711347 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -119,8 +119,8 @@ #if defined(OS_CHROMEOS) #include "ash/common/accessibility_types.h" // nogncheck +#include "ash/common/system/chromeos/devicetype_utils.h" // nogncheck #include "ash/shell.h" // nogncheck -#include "ash/system/devicetype_utils.h" // nogncheck #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/accessibility/accessibility_util.h" #include "chrome/browser/chromeos/arc/arc_util.h"
diff --git a/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc b/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc index 123796e5..2f9a5f3 100644 --- a/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/options_stylus_handler.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/webui/options/chromeos/options_stylus_handler.h" -#include "ash/system/palette/palette_utils.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" #include "base/values.h" #include "chrome/browser/profiles/profile.h" #include "chrome/grit/generated_resources.h"
diff --git a/chrome/browser/ui/webui/options/chromeos/power_handler.h b/chrome/browser/ui/webui/options/chromeos/power_handler.h index 843749b..b5045e6 100644 --- a/chrome/browser/ui/webui/options/chromeos/power_handler.h +++ b/chrome/browser/ui/webui/options/chromeos/power_handler.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS_CHROMEOS_POWER_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_OPTIONS_CHROMEOS_POWER_HANDLER_H_ -#include "ash/system/power/power_status.h" +#include "ash/common/system/chromeos/power/power_status.h" #include "base/macros.h" #include "base/strings/string16.h" #include "chrome/browser/ui/webui/options/options_ui.h"
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index e79a29f3..e2fe6c5f 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -8,7 +8,7 @@ #include <string> -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h index eaaf0cc..9a7aa2ab 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h +++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_DEVICE_POWER_HANDLER_H_ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_DEVICE_POWER_HANDLER_H_ -#include "ash/system/power/power_status.h" +#include "ash/common/system/chromeos/power/power_status.h" #include "base/macros.h" #include "base/scoped_observer.h" #include "base/strings/string16.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc index acc82a8..1f752da 100644 --- a/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/webui/settings/chromeos/device_stylus_handler.h" -#include "ash/system/palette/palette_utils.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" #include "base/bind.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 7f4801d..52ffa8d 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -34,7 +34,7 @@ #if defined(OS_CHROMEOS) #include "ash/common/ash_switches.h" -#include "ash/system/devicetype_utils.h" +#include "ash/common/system/chromeos/devicetype_utils.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h" #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc index 8965f09..1ee6c03 100644 --- a/chrome/browser/ui/webui/settings/md_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -44,8 +44,8 @@ #include "content/public/browser/web_ui_data_source.h" #if defined(OS_CHROMEOS) -#include "ash/system/palette/palette_utils.h" -#include "ash/system/power/power_status.h" +#include "ash/common/system/chromeos/palette/palette_utils.h" +#include "ash/common/system/chromeos/power/power_status.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h" #include "chrome/browser/ui/ash/ash_util.h"
diff --git a/chrome/browser/ui/window_sizer/window_sizer.cc b/chrome/browser/ui/window_sizer/window_sizer.cc index f3c4ea6..2183bcdf 100644 --- a/chrome/browser/ui/window_sizer/window_sizer.cc +++ b/chrome/browser/ui/window_sizer/window_sizer.cc
@@ -24,8 +24,8 @@ #if defined(USE_ASH) #include "ash/common/ash_switches.h" +#include "ash/common/wm/window_positioner.h" // nogncheck #include "ash/shell.h" // nogncheck -#include "ash/wm/window_positioner.h" // nogncheck #include "chrome/browser/ui/ash/ash_util.h" // nogncheck #endif
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash.cc b/chrome/browser/ui/window_sizer/window_sizer_ash.cc index afb0aed2..89c18ebe8 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_ash.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
@@ -4,10 +4,10 @@ #include "chrome/browser/ui/window_sizer/window_sizer.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" #include "ash/shell.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_state.h" #include "chrome/browser/ui/ash/ash_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h"
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc index 4fa16e6c..9e0ebf65 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/shelf/shelf_view.h" +#include "ash/common/shelf/wm_shelf.h" #include "ash/common/wm_window.h" -#include "ash/shelf/shelf_view.h" -#include "ash/shelf/wm_shelf.h" #include "ash/shell.h" #include "base/command_line.h" #include "base/location.h"
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc index e61b306..aee502a 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -3,13 +3,13 @@ // found in the LICENSE file. #include "ash/common/scoped_root_window_for_new_windows.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_resizer.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "base/memory/ptr_util.h" #include "build/build_config.h"
diff --git a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc index cd748e3..039a1ad 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc
@@ -7,7 +7,7 @@ #include <stddef.h> #include <utility> -#include "ash/wm/window_resizer.h" +#include "ash/common/wm/window_resizer.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "build/build_config.h"
diff --git a/chrome/browser/usb/web_usb_detector.cc b/chrome/browser/usb/web_usb_detector.cc index cb08363..8bf90dd 100644 --- a/chrome/browser/usb/web_usb_detector.cc +++ b/chrome/browser/usb/web_usb_detector.cc
@@ -30,7 +30,7 @@ #include "url/gurl.h" #if defined(OS_CHROMEOS) -#include "ash/system/system_notifier.h" // nogncheck +#include "ash/common/system/system_notifier.h" // nogncheck #endif namespace {
diff --git a/chrome/test/base/view_event_test_platform_part_chromeos.cc b/chrome/test/base/view_event_test_platform_part_chromeos.cc index 3e885a4..3714ff6 100644 --- a/chrome/test/base/view_event_test_platform_part_chromeos.cc +++ b/chrome/test/base/view_event_test_platform_part_chromeos.cc
@@ -6,10 +6,10 @@ #include <memory> +#include "ash/common/test/test_session_state_delegate.h" #include "ash/shell.h" #include "ash/shell_init_params.h" #include "ash/test/ash_test_helper.h" -#include "ash/test/test_session_state_delegate.h" #include "ash/test/test_shell_delegate.h" #include "base/command_line.h" #include "base/macros.h"
diff --git a/components/arc/audio/arc_audio_bridge.cc b/components/arc/audio/arc_audio_bridge.cc index 9a0da0882..bdf7e4fe 100644 --- a/components/arc/audio/arc_audio_bridge.cc +++ b/components/arc/audio/arc_audio_bridge.cc
@@ -4,7 +4,7 @@ #include "components/arc/audio/arc_audio_bridge.h" -#include "ash/system/audio/tray_audio.h" +#include "ash/common/system/chromeos/audio/tray_audio.h" #include "base/logging.h" #include "chromeos/audio/audio_device.h" #include "components/arc/arc_bridge_service.h"
diff --git a/components/exo/pointer_unittest.cc b/components/exo/pointer_unittest.cc index 9dbe73ea0..f495138 100644 --- a/components/exo/pointer_unittest.cc +++ b/components/exo/pointer_unittest.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/wm/window_positioning_utils.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/window_positioning_utils.h" #include "components/exo/buffer.h" #include "components/exo/pointer.h" #include "components/exo/pointer_delegate.h"
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index 1083866de..00a36da 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -6,12 +6,12 @@ #include <algorithm> +#include "ash/common/frame/custom_frame_view_ash.h" +#include "ash/common/shelf/wm_shelf.h" +#include "ash/common/wm/window_resizer.h" +#include "ash/common/wm/window_state.h" #include "ash/common/wm_window.h" -#include "ash/frame/custom_frame_view_ash.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/shelf/wm_shelf.h" -#include "ash/wm/window_resizer.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" #include "ash/wm/window_util.h" #include "base/logging.h"
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index ec3d6ab..74ff30d 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -9,7 +9,7 @@ #include <memory> #include <string> -#include "ash/wm/window_state_observer.h" +#include "ash/common/wm/window_state_observer.h" #include "base/macros.h" #include "base/strings/string16.h" #include "components/exo/surface_delegate.h"
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index 86bd001..45cc534 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -3,12 +3,12 @@ // found in the LICENSE file. #include "ash/common/accessibility_delegate.h" +#include "ash/common/wm/window_state.h" +#include "ash/common/wm/wm_event.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/window_state.h" #include "ash/wm/window_state_aura.h" -#include "ash/wm/wm_event.h" #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "components/exo/buffer.h"
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc index 45a00396..e10c6da2 100644 --- a/components/exo/test/exo_test_helper.cc +++ b/components/exo/test/exo_test_helper.cc
@@ -4,10 +4,10 @@ #include "components/exo/test/exo_test_helper.h" +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_positioning_utils.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_positioning_utils.h" #include "components/exo/buffer.h" #include "components/exo/shell_surface.h" #include "components/exo/surface.h"
diff --git a/components/exo/touch_unittest.cc b/components/exo/touch_unittest.cc index 8b9ed93..18917fb 100644 --- a/components/exo/touch_unittest.cc +++ b/components/exo/touch_unittest.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "ash/common/wm/window_positioner.h" +#include "ash/common/wm/window_positioning_utils.h" #include "ash/common/wm_shell.h" #include "ash/common/wm_window.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" -#include "ash/wm/window_positioner.h" -#include "ash/wm/window_positioning_utils.h" #include "components/exo/buffer.h" #include "components/exo/shell_surface.h" #include "components/exo/surface.h"
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc index 273af51e..413eeb8e 100644 --- a/components/exo/wm_helper_ash.cc +++ b/components/exo/wm_helper_ash.cc
@@ -5,10 +5,10 @@ #include "components/exo/wm_helper_ash.h" #include "ash/common/accessibility_delegate.h" +#include "ash/common/system/tray/system_tray_notifier.h" +#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" #include "ash/common/wm_shell.h" #include "ash/shell.h" -#include "ash/system/tray/system_tray_notifier.h" -#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "base/memory/singleton.h" #include "ui/aura/client/focus_client.h" #include "ui/display/manager/display_manager.h"
diff --git a/components/exo/wm_helper_ash.h b/components/exo/wm_helper_ash.h index a8ace31..b41e750 100644 --- a/components/exo/wm_helper_ash.h +++ b/components/exo/wm_helper_ash.h
@@ -6,7 +6,7 @@ #define COMPONENTS_EXO_WM_HELPER_ASH_H_ #include "ash/common/shell_observer.h" -#include "ash/system/accessibility_observer.h" +#include "ash/common/system/accessibility_observer.h" #include "base/macros.h" #include "components/exo/wm_helper.h" #include "ui/aura/client/cursor_client_observer.h"
diff --git a/mojo/public/cpp/bindings/struct_ptr.h b/mojo/public/cpp/bindings/struct_ptr.h index a01c42f..b135312e 100644 --- a/mojo/public/cpp/bindings/struct_ptr.h +++ b/mojo/public/cpp/bindings/struct_ptr.h
@@ -228,7 +228,7 @@ class StructPtrWTFHelper { public: static bool IsHashTableDeletedValue(const StructPtr<Struct>& value) { - return value.ptr_ == reinterpret_cast<Struct*>(1u); + return value.ptr_.get() == reinterpret_cast<Struct*>(1u); } static void ConstructDeletedValue(mojo::StructPtr<Struct>& slot) { @@ -239,7 +239,7 @@ // Dirty trick: implant an invalid pointer in |ptr_|. Destructor isn't // called for deleted buckets, so this is okay. new (&slot) StructPtr<Struct>(); - slot.ptr_ = reinterpret_cast<Struct*>(1u); + slot.ptr_.reset(reinterpret_cast<Struct*>(1u)); } };
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn index 71305b8e..6244226 100644 --- a/mojo/public/cpp/bindings/tests/BUILD.gn +++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -21,6 +21,7 @@ "handle_passing_unittest.cc", "hash_unittest.cc", "interface_ptr_unittest.cc", + "map_unittest.cc", "message_queue.cc", "message_queue.h", "multiplex_router_unittest.cc", @@ -80,6 +81,7 @@ "container_test_util.h", "variant_test_util.h", "wtf_hash_unittest.cc", + "wtf_map_unittest.cc", "wtf_types_unittest.cc", ]
diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc new file mode 100644 index 0000000..8d630a5 --- /dev/null +++ b/mojo/public/cpp/bindings/tests/map_unittest.cc
@@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stddef.h> +#include <stdint.h> +#include <unordered_map> +#include <utility> + +#include "mojo/public/cpp/bindings/tests/rect_chromium.h" +#include "mojo/public/interfaces/bindings/tests/rect.mojom.h" +#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace test { +namespace { + +TEST(MapTest, StructKey) { + std::unordered_map<RectPtr, int32_t> map; + map.insert(std::make_pair(Rect::New(1, 2, 3, 4), 123)); + + RectPtr key = Rect::New(1, 2, 3, 4); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->second); + + map.erase(key); + ASSERT_EQ(0u, map.size()); +} + +TEST(MapTest, TypemappedStructKey) { + std::unordered_map<ContainsHashablePtr, int32_t> map; + map.insert( + std::make_pair(ContainsHashable::New(RectChromium(1, 2, 3, 4)), 123)); + + ContainsHashablePtr key = ContainsHashable::New(RectChromium(1, 2, 3, 4)); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->second); + + map.erase(key); + ASSERT_EQ(0u, map.size()); +} + +} // namespace +} // namespace test +} // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc index 2fc2a67..959d25b 100644 --- a/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc +++ b/mojo/public/cpp/bindings/tests/wtf_hash_unittest.cc
@@ -5,7 +5,9 @@ #include "mojo/public/cpp/bindings/lib/wtf_hash_util.h" #include "mojo/public/interfaces/bindings/tests/test_structs.mojom-blink.h" +#include "mojo/public/interfaces/bindings/tests/test_wtf_types.mojom-blink.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/Source/wtf/HashFunctions.h" namespace mojo { namespace test { @@ -31,6 +33,28 @@ blink::UnmappedNativeStruct::New())); } +TEST_F(WTFHashTest, Enum) { + // Just check that this template instantiation compiles. + + // Top-level. + ASSERT_EQ(WTF::DefaultHash<blink::TopLevelEnum>::Hash().hash( + blink::TopLevelEnum::E0), + WTF::DefaultHash<blink::TopLevelEnum>::Hash().hash( + blink::TopLevelEnum::E0)); + + // Nested in struct. + ASSERT_EQ(WTF::DefaultHash<blink::TestWTFStruct::NestedEnum>::Hash().hash( + blink::TestWTFStruct::NestedEnum::E0), + WTF::DefaultHash<blink::TestWTFStruct::NestedEnum>::Hash().hash( + blink::TestWTFStruct::NestedEnum::E0)); + + // Nested in interface. + ASSERT_EQ(WTF::DefaultHash<blink::TestWTF::NestedEnum>::Hash().hash( + blink::TestWTF::NestedEnum::E0), + WTF::DefaultHash<blink::TestWTF::NestedEnum>::Hash().hash( + blink::TestWTF::NestedEnum::E0)); +} + } // namespace } // namespace test } // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc new file mode 100644 index 0000000..5028087 --- /dev/null +++ b/mojo/public/cpp/bindings/tests/wtf_map_unittest.cc
@@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/tests/rect_blink.h" +#include "mojo/public/interfaces/bindings/tests/rect.mojom-blink.h" +#include "mojo/public/interfaces/bindings/tests/test_structs.mojom-blink.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace test { +namespace { + +TEST(WTFMapTest, StructKey) { + WTF::HashMap<blink::RectPtr, int32_t> map; + map.insert(blink::Rect::New(1, 2, 3, 4), 123); + + blink::RectPtr key = blink::Rect::New(1, 2, 3, 4); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->value); + + map.remove(key); + ASSERT_EQ(0u, map.size()); +} + +TEST(WTFMapTest, TypemappedStructKey) { + WTF::HashMap<blink::ContainsHashablePtr, int32_t> map; + map.insert(blink::ContainsHashable::New(RectBlink(1, 2, 3, 4)), 123); + + blink::ContainsHashablePtr key = + blink::ContainsHashable::New(RectBlink(1, 2, 3, 4)); + ASSERT_NE(map.end(), map.find(key)); + ASSERT_EQ(123, map.find(key)->value); + + map.remove(key); + ASSERT_EQ(0u, map.size()); +} + +} // namespace +} // namespace test +} // namespace mojo
diff --git a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom index 2fdbea8..183f184 100644 --- a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom +++ b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
@@ -25,13 +25,26 @@ }; struct TestWTFStruct { + enum NestedEnum { + E0, + E1, + }; string str; int32 integer; }; interface TestWTF { + enum NestedEnum { + E0, + E1, + }; EchoString(string? str) => (string? str); EchoStringArray(array<string?>? arr) => (array<string?>? arr); EchoStringMap(map<string, string?>? str_map) => (map<string, string?>? str_map); }; + +enum TopLevelEnum { + E0, + E1, +};
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni index cdf93b6..bb0fc43 100644 --- a/mojo/public/tools/bindings/blink_bindings_configuration.gni +++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -30,8 +30,4 @@ } ] } -blacklist = [ - # TODO(sammc): Remove the following once |for_blink| bindings support WTF - # maps with enum keys. See https://crbug.com/583738. - "//mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom", -] +blacklist = []
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl index 9400ca7..92073bc 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/enum_macros.tmpl
@@ -78,3 +78,50 @@ struct hash<{{enum_name}}> : public mojo::internal::EnumHashImpl<{{enum_name}}> {}; {%- endmacro %} + +{%- macro enum_hash_blink(enum) %} +{%- set enum_name = enum|get_qualified_name_for_kind( + flatten_nested_kind=True, include_variant=False) %} +{%- set hash_fn_name = enum|wtf_hash_fn_name_for_enum %} +{# We need two unused enum values: #} +{%- set empty_value = -1000000 %} +{%- set deleted_value = -1000001 %} +{%- set empty_value_unused = "false" if empty_value in enum|all_enum_values else "true" %} +{%- set deleted_value_unused = "false" if empty_value in enum|all_enum_values else "true" %} +namespace WTF { +struct {{hash_fn_name}} { + static unsigned hash(const {{enum_name}}& value) { + typedef base::underlying_type<{{enum_name}}>::type utype; + return DefaultHash<utype>::Hash().hash(static_cast<utype>(value)); + } + static bool equal(const {{enum_name}}& left, const {{enum_name}}& right) { + return left == right; + } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +template <> +struct DefaultHash<{{enum_name}}> { + using Hash = {{hash_fn_name}}; +}; + +template <> +struct HashTraits<{{enum_name}}> + : public GenericHashTraits<{{enum_name}}> { + static_assert({{empty_value_unused}}, + "{{empty_value}} is a reserved enum value"); + static_assert({{deleted_value_unused}}, + "{{deleted_value}} is a reserved enum value"); + static const bool hasIsEmptyValueFunction = true; + static bool isEmptyValue(const {{enum_name}}& value) { + return value == static_cast<{{enum_name}}>({{empty_value}}); + } + static void constructDeletedValue({{enum_name}}& slot, bool) { + slot = static_cast<{{enum_name}}>({{deleted_value}}); + } + static bool isDeletedValue(const {{enum_name}}& value) { + return value == static_cast<{{enum_name}}>({{deleted_value}}); + } +}; +} // namespace WTF +{%- endmacro %}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl index 9306d2f8..acdad5e 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -86,6 +86,16 @@ #include "{{export_header}}" {%- endif %} +{#--- WTF enum hashing #} +{%- from "enum_macros.tmpl" import enum_hash_blink%} +{%- if for_blink %} +{%- for enum in all_enums %} +{%- if not enum|is_native_only_kind %} +{{enum_hash_blink(enum)}} +{%- endif %} +{%- endfor %} +{%- endif %} + {{namespace_begin()}} {#--- Enums #}
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 87e39ecb..38d222b 100644 --- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -153,10 +153,19 @@ internal=internal, flatten_nested_kind=flatten_nested_kind, add_same_module_namespaces=add_same_module_namespaces) -def GetQualifiedNameForKind(kind, internal=False, flatten_nested_kind=False): - return _NameFormatter(kind, _variant).FormatForCpp( - internal=internal, add_same_module_namespaces=True, - flatten_nested_kind=flatten_nested_kind) +def GetQualifiedNameForKind(kind, internal=False, flatten_nested_kind=False, + include_variant=True): + return _NameFormatter( + kind, _variant if include_variant else None).FormatForCpp( + internal=internal, add_same_module_namespaces=True, + flatten_nested_kind=flatten_nested_kind) + + +def GetWtfHashFnNameForEnum(enum): + return _NameFormatter( + enum, None).Format("_", internal=True, add_same_module_namespaces=True, + flatten_nested_kind=True) + "HashFn" + def GetFullMojomNameForKind(kind): return _NameFormatter(kind, _variant).FormatForMojom() @@ -211,6 +220,18 @@ return Check(kind) +def AllEnumValues(enum): + """Return all enum values associated with an enum. + + Args: + enum: {mojom.Enum} The enum type. + + Returns: + {Set[int]} The values. + """ + return set(field.numeric_value for field in enum.fields) + + def GetNativeTypeName(typemapped_kind): return _current_typemap[GetFullMojomNameForKind(typemapped_kind)]["typename"] @@ -584,6 +605,7 @@ class Generator(generator.Generator): cpp_filters = { + "all_enum_values": AllEnumValues, "constant_value": ConstantValue, "contains_handles_or_interfaces": mojom.ContainsHandlesOrInterfaces, "contains_move_only_members": ContainsMoveOnlyMembers, @@ -630,6 +652,7 @@ "stylize_method": generator.StudlyCapsToCamel, "under_to_camel": generator.UnderToCamel, "unmapped_type_for_serializer": GetUnmappedTypeForSerializer, + "wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum, } def GetExtraTraitsHeaders(self):
diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py index df9c2c5..3a5f188e 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py
@@ -303,7 +303,7 @@ module: {Module} The defining module. imported_from: {dict} Information about where this union was imported from. - fields: {List[StructField]} The members of the union. + fields: {List[StructField]} The members of the struct. attributes: {dict} Additional information about the struct, such as if it's a native struct. """
diff --git a/net/BUILD.gn b/net/BUILD.gn index ceec9ce..1f483d3 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -1261,10 +1261,6 @@ "quic/core/quic_headers_stream.cc", "quic/core/quic_headers_stream.h", "quic/core/quic_iovector.h", - "quic/core/quic_multipath_received_packet_manager.cc", - "quic/core/quic_multipath_received_packet_manager.h", - "quic/core/quic_multipath_transmissions_map.cc", - "quic/core/quic_multipath_transmissions_map.h", "quic/core/quic_one_block_arena.h", "quic/core/quic_packet_creator.cc", "quic/core/quic_packet_creator.h",
diff --git a/net/quic/core/congestion_control/bbr_sender.cc b/net/quic/core/congestion_control/bbr_sender.cc index 438a553a..b63b630 100644 --- a/net/quic/core/congestion_control/bbr_sender.cc +++ b/net/quic/core/congestion_control/bbr_sender.cc
@@ -8,8 +8,10 @@ #include <sstream> #include "net/quic/core/congestion_control/rtt_stats.h" +#include "net/quic/core/crypto/crypto_protocol.h" #include "net/quic/core/quic_flags.h" #include "net/quic/platform/api/quic_bug_tracker.h" +#include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_logging.h" namespace net { @@ -90,6 +92,7 @@ static_cast<float>(base::GetFlag(FLAGS_quic_bbr_cwnd_gain))), rtt_variance_weight_(static_cast<float>( base::GetFlag(FLAGS_quic_bbr_rtt_variation_weight))), + num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup), cycle_current_offset_(0), last_cycle_start_(QuicTime::Zero()), is_at_full_bandwidth_(false), @@ -167,6 +170,19 @@ return recovery_state_ != NOT_IN_RECOVERY; } +void BbrSender::SetFromConfig(const QuicConfig& config, + Perspective perspective) { + if (FLAGS_quic_reloadable_flag_quic_allow_2_rtt_bbr_startup) { + QUIC_FLAG_COUNT(gfe2_reloadable_flag_quic_allow_2_rtt_bbr_startup); + if (config.HasClientRequestedIndependentOption(k1RTT, perspective)) { + num_startup_rtts_ = 1; + } + if (config.HasClientRequestedIndependentOption(k2RTT, perspective)) { + num_startup_rtts_ = 2; + } + } +} + void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, QuicByteCount prior_in_flight, QuicTime event_time, @@ -358,8 +374,7 @@ } rounds_without_bandwidth_gain_++; - if (rounds_without_bandwidth_gain_ >= - kRoundTripsWithoutGrowthBeforeExitingStartup) { + if (rounds_without_bandwidth_gain_ >= num_startup_rtts_) { is_at_full_bandwidth_ = true; } }
diff --git a/net/quic/core/congestion_control/bbr_sender.h b/net/quic/core/congestion_control/bbr_sender.h index 21d7115..7a1089c 100644 --- a/net/quic/core/congestion_control/bbr_sender.h +++ b/net/quic/core/congestion_control/bbr_sender.h
@@ -102,7 +102,8 @@ bool InRecovery() const override; void SetFromConfig(const QuicConfig& config, - Perspective perspective) override {} + Perspective perspective) override; + void ResumeConnectionState( const CachedNetworkParameters& cached_network_params, bool max_bandwidth_resumption) override {} @@ -130,6 +131,9 @@ void OnApplicationLimited(QuicByteCount bytes_in_flight) override; // End implementation of SendAlgorithmInterface. + // Gets the number of RTTs BBR remains in STARTUP phase. + QuicRoundTripCount num_startup_rtts() const { return num_startup_rtts_; } + DebugState ExportDebugState() const; private: @@ -242,6 +246,8 @@ // The coefficient by which mean RTT variance is added to the congestion // window. Latched from quic_bbr_rtt_variation_weight flag. const float rtt_variance_weight_; + // The number of RTTs to stay in STARTUP mode. Defaults to 3. + QuicRoundTripCount num_startup_rtts_; // Number of round-trips in PROBE_BW mode, used for determining the current // pacing gain cycle.
diff --git a/net/quic/core/congestion_control/bbr_sender_test.cc b/net/quic/core/congestion_control/bbr_sender_test.cc index 1497689b..d987655 100644 --- a/net/quic/core/congestion_control/bbr_sender_test.cc +++ b/net/quic/core/congestion_control/bbr_sender_test.cc
@@ -461,5 +461,71 @@ EXPECT_GE(sender_->PacingRate(0), initial_rate); } +// Test exiting STARTUP earlier due to the 1RTT connection option. +TEST_F(BbrSenderTest, SimpleTransfer1RTTStartup) { + FLAGS_quic_reloadable_flag_quic_allow_2_rtt_bbr_startup = true; + CreateDefaultSetup(); + + QuicConfig config; + QuicTagVector options; + options.push_back(k1RTT); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + EXPECT_EQ(1u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(1u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(1u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + +// Test exiting STARTUP earlier due to the 2RTT connection option. +TEST_F(BbrSenderTest, SimpleTransfer2RTTStartup) { + FLAGS_quic_reloadable_flag_quic_allow_2_rtt_bbr_startup = true; + CreateDefaultSetup(); + + QuicConfig config; + QuicTagVector options; + options.push_back(k2RTT); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + sender_->SetFromConfig(config, Perspective::IS_SERVER); + EXPECT_EQ(2u, sender_->num_startup_rtts()); + + // Run until the full bandwidth is reached and check how many rounds it was. + bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024); + QuicRoundTripCount max_bw_round = 0; + QuicBandwidth max_bw(QuicBandwidth::Zero()); + bool simulator_result = simulator_.RunUntilOrTimeout( + [this, &max_bw, &max_bw_round]() { + if (max_bw < sender_->ExportDebugState().max_bandwidth) { + max_bw = sender_->ExportDebugState().max_bandwidth; + max_bw_round = sender_->ExportDebugState().round_trip_count; + } + return sender_->ExportDebugState().is_at_full_bandwidth; + }, + QuicTime::Delta::FromSeconds(5)); + ASSERT_TRUE(simulator_result); + EXPECT_EQ(BbrSender::DRAIN, sender_->ExportDebugState().mode); + EXPECT_EQ(2u, sender_->ExportDebugState().round_trip_count - max_bw_round); + EXPECT_EQ(2u, sender_->ExportDebugState().rounds_without_bandwidth_gain); + EXPECT_EQ(0u, bbr_sender_.connection()->GetStats().packets_lost); + EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); +} + } // namespace test } // namespace net
diff --git a/net/quic/core/congestion_control/cubic.cc b/net/quic/core/congestion_control/cubic.cc index d3e04aa..2b023df 100644 --- a/net/quic/core/congestion_control/cubic.cc +++ b/net/quic/core/congestion_control/cubic.cc
@@ -124,22 +124,18 @@ QuicTime event_time) { acked_packets_count_ += 1; // Packets acked. epoch_packets_count_ += 1; - QuicTime current_time = FLAGS_quic_reloadable_flag_quic_use_event_time - ? event_time - : clock_->ApproximateNow(); - // Cubic is "independent" of RTT, the update is limited by the time elapsed. if (last_congestion_window_ == current_congestion_window && - (current_time - last_update_time_ <= MaxCubicTimeInterval())) { + (event_time - last_update_time_ <= MaxCubicTimeInterval())) { return std::max(last_target_congestion_window_, estimated_tcp_congestion_window_); } last_congestion_window_ = current_congestion_window; - last_update_time_ = current_time; + last_update_time_ = event_time; if (!epoch_.IsInitialized()) { // First ACK after a loss event. - epoch_ = current_time; // Start of epoch. + epoch_ = event_time; // Start of epoch. acked_packets_count_ = 1; // Reset count. epoch_packets_count_ = 1; // Reset estimated_tcp_congestion_window_ to be in sync with cubic. @@ -159,7 +155,7 @@ // the round trip time in account. This is done to allow us to use shift as a // divide operator. const int64_t elapsed_time = - ((current_time + delay_min - epoch_).ToMicroseconds() << 10) / + ((event_time + delay_min - epoch_).ToMicroseconds() << 10) / kNumMicrosPerSecond; DCHECK_GE(elapsed_time, 0);
diff --git a/net/quic/core/congestion_control/cubic_bytes.cc b/net/quic/core/congestion_control/cubic_bytes.cc index ea19622e..e18e056 100644 --- a/net/quic/core/congestion_control/cubic_bytes.cc +++ b/net/quic/core/congestion_control/cubic_bytes.cc
@@ -141,23 +141,19 @@ QuicTime::Delta delay_min, QuicTime event_time) { acked_bytes_count_ += acked_bytes; - QuicTime current_time = FLAGS_quic_reloadable_flag_quic_use_event_time - ? event_time - : clock_->ApproximateNow(); - // Cubic is "independent" of RTT, the update is limited by the time elapsed. if (last_congestion_window_ == current_congestion_window && - (current_time - last_update_time_ <= MaxCubicTimeInterval())) { + (event_time - last_update_time_ <= MaxCubicTimeInterval())) { return std::max(last_target_congestion_window_, estimated_tcp_congestion_window_); } last_congestion_window_ = current_congestion_window; - last_update_time_ = current_time; + last_update_time_ = event_time; if (!epoch_.IsInitialized()) { // First ACK after a loss event. QUIC_DVLOG(1) << "Start of epoch"; - epoch_ = current_time; // Start of epoch. + epoch_ = event_time; // Start of epoch. acked_bytes_count_ = acked_bytes; // Reset count. // Reset estimated_tcp_congestion_window_ to be in sync with cubic. estimated_tcp_congestion_window_ = current_congestion_window; @@ -175,7 +171,7 @@ // the round trip time in account. This is done to allow us to use shift as a // divide operator. int64_t elapsed_time = - ((current_time + delay_min - epoch_).ToMicroseconds() << 10) / + ((event_time + delay_min - epoch_).ToMicroseconds() << 10) / kNumMicrosPerSecond; int64_t offset = time_to_origin_point_ - elapsed_time;
diff --git a/net/quic/core/congestion_control/general_loss_algorithm_test.cc b/net/quic/core/congestion_control/general_loss_algorithm_test.cc index da9d11c..6fa96d7 100644 --- a/net/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -35,18 +35,16 @@ void SendDataPacket(QuicPacketNumber packet_number) { QuicStreamFrame* frame = new QuicStreamFrame(); frame->stream_id = kHeadersStreamId; - SerializedPacket packet(kDefaultPathId, packet_number, - PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, - false, false); + SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, false, false); packet.retransmittable_frames.push_back(QuicFrame(frame)); unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(), true); } void SendAckPacket(QuicPacketNumber packet_number) { - SerializedPacket packet(kDefaultPathId, packet_number, - PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, - true, false); + SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, true, false); unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(), false); }
diff --git a/net/quic/core/crypto/crypto_protocol.h b/net/quic/core/crypto/crypto_protocol.h index e426832..9a7876d 100644 --- a/net/quic/core/crypto/crypto_protocol.h +++ b/net/quic/core/crypto/crypto_protocol.h
@@ -79,6 +79,8 @@ // receive window to // 1MB. (2^0xa KB). const QuicTag kTBBR = TAG('T', 'B', 'B', 'R'); // Reduced Buffer Bloat TCP +const QuicTag k1RTT = TAG('1', 'R', 'T', 'T'); // STARTUP in BBR for 1 RTT +const QuicTag k2RTT = TAG('2', 'R', 'T', 'T'); // STARTUP in BBR for 2 RTTs const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control const QuicTag kBYTE = TAG('B', 'Y', 'T', 'E'); // TCP cubic or reno in bytes const QuicTag kRATE = TAG('R', 'A', 'T', 'E'); // TCP cubic rate based sending @@ -123,6 +125,7 @@ const QuicTag kCCVX = TAG('C', 'C', 'V', 'X'); // Fix Cubic convex bug. const QuicTag kCBQT = TAG('C', 'B', 'Q', 'T'); // Fix CubicBytes quantization. const QuicTag kBLMX = TAG('B', 'L', 'M', 'X'); // Fix Cubic BetaLastMax bug. +const QuicTag kNSTP = TAG('N', 'S', 'T', 'P'); // No stop waiting frames. // Optional support of truncated Connection IDs. If sent by a peer, the value // is the minimum number of bytes allowed for the connection ID sent to the
diff --git a/net/quic/core/frames/quic_ack_frame.cc b/net/quic/core/frames/quic_ack_frame.cc index 0f7464a..8dcb1373 100644 --- a/net/quic/core/frames/quic_ack_frame.cc +++ b/net/quic/core/frames/quic_ack_frame.cc
@@ -5,6 +5,7 @@ #include "net/quic/core/frames/quic_ack_frame.h" #include "net/quic/core/quic_constants.h" +#include "net/quic/platform/api/quic_bug_tracker.h" namespace net { @@ -16,9 +17,7 @@ } QuicAckFrame::QuicAckFrame() - : largest_observed(0), - ack_delay_time(QuicTime::Delta::Infinite()), - path_id(kDefaultPathId) {} + : largest_observed(0), ack_delay_time(QuicTime::Delta::Infinite()) {} QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default; @@ -73,6 +72,14 @@ return Empty() || old_min != Min(); } +void PacketNumberQueue::RemoveSmallestInterval() { + QUIC_BUG_IF(packet_number_intervals_.Size() < 2) + << (Empty() ? "No intervals to remove." + : "Can't remove the last interval."); + + packet_number_intervals_.Difference(*packet_number_intervals_.begin()); +} + void PacketNumberQueue::Complement() { if (Empty()) { return;
diff --git a/net/quic/core/frames/quic_ack_frame.h b/net/quic/core/frames/quic_ack_frame.h index 816a4ac..bdfc4be 100644 --- a/net/quic/core/frames/quic_ack_frame.h +++ b/net/quic/core/frames/quic_ack_frame.h
@@ -50,6 +50,9 @@ // the queue. Returns true if packets were removed. bool RemoveUpTo(QuicPacketNumber higher); + // Removes the smallest interval in the queue. + void RemoveSmallestInterval(); + // Mutates packet number set so that it contains only those packet numbers // from minimum to maximum packet number not currently in the set. Do nothing // if packet number set is empty. @@ -115,9 +118,6 @@ // Set of packets. PacketNumberQueue packets; - - // Path which this ack belongs to. - QuicPathId path_id; }; // True if the packet number is greater than largest_observed or is listed
diff --git a/net/quic/core/frames/quic_frames_test.cc b/net/quic/core/frames/quic_frames_test.cc index 11f083ec..82b9667 100644 --- a/net/quic/core/frames/quic_frames_test.cc +++ b/net/quic/core/frames/quic_frames_test.cc
@@ -145,6 +145,23 @@ EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 50u, 20u)); } +TEST(QuicFramesTest, RemoveSmallestInterval) { + QuicAckFrame ack_frame1; + ack_frame1.largest_observed = 100u; + ack_frame1.packets.Add(51, 60); + ack_frame1.packets.Add(71, 80); + ack_frame1.packets.Add(91, 100); + ack_frame1.packets.RemoveSmallestInterval(); + EXPECT_EQ(2u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(71u, ack_frame1.packets.Min()); + EXPECT_EQ(99u, ack_frame1.packets.Max()); + + ack_frame1.packets.RemoveSmallestInterval(); + EXPECT_EQ(1u, ack_frame1.packets.NumIntervals()); + EXPECT_EQ(91u, ack_frame1.packets.Min()); + EXPECT_EQ(99u, ack_frame1.packets.Max()); +} + // Tests that a queue contains the expected data after calls to Add(). TEST(PacketNumberQueueTest, AddRange) { PacketNumberQueue queue;
diff --git a/net/quic/core/frames/quic_stop_waiting_frame.cc b/net/quic/core/frames/quic_stop_waiting_frame.cc index b051beb..b61b32ac 100644 --- a/net/quic/core/frames/quic_stop_waiting_frame.cc +++ b/net/quic/core/frames/quic_stop_waiting_frame.cc
@@ -8,8 +8,7 @@ namespace net { -QuicStopWaitingFrame::QuicStopWaitingFrame() - : path_id(kDefaultPathId), least_unacked(0) {} +QuicStopWaitingFrame::QuicStopWaitingFrame() : least_unacked(0) {} QuicStopWaitingFrame::~QuicStopWaitingFrame() {}
diff --git a/net/quic/core/frames/quic_stop_waiting_frame.h b/net/quic/core/frames/quic_stop_waiting_frame.h index 1c02a77..7632d08 100644 --- a/net/quic/core/frames/quic_stop_waiting_frame.h +++ b/net/quic/core/frames/quic_stop_waiting_frame.h
@@ -20,8 +20,6 @@ std::ostream& os, const QuicStopWaitingFrame& s); - // Path which this stop waiting frame belongs to. - QuicPathId path_id; // The lowest packet we've sent which is unacked, and we expect an ack for. QuicPacketNumber least_unacked; };
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc index ae9e1cd..60e6d7e 100644 --- a/net/quic/core/quic_connection.cc +++ b/net/quic/core/quic_connection.cc
@@ -29,6 +29,7 @@ #include "net/quic/core/quic_pending_retransmission.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_bug_tracker.h" +#include "net/quic/platform/api/quic_flag_utils.h" #include "net/quic/platform/api/quic_logging.h" #include "net/quic/platform/api/quic_map_util.h" #include "net/quic/platform/api/quic_str_cat.h" @@ -260,7 +261,8 @@ goaway_sent_(false), goaway_received_(false), multipath_enabled_(false), - write_error_occured_(false) { + write_error_occured_(false), + no_stop_waiting_frames_(false) { QUIC_DLOG(INFO) << ENDPOINT << "Created connection with connection_id: " << connection_id; framer_.set_visitor(this); @@ -273,6 +275,10 @@ SetMaxPacketLength(perspective_ == Perspective::IS_SERVER ? kDefaultServerMaxPacketSize : kDefaultMaxPacketSize); + if (packet_generator_.latched_flag_no_stop_waiting_frames()) { + QUIC_FLAG_COUNT_N(gfe2_reloadable_flag_quic_no_stop_waiting_frame, 1, 2); + received_packet_manager_.set_max_ack_ranges(255); + } } QuicConnection::~QuicConnection() { @@ -345,6 +351,11 @@ if (config.HasClientSentConnectionOption(k5RTO, perspective_)) { close_connection_after_five_rtos_ = true; } + if (packet_generator_.latched_flag_no_stop_waiting_frames() && + config.HasClientSentConnectionOption(kNSTP, perspective_)) { + QUIC_FLAG_COUNT_N(gfe2_reloadable_flag_quic_no_stop_waiting_frame, 2, 2); + no_stop_waiting_frames_ = true; + } } void QuicConnection::OnSendConnectionState( @@ -694,6 +705,10 @@ largest_seen_packet_with_ack_ = last_header_.packet_number; sent_packet_manager_.OnIncomingAck(incoming_ack, time_of_last_received_packet_); + if (no_stop_waiting_frames_) { + received_packet_manager_.DontWaitForPacketsBefore( + sent_packet_manager_.largest_packet_peer_knows_is_acked()); + } // Always reset the retransmission alarm when an ack comes in, since we now // have a better estimate of the current rtt than when it was set. SetRetransmissionAlarm(); @@ -716,7 +731,9 @@ bool QuicConnection::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) { DCHECK(connected_); - + if (no_stop_waiting_frames_) { + return true; + } if (last_header_.packet_number <= largest_seen_packet_with_stop_waiting_) { QUIC_DLOG(INFO) << ENDPOINT << "Received an old stop waiting frame: ignoring"; @@ -1131,12 +1148,6 @@ stats_.blocked_frames_sent++; } -void QuicConnection::SendPathClose(QuicPathId path_id) { - // Opportunistically bundle an ack with this outgoing packet. - ScopedPacketBundler ack_bundler(this, SEND_ACK_IF_PENDING); - packet_generator_.AddControlFrame(QuicFrame(new QuicPathCloseFrame(path_id))); -} - const QuicConnectionStats& QuicConnection::GetStats() { const RttStats* rtt_stats = sent_packet_manager_.GetRttStats(); @@ -1186,9 +1197,8 @@ ++stats_.packets_received; // Ensure the time coming from the packet reader is within a minute of now. - if (FLAGS_quic_reloadable_flag_quic_allow_large_send_deltas && - std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) > - 60) { + if (std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) > + 60) { QUIC_BUG << "Packet receipt time:" << packet.receipt_time().ToDebuggingValue() << " too far from current time:" @@ -1281,10 +1291,16 @@ if (self_address_.port() != last_packet_destination_address_.port() || self_address_.host().Normalized() != last_packet_destination_address_.host().Normalized()) { - CloseConnection(QUIC_ERROR_MIGRATING_ADDRESS, - "Self address migration is not supported at the server.", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return false; + if (FLAGS_quic_reloadable_flag_quic_allow_one_address_change && + AllowSelfAddressChange()) { + OnSelfAddressChange(); + } else { + CloseConnection( + QUIC_ERROR_MIGRATING_ADDRESS, + "Self address migration is not supported at the server.", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return false; + } } self_address_ = last_packet_destination_address_; } @@ -1618,6 +1634,10 @@ return false; } +bool QuicConnection::AllowSelfAddressChange() const { + return false; +} + void QuicConnection::OnWriteError(int error_code) { if (write_error_occured_) { // A write error already occurred. The connection is being closed. @@ -1642,7 +1662,6 @@ } void QuicConnection::OnSerializedPacket(SerializedPacket* serialized_packet) { - DCHECK_NE(kInvalidPathId, serialized_packet->path_id); if (serialized_packet->encrypted_buffer == nullptr) { // We failed to serialize the packet, so close the connection. // TearDownLocalConnectionState does not send close packet, so no infinite @@ -1743,7 +1762,7 @@ last_ack_had_missing_packets_ = received_packet_manager_.HasMissingPackets(); num_packets_received_since_last_ack_sent_ = 0; - packet_generator_.SetShouldSendAck(true); + packet_generator_.SetShouldSendAck(!no_stop_waiting_frames_); } void QuicConnection::OnRetransmissionTimeout() {
diff --git a/net/quic/core/quic_connection.h b/net/quic/core/quic_connection.h index ba3faf2f..bdcc2fa3 100644 --- a/net/quic/core/quic_connection.h +++ b/net/quic/core/quic_connection.h
@@ -362,9 +362,6 @@ // Send a WINDOW_UPDATE frame to the peer. virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset); - // Send a PATH_CLOSE frame to the peer. - virtual void SendPathClose(QuicPathId path_id); - // Closes the connection. // |connection_close_behavior| determines whether or not a connection close // packet is sent to the peer. @@ -741,6 +738,12 @@ // Returns true if the packet should be discarded and not sent. virtual bool ShouldDiscardPacket(const SerializedPacket& packet); + // Returns true if this connection allows self address change. + virtual bool AllowSelfAddressChange() const; + + // Called when a self address change is observed. + virtual void OnSelfAddressChange() {} + private: friend class test::QuicConnectionPeer; friend class test::PacketSavingConnection; @@ -1083,6 +1086,9 @@ // avoid infinite write errors. bool write_error_occured_; + // Indicates not to send or process stop waiting frames. + bool no_stop_waiting_frames_; + DISALLOW_COPY_AND_ASSIGN(QuicConnection); };
diff --git a/net/quic/core/quic_connection_test.cc b/net/quic/core/quic_connection_test.cc index c607cc26..b8d7384 100644 --- a/net/quic/core/quic_connection_test.cc +++ b/net/quic/core/quic_connection_test.cc
@@ -488,7 +488,6 @@ } void SendPacket(EncryptionLevel level, - QuicPathId path_id, QuicPacketNumber packet_number, QuicPacket* packet, HasRetransmittableData retransmittable, @@ -500,8 +499,8 @@ ENCRYPTION_NONE, packet_number, *packet, buffer, kMaxPacketSize); delete packet; SerializedPacket serialized_packet( - kDefaultPathId, packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer, - encrypted_length, has_ack, has_pending_frames); + packet_number, PACKET_6BYTE_PACKET_NUMBER, buffer, encrypted_length, + has_ack, has_pending_frames); if (retransmittable == HAS_RETRANSMITTABLE_DATA) { serialized_packet.retransmittable_frames.push_back( QuicFrame(new QuicStreamFrame())); @@ -642,19 +641,24 @@ // Run tests with combinations of {QuicVersion, AckResponse}. struct TestParams { - TestParams(QuicVersion version, AckResponse ack_response) - : version(version), ack_response(ack_response) {} + TestParams(QuicVersion version, + AckResponse ack_response, + bool no_stop_waiting) + : version(version), + ack_response(ack_response), + no_stop_waiting(no_stop_waiting) {} friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { os << "{ client_version: " << QuicVersionToString(p.version) << " ack_response: " << (p.ack_response == AckResponse::kDefer ? "defer" : "immediate") - << " }"; + << " no_stop_waiting: " << p.no_stop_waiting << " }"; return os; } QuicVersion version; AckResponse ack_response; + bool no_stop_waiting; }; // Constructs various test permutations. @@ -664,7 +668,10 @@ for (size_t i = 0; i < all_supported_versions.size(); ++i) { for (AckResponse ack_response : {AckResponse::kDefer, AckResponse::kImmediate}) { - params.push_back(TestParams(all_supported_versions[i], ack_response)); + for (bool stop_waiting : {true, false}) { + params.push_back( + TestParams(all_supported_versions[i], ack_response, stop_waiting)); + } } } return params; @@ -705,6 +712,8 @@ connection_id_length_(PACKET_8BYTE_CONNECTION_ID) { connection_.set_defer_send_in_response_to_packets(GetParam().ack_response == AckResponse::kDefer); + QuicConnectionPeer::SetNoStopWaitingFrames(&connection_, + GetParam().no_stop_waiting); connection_.set_visitor(&visitor_); connection_.SetSendAlgorithm(send_algorithm_); connection_.SetLossAlgorithm(loss_algorithm_.get()); @@ -762,9 +771,9 @@ void use_tagging_decrypter() { writer_->use_tagging_decrypter(); } - void ProcessPacket(QuicPathId path_id, QuicPacketNumber number) { + void ProcessPacket(QuicPacketNumber number) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacket(path_id, number); + ProcessDataPacket(number); if (connection_.GetSendAlarm()->IsSet()) { connection_.GetSendAlarm()->Fire(); } @@ -810,7 +819,7 @@ DCHECK_GT(length, 0u); const size_t encrypted_length = peer_framer_.EncryptInPlace( - ENCRYPTION_NONE, kDefaultPathId, header.packet_number, + ENCRYPTION_NONE, header.packet_number, GetStartOfEncryptedData(peer_framer_.version(), header), length, kMaxPacketSize, encrypted_buffer); DCHECK_GT(encrypted_length, 0u); @@ -820,16 +829,14 @@ QuicReceivedPacket(encrypted_buffer, encrypted_length, clock_.Now())); } - size_t ProcessFramePacketAtLevel(QuicPathId path_id, - QuicPacketNumber number, + size_t ProcessFramePacketAtLevel(QuicPacketNumber number, QuicFrame frame, EncryptionLevel level) { QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.packet_number_length = packet_number_length_; header.public_header.connection_id_length = connection_id_length_; - header.public_header.multipath_flag = path_id != kDefaultPathId; - header.path_id = path_id; + header.public_header.multipath_flag = false; header.packet_number = number; QuicFrames frames; frames.push_back(frame); @@ -844,16 +851,15 @@ return encrypted_length; } - size_t ProcessDataPacket(QuicPathId path_id, QuicPacketNumber number) { - return ProcessDataPacketAtLevel(path_id, number, false, ENCRYPTION_NONE); + size_t ProcessDataPacket(QuicPacketNumber number) { + return ProcessDataPacketAtLevel(number, false, ENCRYPTION_NONE); } - size_t ProcessDataPacketAtLevel(QuicPathId path_id, - QuicPacketNumber number, + size_t ProcessDataPacketAtLevel(QuicPacketNumber number, bool has_stop_waiting, EncryptionLevel level) { std::unique_ptr<QuicPacket> packet( - ConstructDataPacket(path_id, number, has_stop_waiting)); + ConstructDataPacket(number, has_stop_waiting)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( level, number, *packet, buffer, kMaxPacketSize); @@ -866,7 +872,7 @@ return encrypted_length; } - void ProcessClosePacket(QuicPathId path_id, QuicPacketNumber number) { + void ProcessClosePacket(QuicPacketNumber number) { std::unique_ptr<QuicPacket> packet(ConstructClosePacket(number)); char buffer[kMaxPacketSize]; size_t encrypted_length = peer_framer_.EncryptPayload( @@ -913,11 +919,10 @@ ProcessFramePacket(QuicFrame(frame)); } - size_t ProcessStopWaitingPacketAtLevel(QuicPathId path_id, - QuicPacketNumber number, + size_t ProcessStopWaitingPacketAtLevel(QuicPacketNumber number, QuicStopWaitingFrame* frame, EncryptionLevel level) { - return ProcessFramePacketAtLevel(path_id, number, QuicFrame(frame), + return ProcessFramePacketAtLevel(number, QuicFrame(frame), ENCRYPTION_INITIAL); } @@ -939,15 +944,13 @@ return packet; } - QuicPacket* ConstructDataPacket(QuicPathId path_id, - QuicPacketNumber number, + QuicPacket* ConstructDataPacket(QuicPacketNumber number, bool has_stop_waiting) { QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.packet_number_length = packet_number_length_; header.public_header.connection_id_length = connection_id_length_; - header.public_header.multipath_flag = path_id != kDefaultPathId; - header.path_id = path_id; + header.public_header.multipath_flag = false; header.packet_number = number; QuicFrames frames; @@ -1012,7 +1015,7 @@ ConnectionCloseSource::FROM_SELF)); // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - ProcessDataPacket(kDefaultPathId, 6000); + ProcessDataPacket(6000); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); } @@ -1203,7 +1206,6 @@ QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.version_flag = true; - header.path_id = kDefaultPathId; header.packet_number = 1; QuicFrames frames; @@ -1237,7 +1239,6 @@ QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.version_flag = true; - header.path_id = kDefaultPathId; header.packet_number = 1; QuicFrames frames; @@ -1286,15 +1287,15 @@ TEST_P(QuicConnectionTest, PacketsInOrder) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); EXPECT_EQ(1u, outgoing_ack()->largest_observed); EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals()); - ProcessPacket(kDefaultPathId, 2); + ProcessPacket(2); EXPECT_EQ(2u, outgoing_ack()->largest_observed); EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals()); - ProcessPacket(kDefaultPathId, 3); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_EQ(1u, outgoing_ack()->packets.NumIntervals()); } @@ -1302,17 +1303,17 @@ TEST_P(QuicConnectionTest, PacketsOutOfOrder) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 3); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); - ProcessPacket(kDefaultPathId, 2); + ProcessPacket(2); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_FALSE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_FALSE(IsMissing(2)); EXPECT_FALSE(IsMissing(1)); @@ -1321,14 +1322,14 @@ TEST_P(QuicConnectionTest, DuplicatePacket) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 3); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); // Send packet 3 again, but do not set the expectation that // the visitor OnStreamFrame() will be called. - ProcessDataPacket(kDefaultPathId, 3); + ProcessDataPacket(3); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); @@ -1337,16 +1338,16 @@ TEST_P(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 3); + ProcessPacket(3); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); - ProcessPacket(kDefaultPathId, 2); + ProcessPacket(2); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(1)); - ProcessPacket(kDefaultPathId, 5); + ProcessPacket(5); EXPECT_EQ(5u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(1)); EXPECT_TRUE(IsMissing(4)); @@ -1369,7 +1370,7 @@ ConnectionCloseSource::FROM_SELF)); // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - ProcessDataPacket(kDefaultPathId, 6000); + ProcessDataPacket(6000); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); } @@ -1380,7 +1381,7 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_UNENCRYPTED_STREAM_DATA, _, ConnectionCloseSource::FROM_SELF)); - EXPECT_QUIC_BUG(ProcessDataPacket(kDefaultPathId, 1), ""); + EXPECT_QUIC_BUG(ProcessDataPacket(1), ""); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); const std::vector<QuicConnectionCloseFrame>& connection_close_frames = @@ -1393,19 +1394,19 @@ TEST_P(QuicConnectionTest, OutOfOrderReceiptCausesAckSend) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 3); + ProcessPacket(3); // Should ack immediately since we have missing packets. EXPECT_EQ(1u, writer_->packets_write_attempts()); - ProcessPacket(kDefaultPathId, 2); + ProcessPacket(2); // Should ack immediately since we have missing packets. EXPECT_EQ(2u, writer_->packets_write_attempts()); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); // Should ack immediately, since this fills the last hole. EXPECT_EQ(3u, writer_->packets_write_attempts()); - ProcessPacket(kDefaultPathId, 4); + ProcessPacket(4); // Should not cause an ack. EXPECT_EQ(3u, writer_->packets_write_attempts()); } @@ -1475,7 +1476,11 @@ OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)); connection_.SendStreamDataWithString(3, "foo", 3, !kFin, nullptr); // Ack bundled. - EXPECT_EQ(3u, writer_->frame_count()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + } EXPECT_EQ(1u, writer_->stream_frames().size()); EXPECT_FALSE(writer_->ack_frames().empty()); @@ -1521,16 +1526,20 @@ QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1); // The scheduler will not process out of order acks, but all packet processing // causes the connection to try to write. - EXPECT_CALL(visitor_, OnCanWrite()); + if (!GetParam().no_stop_waiting) { + EXPECT_CALL(visitor_, OnCanWrite()); + } QuicStopWaitingFrame frame2 = InitStopWaitingFrame(1); ProcessStopWaitingPacket(&frame2); // Now claim it's one, but set the ordering so it was sent "after" the first // one. This should cause a connection error. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 7); - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_STOP_WAITING_DATA, _, - ConnectionCloseSource::FROM_SELF)); + if (!GetParam().no_stop_waiting) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_STOP_WAITING_DATA, _, + ConnectionCloseSource::FROM_SELF)); + } QuicStopWaitingFrame frame3 = InitStopWaitingFrame(1); ProcessStopWaitingPacket(&frame3); } @@ -1556,7 +1565,7 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Miss 99 of every 100 packets for 5500 packets. for (QuicPacketNumber i = 1; i < kMaxTrackedPackets + 500; i += 100) { - ProcessPacket(kDefaultPathId, i); + ProcessPacket(i); if (!connection_.connected()) { break; } @@ -1596,7 +1605,7 @@ TEST_P(QuicConnectionTest, AckAll) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1); QuicAckFrame frame1 = InitAckFrame(0); @@ -1610,15 +1619,30 @@ EXPECT_EQ(1u, last_packet); SendAckPacketToPeer(); // Packet 2 - EXPECT_EQ(1u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(1u, least_unacked()); + } SendAckPacketToPeer(); // Packet 3 - EXPECT_EQ(1u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(1u, least_unacked()); + } SendStreamDataToPeer(1, "bar", 3, !kFin, &last_packet); // Packet 4 EXPECT_EQ(4u, last_packet); SendAckPacketToPeer(); // Packet 5 - EXPECT_EQ(1u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(1u, least_unacked()); + } EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); @@ -1629,7 +1653,12 @@ // As soon as we've acked one, we skip ack packets 2 and 3 and note lack of // ack for 4. - EXPECT_EQ(4u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(4u, least_unacked()); + } EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); @@ -1641,17 +1670,32 @@ EXPECT_EQ(6u, writer_->header().packet_number); // So the last ack has not changed. - EXPECT_EQ(4u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(4u, least_unacked()); + } // If we force an ack, we shouldn't change our retransmit state. SendAckPacketToPeer(); // Packet 7 - EXPECT_EQ(7u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(7u, least_unacked()); + } // But if we send more data it should. SendStreamDataToPeer(1, "eep", 6, !kFin, &last_packet); // Packet 8 EXPECT_EQ(8u, last_packet); SendAckPacketToPeer(); // Packet 9 - EXPECT_EQ(7u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(7u, least_unacked()); + } } // QuicConnection should record the the packet sent-time prior to sending the @@ -1701,8 +1745,13 @@ // Parse the last packet and ensure it's an ack and two stream frames from // two different streams. - EXPECT_EQ(4u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(4u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); ASSERT_EQ(2u, writer_->stream_frames().size()); EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0]->stream_id); @@ -1751,7 +1800,7 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Process a data packet to queue up a pending ack. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacket(kDefaultPathId, 1); + ProcessDataPacket(1); EXPECT_CALL(visitor_, OnCanWrite()) .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs( @@ -1770,8 +1819,13 @@ // Parse the last packet and ensure it's an ack and two stream frames from // two different streams. - EXPECT_EQ(4u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(4u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); ASSERT_EQ(2u, writer_->stream_frames().size()); EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0]->stream_id); @@ -2180,8 +2234,7 @@ EXPECT_EQ(0u, connection_.NumQueuedPackets()); // We do not store retransmittable frames of this retransmission. - EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, - kDefaultPathId, 4)); + EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, 4)); } TEST_P(QuicConnectionTest, RetransmitNackedLargestObserved) { @@ -2284,8 +2337,7 @@ connection_.OnCanWrite(); // There is now a pending packet, but with no retransmittable frames. EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, - ack.path_id, 2)); + EXPECT_FALSE(QuicConnectionPeer::HasRetransmittableFrames(&connection_, 2)); } TEST_P(QuicConnectionTest, AlarmsWhenWriteBlocked) { @@ -2389,8 +2441,13 @@ SendAckPacketToPeer(); // Packet 3 // Least_unacked remains at 3 until another ack is received. EXPECT_EQ(3u, stop_waiting()->least_unacked); - // Check that the outgoing ack had its packet number as least_unacked. - EXPECT_EQ(3u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + // Check that the outgoing ack had its packet number as least_unacked. + EXPECT_EQ(3u, least_unacked()); + } // Ack the ack, which updates the rtt and raises the least unacked. EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); @@ -2404,7 +2461,12 @@ ON_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) .WillByDefault(Return(false)); SendAckPacketToPeer(); // Packet 5 - EXPECT_EQ(4u, least_unacked()); + if (GetParam().no_stop_waiting) { + // Expect no stop waiting frame is sent. + EXPECT_EQ(0u, least_unacked()); + } else { + EXPECT_EQ(4u, least_unacked()); + } // Send two data packets at the end, and ensure if the last one is acked, // the least unacked is raised above the ack packets. @@ -2574,8 +2636,7 @@ // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. - ProcessDataPacketAtLevel(kDefaultPathId, 1, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL); // Transition to the new encryption state and process another encrypted packet // which should result in the original packet being processed. @@ -2583,14 +2644,12 @@ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2); - ProcessDataPacketAtLevel(kDefaultPathId, 2, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL); // Finally, process a third packet and note that we do not reprocess the // buffered packet. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 3, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL); } TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) { @@ -2608,8 +2667,7 @@ // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. for (QuicPacketNumber i = 1; i <= 100; ++i) { - ProcessDataPacketAtLevel(kDefaultPathId, i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL); } // Transition to the new encryption state and process another encrypted packet @@ -2618,14 +2676,12 @@ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101); - ProcessDataPacketAtLevel(kDefaultPathId, 101, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(101, !kHasStopWaiting, ENCRYPTION_INITIAL); // Finally, process a third packet and note that we do not reprocess the // buffered packet. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 102, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_INITIAL); } TEST_P(QuicConnectionTest, TestRetransmitOrder) { @@ -3252,7 +3308,7 @@ const QuicTime receive_time = send_time + five_ms; clock_.AdvanceTime(receive_time - clock_.Now()); ASSERT_EQ(receive_time, clock_.Now()); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); // Now move forward to the retransmission time and retransmit the // packet, which should move the timeout forward again (but will not @@ -3497,10 +3553,10 @@ TEST_P(QuicConnectionTest, SendScheduler) { // Test that if we send a packet without delay, it is not queued. - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, !kHasStopWaiting); + QuicPacket* packet = ConstructDataPacket(1, !kHasStopWaiting); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, - HAS_RETRANSMITTABLE_DATA, false, false); + connection_.SendPacket(ENCRYPTION_NONE, 1, packet, HAS_RETRANSMITTABLE_DATA, + false, false); EXPECT_EQ(0u, connection_.NumQueuedPackets()); } @@ -3508,18 +3564,18 @@ // Test that the connection does not crash when it fails to send the first // packet at which point self_address_ might be uninitialized. EXPECT_CALL(visitor_, OnConnectionClosed(_, _, _)).Times(1); - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, !kHasStopWaiting); + QuicPacket* packet = ConstructDataPacket(1, !kHasStopWaiting); writer_->SetShouldWriteFail(); - connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, - HAS_RETRANSMITTABLE_DATA, false, false); + connection_.SendPacket(ENCRYPTION_NONE, 1, packet, HAS_RETRANSMITTABLE_DATA, + false, false); } TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) { - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, !kHasStopWaiting); + QuicPacket* packet = ConstructDataPacket(1, !kHasStopWaiting); BlockOnNextWrite(); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0); - connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, - HAS_RETRANSMITTABLE_DATA, false, false); + connection_.SendPacket(ENCRYPTION_NONE, 1, packet, HAS_RETRANSMITTABLE_DATA, + false, false); EXPECT_EQ(1u, connection_.NumQueuedPackets()); } @@ -3604,8 +3660,7 @@ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3613,8 +3668,13 @@ // Simulate delayed ack alarm firing. connection_.GetAckAlarm()->Fire(); // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -3642,15 +3702,14 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3660,12 +3719,17 @@ for (int i = 0; i < 9; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -3694,15 +3758,14 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3712,12 +3775,17 @@ for (int i = 0; i < 9; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -3746,15 +3814,14 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3762,8 +3829,8 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting, + ENCRYPTION_INITIAL); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -3772,12 +3839,17 @@ for (int i = 0; i < 8; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -3806,15 +3878,14 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3822,8 +3893,8 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, + ENCRYPTION_INITIAL); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -3832,12 +3903,17 @@ for (int i = 0; i < 8; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); @@ -3845,11 +3921,16 @@ // because it fills a hole. EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -3879,15 +3960,14 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3895,8 +3975,8 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting, + ENCRYPTION_INITIAL); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -3905,12 +3985,17 @@ for (int i = 0; i < 8; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -3941,15 +4026,14 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -3957,8 +4041,8 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, + ENCRYPTION_INITIAL); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -3967,12 +4051,17 @@ for (int i = 0; i < 8; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); @@ -3980,18 +4069,23 @@ // because it fills a hole. EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); // Check that ack is sent and that delayed ack alarm is set. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); QuicTime ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime(); @@ -4012,11 +4106,16 @@ TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); - ProcessPacket(kDefaultPathId, 2); + ProcessPacket(1); + ProcessPacket(2); // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(1u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } @@ -4024,56 +4123,66 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Drop one packet, triggering a sequence of acks. - ProcessPacket(kDefaultPathId, 2); - size_t frames_per_ack = 2; + ProcessPacket(2); + size_t frames_per_ack = GetParam().no_stop_waiting ? 1 : 2; EXPECT_EQ(frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); - ProcessPacket(kDefaultPathId, 3); + ProcessPacket(3); EXPECT_EQ(frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); - ProcessPacket(kDefaultPathId, 4); + ProcessPacket(4); EXPECT_EQ(frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); - ProcessPacket(kDefaultPathId, 5); + ProcessPacket(5); EXPECT_EQ(frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); // Now only set the timer on the 6th packet, instead of sending another ack. - ProcessPacket(kDefaultPathId, 6); + ProcessPacket(6); EXPECT_EQ(0u, writer_->frame_count()); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); } TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingPacket) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); connection_.SendStreamDataWithString(kClientDataStreamId1, "foo", 0, !kFin, nullptr); // Check that ack is bundled with outgoing data and that delayed ack // alarm is reset. - EXPECT_EQ(3u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } TEST_P(QuicConnectionTest, SendDelayedAckOnOutgoingCryptoPacket) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin, nullptr); // Check that ack is bundled with outgoing crypto data. - EXPECT_EQ(3u, writer_->frame_count()); - EXPECT_FALSE(writer_->ack_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } TEST_P(QuicConnectionTest, BlockAndBufferOnFirstCHLOPacketOfTwo) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); BlockOnNextWrite(); writer_->set_is_write_blocked_data_buffered(true); connection_.SendStreamDataWithString(kCryptoStreamId, "foo", 0, !kFin, @@ -4095,10 +4204,15 @@ // Process a packet from the crypto stream, which is frame1_'s default. // Receiving the CHLO as packet 2 first will cause the connection to // immediately send an ack, due to the packet gap. - ProcessPacket(kDefaultPathId, 2); + ProcessPacket(2); // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(3u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_EQ(1u, writer_->stream_frames().size()); EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(2u, writer_->ack_frames().front().largest_observed); @@ -4112,16 +4226,21 @@ // Process two packets from the crypto stream, which is frame1_'s default, // simulating a 2 packet reject. { - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); // Send the new CHLO when the REJ is processed. EXPECT_CALL(visitor_, OnStreamFrame(_)) .WillOnce(IgnoreResult(InvokeWithoutArgs( &connection_, &TestConnection::SendCryptoStreamData))); - ProcessDataPacket(kDefaultPathId, 2); + ProcessDataPacket(2); } // Check that ack is sent and that delayed ack alarm is reset. - EXPECT_EQ(3u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_EQ(1u, writer_->stream_frames().size()); EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(2u, writer_->ack_frames().front().largest_observed); @@ -4171,8 +4290,13 @@ // Check that ack is bundled with outgoing data and the delayed ack // alarm is reset. - EXPECT_EQ(3u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + if (GetParam().no_stop_waiting) { + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_TRUE(writer_->stop_waiting_frames().empty()); + } else { + EXPECT_EQ(3u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + } EXPECT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(3u, writer_->ack_frames().front().largest_observed); EXPECT_EQ(1u, writer_->stream_frames().size()); @@ -4181,11 +4305,11 @@ TEST_P(QuicConnectionTest, NoAckSentForClose) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, _, ConnectionCloseSource::FROM_PEER)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - ProcessClosePacket(kDefaultPathId, 2); + ProcessClosePacket(2); } TEST_P(QuicConnectionTest, SendWhenDisconnected) { @@ -4196,10 +4320,10 @@ ConnectionCloseBehavior::SILENT_CLOSE); EXPECT_FALSE(connection_.connected()); EXPECT_FALSE(connection_.CanWriteStreamData()); - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, !kHasStopWaiting); + QuicPacket* packet = ConstructDataPacket(1, !kHasStopWaiting); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0); - connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, - HAS_RETRANSMITTABLE_DATA, false, false); + connection_.SendPacket(ENCRYPTION_NONE, 1, packet, HAS_RETRANSMITTABLE_DATA, + false, false); } TEST_P(QuicConnectionTest, PublicReset) { @@ -4273,7 +4397,6 @@ QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.public_header.version_flag = true; - header.path_id = kDefaultPathId; header.packet_number = 12; QuicFrames frames; @@ -4388,7 +4511,6 @@ // NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion. QuicPacketHeader header; header.public_header.connection_id = connection_id_; - header.path_id = kDefaultPathId; header.packet_number = 12; header.public_header.version_flag = false; QuicFrames frames; @@ -5020,7 +5142,7 @@ TEST_P(QuicConnectionTest, DonotForceSendingAckOnPacketTooLarge) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Send an ack by simulating delayed ack alarm firing. - ProcessPacket(kDefaultPathId, 1); + ProcessPacket(1); QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); EXPECT_TRUE(ack_alarm->IsSet()); connection_.GetAckAlarm()->Fire();
diff --git a/net/quic/core/quic_crypto_client_stream_test.cc b/net/quic/core/quic_crypto_client_stream_test.cc index 571ca249..497e82a 100644 --- a/net/quic/core/quic_crypto_client_stream_test.cc +++ b/net/quic/core/quic_crypto_client_stream_test.cc
@@ -230,10 +230,8 @@ reinterpret_cast<char*>(scfg), arraysize(scfg)); QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(stream()); - EXPECT_NE( - FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer && - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time, // NOLINT - QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + EXPECT_NE(FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer, + QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); } TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdateWithCert) {
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h index 8d284003..4128de5 100644 --- a/net/quic/core/quic_flags_list.h +++ b/net/quic/core/quic_flags_list.h
@@ -76,29 +76,15 @@ FLAGS_quic_reloadable_flag_quic_enable_server_push_by_default, true) -// Allow large send deltas to be used as RTT samples. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_large_send_deltas, true) - // If true, release QuicCryptoStream\'s read buffer when stream are less // frequently used. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer, true) -// Use a more conservative backoff of 2x instead of 1.5x for handshake -// retransmissions, as well as a larger minimum. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_conservative_handshake_retransmits, - false) - // If true, buffer packets while parsing public headers instead of parsing down // if CHLO is already buffered. -QUIC_FLAG(bool, - FLAGS_quic_reloadable_flag_quic_buffer_packets_after_chlo, - false) - -// If true, enable the Lazy FACK style loss detection in QUIC. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_lazy_fack, true) +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_buffer_packets_after_chlo, true) // If true, do not override a connection in global map if exists. Only create // QUIC session if it is successfully inserted to the global map. Toss the @@ -122,13 +108,6 @@ FLAGS_quic_reloadable_flag_quic_limit_uncompressed_headers, false) -// If true, release headers stream\'s sequencer buffer when there is no active -// stream. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_headers_stream_release_sequencer_buffer, - true) - // Enable QUIC force HOL blocking experiment. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_force_hol_blocking, true) @@ -136,10 +115,6 @@ // allow CHLO packets to be buffered until next iteration of the event loop. QUIC_FLAG(bool, FLAGS_quic_allow_chlo_buffering, true) -// Add a new client connection options field to QuicOptions which is only used -// to configure client side features, such as congestion control. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_client_connection_options, true) - // If true, fix some casts that were causing off-by-one errors in QUIC's cubic // "convex" increases. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_cubic_convex_mode, false) @@ -153,17 +128,6 @@ FLAGS_quic_reloadable_flag_quic_fix_cubic_bytes_quantization, false) -// If true, QUIC cubic code will use the event time when adjusting CWND after an -// ACK instead of the clock\'s current approximate time. -QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_event_time, true) - -// If true, lazy allocate and early release memeory used in -// QuicStreamSequencerBuffer to buffer incoming data. -QUIC_FLAG( - bool, - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time, - true) - // If true, Makes GFE respect the connection options for initial flow control // window larger than 32 KB. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_large_ifw_options, true) @@ -177,9 +141,6 @@ // If true, disables QUIC v34. QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_disable_version_34, true) -// Allow quic to properly support proxying 100 Continue responses. -QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_supports_100_continue, false) - // If true, enable quic version 38 QUIC_FLAG(bool, FLAGS_quic_enable_version_38, false) @@ -198,3 +159,14 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_always_enable_bidi_streaming, false) + +// If true, allows the 1RTT and 2RTT connection options to reduce the time +// in BBR STARTUP to 1 or 2 RTTs with no bandwidth increase from 3. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_2_rtt_bbr_startup, false) + +// If true, do not send or process stop waiting frames in QUIC if the NSTP +// connection option is provided. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames, false) + +// Allows one self address change. +QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_allow_one_address_change, false)
diff --git a/net/quic/core/quic_framer.cc b/net/quic/core/quic_framer.cc index e32db271..0084511 100644 --- a/net/quic/core/quic_framer.cc +++ b/net/quic/core/quic_framer.cc
@@ -703,11 +703,6 @@ << QuicTagToString(tag) << "'"; } - if (header.public_header.multipath_flag && - !writer->WriteUInt8(header.path_id)) { - return false; - } - if (header.public_header.nonce != nullptr && !writer->WriteBytes(header.public_header.nonce, kDiversificationNonceSize)) { @@ -924,13 +919,6 @@ bool QuicFramer::ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, QuicPacketHeader* header) { - header->path_id = kDefaultPathId; - if (header->public_header.multipath_flag && - !ProcessPathId(encrypted_reader, &header->path_id)) { - set_detailed_error("Unable to read path id."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - QuicPacketNumber base_packet_number = largest_packet_number_; if (!ProcessPacketSequenceNumber( @@ -953,14 +941,6 @@ return true; } -bool QuicFramer::ProcessPathId(QuicDataReader* reader, QuicPathId* path_id) { - if (!reader->ReadBytes(path_id, 1)) { - return false; - } - - return true; -} - bool QuicFramer::ProcessPacketSequenceNumber( QuicDataReader* reader, QuicPacketNumberLength packet_number_length, @@ -1525,7 +1505,6 @@ } size_t QuicFramer::EncryptInPlace(EncryptionLevel level, - QuicPathId path_id, QuicPacketNumber packet_number, size_t ad_len, size_t total_len,
diff --git a/net/quic/core/quic_framer.h b/net/quic/core/quic_framer.h index 23d3c3ce..004643f 100644 --- a/net/quic/core/quic_framer.h +++ b/net/quic/core/quic_framer.h
@@ -296,7 +296,6 @@ // data. |total_len| is the length of the associated data plus plaintext. // |buffer_len| is the full length of the allocated buffer. size_t EncryptInPlace(EncryptionLevel level, - QuicPathId path_id, QuicPacketNumber packet_number, size_t ad_len, size_t total_len, @@ -370,7 +369,6 @@ bool ProcessUnauthenticatedHeader(QuicDataReader* encrypted_reader, QuicPacketHeader* header); - bool ProcessPathId(QuicDataReader* reader, QuicPathId* path_id); bool ProcessPacketSequenceNumber(QuicDataReader* reader, QuicPacketNumberLength packet_number_length, QuicPacketNumber base_packet_number,
diff --git a/net/quic/core/quic_framer_test.cc b/net/quic/core/quic_framer_test.cc index 01a201d..26ece5bf 100644 --- a/net/quic/core/quic_framer_test.cc +++ b/net/quic/core/quic_framer_test.cc
@@ -67,37 +67,29 @@ // Index into the packet number offset in the header. size_t GetPacketNumberOffset(QuicConnectionIdLength connection_id_length, - bool include_version, - bool include_path_id) { + bool include_version) { return kConnectionIdOffset + connection_id_length + - (include_version ? kQuicVersionSize : 0) + - (include_path_id ? kQuicPathIdSize : 0); + (include_version ? kQuicVersionSize : 0); } -size_t GetPacketNumberOffset(bool include_version, bool include_path_id) { - return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version, - include_path_id); +size_t GetPacketNumberOffset(bool include_version) { + return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version); } // Index into the private flags offset in the data packet header. size_t GetPrivateFlagsOffset(QuicConnectionIdLength connection_id_length, - bool include_version, - bool include_path_id) { - return GetPacketNumberOffset(connection_id_length, include_version, - include_path_id) + + bool include_version) { + return GetPacketNumberOffset(connection_id_length, include_version) + PACKET_6BYTE_PACKET_NUMBER; } -size_t GetPrivateFlagsOffset(bool include_version, bool include_path_id) { - return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version, - include_path_id); +size_t GetPrivateFlagsOffset(bool include_version) { + return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version); } size_t GetPrivateFlagsOffset(bool include_version, - bool include_path_id, QuicPacketNumberLength packet_number_length) { - return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version, - include_path_id) + + return GetPacketNumberOffset(PACKET_8BYTE_CONNECTION_ID, include_version) + packet_number_length; } @@ -355,9 +347,7 @@ return static_cast<unsigned char>('0' + (version_ / 10) % 10); } - bool CheckEncryption(QuicPathId path_id, - QuicPacketNumber packet_number, - QuicPacket* packet) { + bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { EXPECT_EQ(version_, encrypter_->version_); if (packet_number != encrypter_->packet_number_) { QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected " @@ -663,7 +653,7 @@ string expected_error; if (i < kConnectionIdOffset) { expected_error = "Unable to read public flags."; - } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) { + } else if (i < GetPacketNumberOffset(!kIncludeVersion)) { expected_error = "Unable to read ConnectionId."; } else { expected_error = "Unable to read packet number."; @@ -706,7 +696,7 @@ if (i < kConnectionIdOffset) { expected_error = "Unable to read public flags."; } else if (i < GetPacketNumberOffset(PACKET_0BYTE_CONNECTION_ID, - !kIncludeVersion, !kIncludePathId)) { + !kIncludeVersion)) { expected_error = "Unable to read ConnectionId."; } else { expected_error = "Unable to read packet number."; @@ -751,7 +741,7 @@ expected_error = "Unable to read public flags."; } else if (i < kVersionOffset) { expected_error = "Unable to read ConnectionId."; - } else if (i < GetPacketNumberOffset(kIncludeVersion, !kIncludePathId)) { + } else if (i < GetPacketNumberOffset(kIncludeVersion)) { expected_error = "Unable to read protocol version."; } else { expected_error = "Unable to read packet number."; @@ -793,7 +783,7 @@ string expected_error; if (i < kConnectionIdOffset) { expected_error = "Unable to read public flags."; - } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) { + } else if (i < GetPacketNumberOffset(!kIncludeVersion)) { expected_error = "Unable to read ConnectionId."; } else { expected_error = "Unable to read packet number."; @@ -837,7 +827,7 @@ string expected_error; if (i < kConnectionIdOffset) { expected_error = "Unable to read public flags."; - } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) { + } else if (i < GetPacketNumberOffset(!kIncludeVersion)) { expected_error = "Unable to read ConnectionId."; } else { expected_error = "Unable to read packet number."; @@ -881,7 +871,7 @@ string expected_error; if (i < kConnectionIdOffset) { expected_error = "Unable to read public flags."; - } else if (i < GetPacketNumberOffset(!kIncludeVersion, !kIncludePathId)) { + } else if (i < GetPacketNumberOffset(!kIncludeVersion)) { expected_error = "Unable to read ConnectionId."; } else { expected_error = "Unable to read packet number."; @@ -3359,7 +3349,7 @@ ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); - EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get())); + EXPECT_TRUE(CheckEncryption(packet_number, raw.get())); } TEST_P(QuicFramerTest, EncryptPacketWithVersionFlag) { @@ -3394,7 +3384,7 @@ ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); ASSERT_NE(0u, encrypted_length); - EXPECT_TRUE(CheckEncryption(kDefaultPathId, packet_number, raw.get())); + EXPECT_TRUE(CheckEncryption(packet_number, raw.get())); } TEST_P(QuicFramerTest, AckTruncationLargePacket) { @@ -3579,7 +3569,7 @@ QuicVersionVector versions; versions.push_back(framer_.version()); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( - 42, false, false, false, kDefaultPathId, kTestQuicStreamId, kTestString, + 42, false, false, false, kTestQuicStreamId, kTestString, PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions)); MockFramerVisitor visitor; @@ -3615,7 +3605,7 @@ QuicVersionVector versions; versions.push_back(framer_.version()); std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( - 42, false, false, kDefaultPathId, kTestQuicStreamId, kTestString, + 42, false, false, kTestQuicStreamId, kTestString, PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions, Perspective::IS_CLIENT));
diff --git a/net/quic/core/quic_headers_stream.cc b/net/quic/core/quic_headers_stream.cc index 9f03573..00c769c 100644 --- a/net/quic/core/quic_headers_stream.cc +++ b/net/quic/core/quic_headers_stream.cc
@@ -38,8 +38,7 @@ } void QuicHeadersStream::MaybeReleaseSequencerBuffer() { - if (FLAGS_quic_reloadable_flag_quic_headers_stream_release_sequencer_buffer && - spdy_session_->ShouldReleaseHeadersStreamSequencerBuffer()) { + if (spdy_session_->ShouldReleaseHeadersStreamSequencerBuffer()) { sequencer()->ReleaseBufferIfEmpty(); } }
diff --git a/net/quic/core/quic_multipath_received_packet_manager.cc b/net/quic/core/quic_multipath_received_packet_manager.cc deleted file mode 100644 index c7931cf..0000000 --- a/net/quic/core/quic_multipath_received_packet_manager.cc +++ /dev/null
@@ -1,117 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/core/quic_multipath_received_packet_manager.h" - -#include <cstdint> - -#include "net/quic/platform/api/quic_bug_tracker.h" -#include "net/quic/platform/api/quic_ptr_util.h" - -namespace net { - -QuicMultipathReceivedPacketManager::QuicMultipathReceivedPacketManager( - QuicConnectionStats* stats) { - path_managers_[kDefaultPathId] = - QuicMakeUnique<QuicReceivedPacketManager>(stats); -} - -QuicMultipathReceivedPacketManager::~QuicMultipathReceivedPacketManager() {} - -void QuicMultipathReceivedPacketManager::OnPathCreated( - QuicPathId path_id, - QuicConnectionStats* stats) { - if (path_managers_[path_id] != nullptr) { - QUIC_BUG << "Received packet manager of path already exists: " - << static_cast<uint32_t>(path_id); - return; - } - - path_managers_[path_id] = QuicMakeUnique<QuicReceivedPacketManager>(stats); -} - -void QuicMultipathReceivedPacketManager::OnPathClosed(QuicPathId path_id) { - QuicReceivedPacketManager* manager = path_managers_[path_id].get(); - if (manager == nullptr) { - QUIC_BUG << "Received packet manager of path does not exist: " - << static_cast<uint32_t>(path_id); - return; - } - - path_managers_.erase(path_id); -} - -void QuicMultipathReceivedPacketManager::RecordPacketReceived( - QuicPathId path_id, - const QuicPacketHeader& header, - QuicTime receipt_time) { - QuicReceivedPacketManager* manager = path_managers_[path_id].get(); - if (manager == nullptr) { - QUIC_BUG << "Received a packet on a non-existent path."; - return; - } - - manager->RecordPacketReceived(header, receipt_time); -} - -bool QuicMultipathReceivedPacketManager::IsMissing( - QuicPathId path_id, - QuicPacketNumber packet_number) { - QuicReceivedPacketManager* manager = path_managers_[path_id].get(); - if (manager == nullptr) { - QUIC_BUG << "Check whether a packet is missing on a non-existent path."; - return true; - } - - return manager->IsMissing(packet_number); -} - -bool QuicMultipathReceivedPacketManager::IsAwaitingPacket( - QuicPathId path_id, - QuicPacketNumber packet_number) { - QuicReceivedPacketManager* manager = path_managers_[path_id].get(); - if (manager == nullptr) { - QUIC_BUG << "Check whether a packet is awaited on a non-existent path."; - return false; - } - - return manager->IsAwaitingPacket(packet_number); -} - -void QuicMultipathReceivedPacketManager::UpdatePacketInformationSentByPeer( - const std::vector<QuicStopWaitingFrame>& stop_waitings) { - for (QuicStopWaitingFrame stop_waiting : stop_waitings) { - QuicReceivedPacketManager* manager = - path_managers_[stop_waiting.path_id].get(); - if (manager != nullptr) { - manager->DontWaitForPacketsBefore(stop_waiting.least_unacked); - } - } -} - -bool QuicMultipathReceivedPacketManager::HasNewMissingPackets( - QuicPathId path_id) const { - auto it = path_managers_.find(path_id); - if (it == path_managers_.end()) { - QUIC_BUG << "Check whether has new missing packets on a non-existent path."; - return false; - } - - return it->second->HasNewMissingPackets(); -} - -QuicPacketNumber -QuicMultipathReceivedPacketManager::GetPeerLeastPacketAwaitingAck( - QuicPathId path_id) { - QuicReceivedPacketManager* manager = path_managers_[path_id].get(); - if (manager == nullptr) { - QUIC_BUG - << "Try to get peer_least_packet_awaiting_ack of a non-existent path."; - return false; - } - - return manager->peer_least_packet_awaiting_ack(); -} - -} // namespace net
diff --git a/net/quic/core/quic_multipath_received_packet_manager.h b/net/quic/core/quic_multipath_received_packet_manager.h deleted file mode 100644 index 3f48aaa..0000000 --- a/net/quic/core/quic_multipath_received_packet_manager.h +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// A connection level received packet manager which manages multiple per path -// received packet managers. - -#ifndef NET_QUIC_CORE_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_ -#define NET_QUIC_CORE_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_ - -#include <memory> -#include <unordered_map> -#include <vector> - -#include "net/quic/core/quic_packets.h" -#include "net/quic/core/quic_received_packet_manager.h" -#include "net/quic/platform/api/quic_export.h" - -namespace net { - -namespace test { -class QuicMultipathReceivedPacketManagerPeer; -} // namespace test - -class QUIC_EXPORT_PRIVATE QuicMultipathReceivedPacketManager { - public: - explicit QuicMultipathReceivedPacketManager(QuicConnectionStats* stats); - ~QuicMultipathReceivedPacketManager(); - QuicMultipathReceivedPacketManager( - const QuicMultipathReceivedPacketManager&) = delete; - QuicMultipathReceivedPacketManager& operator=( - const QuicMultipathReceivedPacketManager&) = delete; - - // Called when a new path with |path_id| is created. - void OnPathCreated(QuicPathId path_id, QuicConnectionStats* stats); - - // Called when path with |path_id| is closed. - void OnPathClosed(QuicPathId path_id); - - // Records packet receipt information on path with |path_id|. - void RecordPacketReceived(QuicPathId path_id, - const QuicPacketHeader& header, - QuicTime receipt_time); - - // Checks whether |packet_number| is missing on path with |path_id|. - bool IsMissing(QuicPathId path_id, QuicPacketNumber packet_number); - - // Checks if we're still waiting for the packet with |packet_number| on path - // with |path_id|. - bool IsAwaitingPacket(QuicPathId path_id, QuicPacketNumber packet_number); - - // If |force_all_paths| is false, populates ack information for paths whose - // ack has been updated since UpdateReceivedPacketInfo was called last time. - // Otherwise, populates ack for all paths. - void UpdateReceivedPacketInfo(std::vector<QuicAckFrame>* ack_frames, - QuicTime approximate_now, - bool force_all_paths); - - // Updates internal state based on stop_waiting frames for corresponding path. - void UpdatePacketInformationSentByPeer( - const std::vector<QuicStopWaitingFrame>& stop_waitings); - - // Returns true when there are new missing packets to be reported within 3 - // packets of the largest observed on path with |path_id|. - bool HasNewMissingPackets(QuicPathId path_id) const; - - QuicPacketNumber GetPeerLeastPacketAwaitingAck(QuicPathId path_id); - - private: - friend class test::QuicMultipathReceivedPacketManagerPeer; - - // Map mapping path id to path received packet manager. - std::unordered_map<QuicPathId, std::unique_ptr<QuicReceivedPacketManager>> - path_managers_; -}; - -} // namespace net - -#endif // NET_QUIC_CORE_QUIC_MULTIPATH_RECEIVED_PACKET_MANAGER_H_
diff --git a/net/quic/core/quic_multipath_received_packet_manager_test.cc b/net/quic/core/quic_multipath_received_packet_manager_test.cc deleted file mode 100644 index afedaa3..0000000 --- a/net/quic/core/quic_multipath_received_packet_manager_test.cc +++ /dev/null
@@ -1,139 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/core/quic_multipath_received_packet_manager.h" - -#include "net/quic/core/quic_connection_stats.h" -#include "net/quic/platform/api/quic_ptr_util.h" -#include "net/quic/test_tools/quic_test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::Return; -using testing::_; - -namespace net { -namespace test { - -class QuicMultipathReceivedPacketManagerPeer { - public: - static bool PathReceivedPacketManagerExists( - QuicMultipathReceivedPacketManager* multipath_manager, - QuicPathId path_id) { - return multipath_manager->path_managers_.count(path_id); - } - - static void SetPathReceivedPacketManager( - QuicMultipathReceivedPacketManager* multipath_manager, - QuicPathId path_id, - std::unique_ptr<QuicReceivedPacketManager> manager) { - multipath_manager->path_managers_[path_id] = std::move(manager); - } -}; - -namespace { - -const QuicPathId kPathId1 = 1; -const QuicPathId kPathId2 = 2; -const QuicPathId kPathId3 = 3; - -class QuicMultipathReceivedPacketManagerTest : public testing::Test { - public: - QuicMultipathReceivedPacketManagerTest() - : multipath_manager_(&stats_), - manager_0_(new MockReceivedPacketManager(&stats_)), - manager_1_(new MockReceivedPacketManager(&stats_)) { - QuicMultipathReceivedPacketManagerPeer::SetPathReceivedPacketManager( - &multipath_manager_, kDefaultPathId, QuicWrapUnique(manager_0_)); - QuicMultipathReceivedPacketManagerPeer::SetPathReceivedPacketManager( - &multipath_manager_, kPathId1, QuicWrapUnique(manager_1_)); - } - - QuicConnectionStats stats_; - QuicMultipathReceivedPacketManager multipath_manager_; - MockReceivedPacketManager* manager_0_; - MockReceivedPacketManager* manager_1_; - QuicPacketHeader header_; -}; - -TEST_F(QuicMultipathReceivedPacketManagerTest, OnPathCreatedAndClosed) { - EXPECT_TRUE( - QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists( - &multipath_manager_, kDefaultPathId)); - EXPECT_TRUE( - QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists( - &multipath_manager_, kPathId1)); - EXPECT_QUIC_BUG(multipath_manager_.OnPathCreated(kDefaultPathId, &stats_), - "Received packet manager of path already exists"); - // Path 2 created. - multipath_manager_.OnPathCreated(kPathId2, &stats_); - EXPECT_TRUE( - QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists( - &multipath_manager_, kPathId2)); - EXPECT_FALSE( - QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists( - &multipath_manager_, kPathId3)); - // Path 3 created. - multipath_manager_.OnPathCreated(kPathId3, &stats_); - EXPECT_TRUE( - QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists( - &multipath_manager_, kPathId3)); - - // Path 0 closed. - multipath_manager_.OnPathClosed(kDefaultPathId); - EXPECT_FALSE( - QuicMultipathReceivedPacketManagerPeer::PathReceivedPacketManagerExists( - &multipath_manager_, kDefaultPathId)); - EXPECT_QUIC_BUG(multipath_manager_.OnPathClosed(kDefaultPathId), - "Received packet manager of path does not exist"); -} - -TEST_F(QuicMultipathReceivedPacketManagerTest, RecordPacketReceived) { - EXPECT_CALL(*manager_0_, RecordPacketReceived(_, _)).Times(1); - multipath_manager_.RecordPacketReceived(kDefaultPathId, header_, - QuicTime::Zero()); - EXPECT_QUIC_BUG(multipath_manager_.RecordPacketReceived(kPathId2, header_, - QuicTime::Zero()), - "Received a packet on a non-existent path"); -} - -TEST_F(QuicMultipathReceivedPacketManagerTest, IsMissing) { - EXPECT_CALL(*manager_0_, IsMissing(header_.packet_number)) - .WillOnce(Return(true)); - EXPECT_CALL(*manager_1_, IsMissing(header_.packet_number)) - .WillOnce(Return(false)); - EXPECT_TRUE( - multipath_manager_.IsMissing(kDefaultPathId, header_.packet_number)); - EXPECT_FALSE(multipath_manager_.IsMissing(kPathId1, header_.packet_number)); - EXPECT_QUIC_BUG(multipath_manager_.IsMissing(kPathId2, header_.packet_number), - "Check whether a packet is missing on a non-existent path"); -} - -TEST_F(QuicMultipathReceivedPacketManagerTest, IsAwaitingPacket) { - EXPECT_CALL(*manager_0_, IsAwaitingPacket(header_.packet_number)) - .WillOnce(Return(true)); - EXPECT_CALL(*manager_1_, IsAwaitingPacket(header_.packet_number)) - .WillOnce(Return(false)); - EXPECT_TRUE(multipath_manager_.IsAwaitingPacket(kDefaultPathId, - header_.packet_number)); - EXPECT_FALSE( - multipath_manager_.IsAwaitingPacket(kPathId1, header_.packet_number)); - EXPECT_QUIC_BUG( - multipath_manager_.IsAwaitingPacket(kPathId2, header_.packet_number), - "Check whether a packet is awaited on a non-existent path"); -} - -TEST_F(QuicMultipathReceivedPacketManagerTest, HasNewMissingPackets) { - EXPECT_CALL(*manager_0_, HasNewMissingPackets()).WillOnce(Return(true)); - EXPECT_CALL(*manager_1_, HasNewMissingPackets()).WillOnce(Return(false)); - EXPECT_TRUE(multipath_manager_.HasNewMissingPackets(kDefaultPathId)); - EXPECT_FALSE(multipath_manager_.HasNewMissingPackets(kPathId1)); - EXPECT_QUIC_BUG( - multipath_manager_.HasNewMissingPackets(kPathId2), - "Check whether has new missing packets on a non-existent path"); -} - -} // namespace -} // namespace test -} // namespace net
diff --git a/net/quic/core/quic_multipath_transmissions_map.cc b/net/quic/core/quic_multipath_transmissions_map.cc deleted file mode 100644 index 100bf08..0000000 --- a/net/quic/core/quic_multipath_transmissions_map.cc +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/core/quic_multipath_transmissions_map.h" - -namespace net { - -QuicMultipathTransmissionsMap::QuicMultipathTransmissionsMap() {} - -QuicMultipathTransmissionsMap::~QuicMultipathTransmissionsMap() { - for (std::pair<QuicPathIdPacketNumber, MultipathTransmissionsList*> - packet_transmissions : transmission_map_) { - packet_transmissions.second->pop_front(); - if (packet_transmissions.second->empty()) { - delete packet_transmissions.second; - } - } -} - -void QuicMultipathTransmissionsMap::OnPacketRetransmittedOnDifferentPath( - QuicPathIdPacketNumber original_path_id_packet_number, - QuicPathIdPacketNumber path_id_packet_number) { - MultipathTransmissionsList* across_paths_transmission_list = nullptr; - MultipathTransmissionsMap::iterator it = - transmission_map_.find(original_path_id_packet_number); - if (it != transmission_map_.end()) { - across_paths_transmission_list = it->second; - } else { - across_paths_transmission_list = new MultipathTransmissionsList(); - across_paths_transmission_list->push_back(original_path_id_packet_number); - transmission_map_[original_path_id_packet_number] = - across_paths_transmission_list; - } - - across_paths_transmission_list->push_back(path_id_packet_number); - transmission_map_[path_id_packet_number] = across_paths_transmission_list; -} - -const QuicMultipathTransmissionsMap::MultipathTransmissionsList* -QuicMultipathTransmissionsMap::MaybeGetTransmissionsOnOtherPaths( - QuicPathIdPacketNumber path_id_packet_number) const { - MultipathTransmissionsMap::const_iterator it = - transmission_map_.find(path_id_packet_number); - if (it == transmission_map_.end()) { - return nullptr; - } - - return it->second; -} - -void QuicMultipathTransmissionsMap::OnPacketHandled( - QuicPathIdPacketNumber path_id_packet_number) { - MultipathTransmissionsMap::iterator it = - transmission_map_.find(path_id_packet_number); - if (it == transmission_map_.end()) { - return; - } - - MultipathTransmissionsList* transmission_list = it->second; - MultipathTransmissionsList::iterator transmission_it; - // Remove all across paths transmissions of this packet from the map. - for (QuicPathIdPacketNumber path_id_packet_number : *transmission_list) { - transmission_map_.erase(path_id_packet_number); - } - // Remove the multipath transmissions list. - delete transmission_list; -} - -} // namespace net
diff --git a/net/quic/core/quic_multipath_transmissions_map.h b/net/quic/core/quic_multipath_transmissions_map.h deleted file mode 100644 index 6b40076..0000000 --- a/net/quic/core/quic_multipath_transmissions_map.h +++ /dev/null
@@ -1,74 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// A map manages packets which are transmitted across multiple paths. -// For example, a packet is originally transmitted on path 1 with packet number -// 1. Then this packet is retransmitted on path 2 with packet number 1. (1, 1) -// and (2, 1) are inserted into this map. Suppose (2, 1) is detected lost and -// gets retransmitted on path 2 with packet 2. (2, 2) will not be inserted -// because this transmission does not "across" path compared to (2, 1). - -#ifndef NET_QUIC_CORE_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_ -#define NET_QUIC_CORE_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_ - -#include <deque> -#include <unordered_map> - -#include "base/macros.h" -#include "net/quic/core/quic_packets.h" -#include "net/quic/core/quic_utils.h" -#include "net/quic/platform/api/quic_export.h" - -namespace net { - -typedef std::pair<QuicPathId, QuicPacketNumber> QuicPathIdPacketNumber; - -class QUIC_EXPORT_PRIVATE QuicMultipathTransmissionsMap { - public: - struct QuicPathIdPacketNumberHash { - size_t operator()(std::pair<QuicPathId, QuicPacketNumber> value) const { - return QuicUtils::PackPathIdAndPacketNumber(value.first, value.second); - } - }; - - typedef std::deque<QuicPathIdPacketNumber> MultipathTransmissionsList; - typedef std::unordered_map<QuicPathIdPacketNumber, - MultipathTransmissionsList*, - QuicPathIdPacketNumberHash> - MultipathTransmissionsMap; - - QuicMultipathTransmissionsMap(); - ~QuicMultipathTransmissionsMap(); - - // Called when a packet is retransmitted on a different path. Adds both - // |original_path_id_packet_number| (if not exists) and - // |path_id_packet_number| to |transmission_map_|. - void OnPacketRetransmittedOnDifferentPath( - QuicPathIdPacketNumber original_path_id_packet_number, - QuicPathIdPacketNumber path_id_packet_number); - - // Returns all multipath transmissions list if |path_id_packet_number| has - // been transmitted across multiple paths, nullptr otherwise. - const MultipathTransmissionsList* MaybeGetTransmissionsOnOtherPaths( - QuicPathIdPacketNumber path_id_packet_number) const; - - // Called after packet |path_id_packet_number| is received. - // If |path_id_packet_number| has been transmitted across multiple paths, - // clears all multipath transmissions list and removes each transmission from - // |transmission_map_|, does nothing otherwise. - void OnPacketHandled(QuicPathIdPacketNumber path_id_packet_number); - - private: - // Keys of the map are QuicPathIdPacketNumber, and values are pointers to - // lists of multipath transmissions of the same packet. For example, if a - // packet has been transmitted as (1, 1) and (2, 1), two entries are added - // to this map and both values point to the same list: {(1, 1), (2, 1)}. - // The MultipathTransmissionsList is owned by the transmission which is - // received first (on any path). - MultipathTransmissionsMap transmission_map_; -}; - -} // namespace net - -#endif // NET_QUIC_CORE_QUIC_MULTIPATH_TRANSMISSIONS_MAP_H_
diff --git a/net/quic/core/quic_multipath_transmissions_map_test.cc b/net/quic/core/quic_multipath_transmissions_map_test.cc deleted file mode 100644 index a264b0d7..0000000 --- a/net/quic/core/quic_multipath_transmissions_map_test.cc +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/core/quic_multipath_transmissions_map.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace test { -namespace { - -TEST(QuicAcrossPathsTransmissionMapTest, OnPacketRetransmittedOnDifferentPath) { - QuicMultipathTransmissionsMap transmission_map; - // Packet0's original transmission sent on path 1 with packet number 1. - QuicPathIdPacketNumber packet0_0(1, 1); - // Packet0's retransmission sent on path 2 with packet number 1. - QuicPathIdPacketNumber packet0_1(2, 1); - // packet0's 2nd retransmission sent on path 3 with packet number 1. - QuicPathIdPacketNumber packet0_2(3, 1); - - transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1); - const QuicMultipathTransmissionsMap::MultipathTransmissionsList* - transmission_list1 = - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0); - EXPECT_EQ(packet0_0, (*transmission_list1)[0]); - EXPECT_EQ(packet0_1, (*transmission_list1)[1]); - - transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2); - const QuicMultipathTransmissionsMap::MultipathTransmissionsList* - transmission_list2 = - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0); - EXPECT_EQ(packet0_0, (*transmission_list2)[0]); - EXPECT_EQ(packet0_1, (*transmission_list2)[1]); - EXPECT_EQ(packet0_2, (*transmission_list2)[2]); - // Make sure there is no memory leakage. -} - -TEST(QuicAcrossPathsTransmissionMapTest, MaybeGetTransmissionsOnOtherPaths) { - QuicMultipathTransmissionsMap transmission_map; - // Packet0's original transmission sent on path 1 with packet number 1. - QuicPathIdPacketNumber packet0_0(1, 1); - // Packet0's retransmission sent on path 2 with packet number 1. - QuicPathIdPacketNumber packet0_1(2, 1); - // packet0's 2nd retransmission sent on path 3 with packet number 1. - QuicPathIdPacketNumber packet0_2(3, 1); - - transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1); - transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2); - - const QuicMultipathTransmissionsMap::MultipathTransmissionsList* - transmission_list1 = - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0); - const QuicMultipathTransmissionsMap::MultipathTransmissionsList* - transmission_list2 = - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1); - const QuicMultipathTransmissionsMap::MultipathTransmissionsList* - transmission_list3 = - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2); - // Make sure all three pointers point to the same list. - EXPECT_EQ(transmission_list1, transmission_list2); - EXPECT_EQ(transmission_list2, transmission_list3); - EXPECT_EQ(packet0_0, (*transmission_list1)[0]); - EXPECT_EQ(packet0_1, (*transmission_list1)[1]); - EXPECT_EQ(packet0_2, (*transmission_list1)[2]); - - // Packet1 which is not transmitted across path. - QuicPathIdPacketNumber packet1_0(1, 2); - EXPECT_EQ(nullptr, - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0)); - // Make sure there is no memory leakage. -} - -TEST(QuicAcrossPathsTransmissionMapTest, OnPacketHandled) { - QuicMultipathTransmissionsMap transmission_map; - - // Packet's original transmission sent on path 1 with packet number 1. - QuicPathIdPacketNumber packet0_0(1, 1); - // Packet's retransmission sent on path 2 with packet number 1. - QuicPathIdPacketNumber packet0_1(2, 1); - // packet's 2nd retransmission sent on path 3 with packet number 1. - QuicPathIdPacketNumber packet0_2(3, 1); - transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_0, packet0_1); - transmission_map.OnPacketRetransmittedOnDifferentPath(packet0_1, packet0_2); - - // Packet1's original transmission sent on path 1 with packet number 2. - QuicPathIdPacketNumber packet1_0(1, 2); - // Packet1's retransmission sent on path 2 with packet number 2. - QuicPathIdPacketNumber packet1_1(2, 2); - transmission_map.OnPacketRetransmittedOnDifferentPath(packet1_0, packet1_1); - - transmission_map.OnPacketHandled(packet0_0); - EXPECT_EQ(nullptr, - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_0)); - EXPECT_EQ(nullptr, - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_1)); - EXPECT_EQ(nullptr, - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet0_2)); - const QuicMultipathTransmissionsMap::MultipathTransmissionsList* - transmission_list = - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0); - EXPECT_EQ(packet1_0, (*transmission_list)[0]); - EXPECT_EQ(packet1_1, (*transmission_list)[1]); - // Packet 1 is received on path 2. - transmission_map.OnPacketHandled(packet1_1); - EXPECT_EQ(nullptr, - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_0)); - EXPECT_EQ(nullptr, - transmission_map.MaybeGetTransmissionsOnOtherPaths(packet1_1)); - // Make sure there is no memory leakage. -} - -} // namespace -} // namespace test -} // namespace net
diff --git a/net/quic/core/quic_packet_creator.cc b/net/quic/core/quic_packet_creator.cc index 5c4f4f82..7481e1a 100644 --- a/net/quic/core/quic_packet_creator.cc +++ b/net/quic/core/quic_packet_creator.cc
@@ -39,13 +39,9 @@ connection_id_length_(PACKET_8BYTE_CONNECTION_ID), packet_size_(0), connection_id_(connection_id), - packet_(kDefaultPathId, - 0, - PACKET_1BYTE_PACKET_NUMBER, - nullptr, - 0, - false, - false) { + packet_(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false, false), + latched_flag_no_stop_waiting_frames_( + FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames) { SetMaxPacketLength(kDefaultMaxPacketSize); } @@ -341,6 +337,7 @@ packet_.encrypted_length = 0; DCHECK(packet_.retransmittable_frames.empty()); packet_.listeners.clear(); + packet_.largest_acked = 0; } void QuicPacketCreator::CreateAndSerializeStreamFrame( @@ -395,7 +392,7 @@ } size_t encrypted_length = framer_->EncryptInPlace( - packet_.encryption_level, packet_.path_id, packet_.packet_number, + packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->version(), header), writer.length(), arraysize(encrypted_buffer), encrypted_buffer); if (encrypted_length == 0) { @@ -499,7 +496,7 @@ DCHECK_EQ(packet_size_, length); } const size_t encrypted_length = framer_->EncryptInPlace( - packet_.encryption_level, packet_.path_id, packet_.packet_number, + packet_.encryption_level, packet_.packet_number, GetStartOfEncryptedData(framer_->version(), header), length, encrypted_buffer_len, encrypted_buffer); if (encrypted_length == 0) { @@ -527,8 +524,8 @@ // TODO(jri): Make this a public method of framer? SerializedPacket QuicPacketCreator::NoPacket() { - return SerializedPacket(kInvalidPathId, 0, PACKET_1BYTE_PACKET_NUMBER, - nullptr, 0, false, false); + return SerializedPacket(0, PACKET_1BYTE_PACKET_NUMBER, nullptr, 0, false, + false); } void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { @@ -543,7 +540,6 @@ } else { header->public_header.nonce = nullptr; } - header->path_id = packet_.path_id; header->packet_number = ++packet_.packet_number; header->public_header.packet_number_length = packet_.packet_number_length; } @@ -600,6 +596,9 @@ if (frame.type == ACK_FRAME) { packet_.has_ack = true; + if (latched_flag_no_stop_waiting_frames_) { + packet_.largest_acked = frame.ack_frame->largest_observed; + } } if (frame.type == STOP_WAITING_FRAME) { packet_.has_stop_waiting = true;
diff --git a/net/quic/core/quic_packet_creator.h b/net/quic/core/quic_packet_creator.h index f7bce4e..f73f7c13 100644 --- a/net/quic/core/quic_packet_creator.h +++ b/net/quic/core/quic_packet_creator.h
@@ -209,6 +209,10 @@ debug_delegate_ = debug_delegate; } + bool latched_flag_no_stop_waiting_frames() const { + return latched_flag_no_stop_waiting_frames_; + } + private: friend class test::QuicPacketCreatorPeer; @@ -299,8 +303,8 @@ // Packet used to invoke OnSerializedPacket. SerializedPacket packet_; - // Map mapping path_id to last sent packet number on the path. - std::unordered_map<QuicPathId, QuicPacketNumber> multipath_packet_number_; + // The latched value of FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames + bool latched_flag_no_stop_waiting_frames_; DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator); };
diff --git a/net/quic/core/quic_packet_creator_test.cc b/net/quic/core/quic_packet_creator_test.cc index 69439d3..1934414 100644 --- a/net/quic/core/quic_packet_creator_test.cc +++ b/net/quic/core/quic_packet_creator_test.cc
@@ -753,7 +753,7 @@ creator_.BytesFree()); // Add a variety of frame types and then a padding frame. - QuicAckFrame ack_frame(MakeAckFrame(0u)); + QuicAckFrame ack_frame(MakeAckFrame(10u)); EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(&ack_frame))); EXPECT_TRUE(creator_.HasPendingFrames()); @@ -783,6 +783,10 @@ ASSERT_EQ(1u, retransmittable.size()); EXPECT_EQ(STREAM_FRAME, retransmittable[0].type); ASSERT_TRUE(retransmittable[0].stream_frame); + EXPECT_TRUE(serialized_packet_.has_ack); + if (FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames) { + EXPECT_EQ(10u, serialized_packet_.largest_acked); + } DeleteSerializedPacket(); EXPECT_FALSE(creator_.HasPendingFrames());
diff --git a/net/quic/core/quic_packet_generator.h b/net/quic/core/quic_packet_generator.h index 5821aad..676691c 100644 --- a/net/quic/core/quic_packet_generator.h +++ b/net/quic/core/quic_packet_generator.h
@@ -176,6 +176,10 @@ packet_creator_.set_debug_delegate(debug_delegate); } + bool latched_flag_no_stop_waiting_frames() const { + return packet_creator_.latched_flag_no_stop_waiting_frames(); + } + private: friend class test::QuicPacketGeneratorPeer;
diff --git a/net/quic/core/quic_packets.cc b/net/quic/core/quic_packets.cc index a88b6e8..a5c44105 100644 --- a/net/quic/core/quic_packets.cc +++ b/net/quic/core/quic_packets.cc
@@ -64,11 +64,10 @@ QuicPacketPublicHeader::~QuicPacketPublicHeader() {} -QuicPacketHeader::QuicPacketHeader() - : packet_number(0), path_id(kDefaultPathId) {} +QuicPacketHeader::QuicPacketHeader() : packet_number(0) {} QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header) - : public_header(header), packet_number(0), path_id(kDefaultPathId) {} + : public_header(header), packet_number(0) {} QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default; @@ -98,8 +97,7 @@ StringPiece(header.public_header.nonce->data(), header.public_header.nonce->size())); } - os << ", path_id: " << static_cast<int>(header.path_id) - << ", packet_number: " << header.packet_number << " }\n"; + os << ", packet_number: " << header.packet_number << " }\n"; return os; } @@ -200,8 +198,7 @@ length() - start_of_encrypted_data); } -SerializedPacket::SerializedPacket(QuicPathId path_id, - QuicPacketNumber packet_number, +SerializedPacket::SerializedPacket(QuicPacketNumber packet_number, QuicPacketNumberLength packet_number_length, const char* encrypted_buffer, QuicPacketLength encrypted_length, @@ -211,14 +208,14 @@ encrypted_length(encrypted_length), has_crypto_handshake(NOT_HANDSHAKE), num_padding_bytes(0), - path_id(path_id), packet_number(packet_number), packet_number_length(packet_number_length), encryption_level(ENCRYPTION_NONE), has_ack(has_ack), has_stop_waiting(has_stop_waiting), transmission_type(NOT_RETRANSMISSION), - original_packet_number(0) {} + original_packet_number(0), + largest_acked(0) {} SerializedPacket::SerializedPacket(const SerializedPacket& other) = default; @@ -230,6 +227,7 @@ } serialized_packet->encrypted_buffer = nullptr; serialized_packet->encrypted_length = 0; + serialized_packet->largest_acked = 0; } char* CopyBuffer(const SerializedPacket& packet) {
diff --git a/net/quic/core/quic_packets.h b/net/quic/core/quic_packets.h index 5f2d863..80398e0 100644 --- a/net/quic/core/quic_packets.h +++ b/net/quic/core/quic_packets.h
@@ -86,7 +86,6 @@ QuicPacketPublicHeader public_header; QuicPacketNumber packet_number; - QuicPathId path_id; }; struct QUIC_EXPORT_PRIVATE QuicPublicResetPacket { @@ -212,8 +211,7 @@ }; struct QUIC_EXPORT_PRIVATE SerializedPacket { - SerializedPacket(QuicPathId path_id, - QuicPacketNumber packet_number, + SerializedPacket(QuicPacketNumber packet_number, QuicPacketNumberLength packet_number_length, const char* encrypted_buffer, QuicPacketLength encrypted_length, @@ -231,7 +229,6 @@ // 0: no padding // otherwise: only pad up to num_padding_bytes bytes int16_t num_padding_bytes; - QuicPathId path_id; QuicPacketNumber packet_number; QuicPacketNumberLength packet_number_length; EncryptionLevel encryption_level; @@ -239,6 +236,9 @@ bool has_stop_waiting; TransmissionType transmission_type; QuicPacketNumber original_packet_number; + // The largest acked of the AckFrame in this packet if has_ack is true, + // 0 otherwise. + QuicPacketNumber largest_acked; // Optional notifiers which will be informed when this packet has been ACKed. std::list<AckListenerWrapper> listeners;
diff --git a/net/quic/core/quic_received_packet_manager.cc b/net/quic/core/quic_received_packet_manager.cc index 668301d..2c4ae8f 100644 --- a/net/quic/core/quic_received_packet_manager.cc +++ b/net/quic/core/quic_received_packet_manager.cc
@@ -26,6 +26,7 @@ QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats) : peer_least_packet_awaiting_ack_(0), ack_frame_updated_(false), + max_ack_ranges_(0), time_largest_observed_(QuicTime::Zero()), stats_(stats) { ack_frame_.largest_observed = 0; @@ -87,6 +88,10 @@ ? QuicTime::Delta::Zero() : approximate_now - time_largest_observed_; } + while (max_ack_ranges_ > 0 && + ack_frame_.packets.NumIntervals() > max_ack_ranges_) { + ack_frame_.packets.RemoveSmallestInterval(); + } // Clear all packet times if any are too far from largest observed. // It's expected this is extremely rare.
diff --git a/net/quic/core/quic_received_packet_manager.h b/net/quic/core/quic_received_packet_manager.h index 08001a8..4da4a1e0 100644 --- a/net/quic/core/quic_received_packet_manager.h +++ b/net/quic/core/quic_received_packet_manager.h
@@ -65,6 +65,10 @@ // For logging purposes. const QuicAckFrame& ack_frame() const { return ack_frame_; } + void set_max_ack_ranges(size_t max_ack_ranges) { + max_ack_ranges_ = max_ack_ranges; + } + private: friend class test::QuicConnectionPeer; @@ -79,6 +83,9 @@ // last called. bool ack_frame_updated_; + // Maximum number of ack ranges allowed to be stored in the ack frame. + size_t max_ack_ranges_; + // The time we received the largest_observed packet number, or zero if // no packet numbers have been received since UpdateReceivedPacketInfo. // Needed for calculating ack_delay_time.
diff --git a/net/quic/core/quic_received_packet_manager_test.cc b/net/quic/core/quic_received_packet_manager_test.cc index e7ff3d3..2f2c7a7 100644 --- a/net/quic/core/quic_received_packet_manager_test.cc +++ b/net/quic/core/quic_received_packet_manager_test.cc
@@ -124,6 +124,23 @@ EXPECT_EQ(1u, stats_.packets_reordered); } +TEST_P(QuicReceivedPacketManagerTest, LimitAckRanges) { + received_manager_.set_max_ack_ranges(10); + EXPECT_FALSE(received_manager_.ack_frame_updated()); + for (int i = 0; i < 100; ++i) { + RecordPacketReceipt(1 + 2 * i); + EXPECT_TRUE(received_manager_.ack_frame_updated()); + received_manager_.GetUpdatedAckFrame(QuicTime::Zero()); + EXPECT_GE(10u, received_manager_.ack_frame().packets.NumIntervals()); + EXPECT_EQ(1u + 2 * i, received_manager_.ack_frame().packets.Max()); + for (int j = 0; j < std::min(10, i + 1); ++j) { + EXPECT_TRUE( + received_manager_.ack_frame().packets.Contains(1 + (i - j) * 2)); + EXPECT_FALSE(received_manager_.ack_frame().packets.Contains((i - j) * 2)); + } + } +} + } // namespace } // namespace test } // namespace net
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc index 3b601e25..b88e532 100644 --- a/net/quic/core/quic_sent_packet_manager.cc +++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -83,7 +83,8 @@ conservative_handshake_retransmits_(false), largest_newly_acked_(0), largest_mtu_acked_(0), - handshake_confirmed_(false) { + handshake_confirmed_(false), + largest_packet_peer_knows_is_acked_(0) { SetSendAlgorithm(congestion_control_type); } @@ -104,40 +105,18 @@ config.GetInitialRoundTripTimeUsToSend()))); } // Configure congestion control. - const bool enable_client_connection_options = - FLAGS_quic_reloadable_flag_quic_client_connection_options; - if (enable_client_connection_options) { - if (FLAGS_quic_reloadable_flag_quic_allow_new_bbr && - config.HasClientRequestedIndependentOption(kTBBR, perspective_)) { - SetSendAlgorithm(kBBR); + if (FLAGS_quic_reloadable_flag_quic_allow_new_bbr && + config.HasClientRequestedIndependentOption(kTBBR, perspective_)) { + SetSendAlgorithm(kBBR); + } + if (config.HasClientRequestedIndependentOption(kRENO, perspective_)) { + if (config.HasClientRequestedIndependentOption(kBYTE, perspective_)) { + SetSendAlgorithm(kRenoBytes); + } else { + SetSendAlgorithm(kReno); } - if (config.HasClientRequestedIndependentOption(kRENO, perspective_)) { - if (config.HasClientRequestedIndependentOption(kBYTE, perspective_)) { - SetSendAlgorithm(kRenoBytes); - } else { - SetSendAlgorithm(kReno); - } - } else if (config.HasClientRequestedIndependentOption(kBYTE, - perspective_)) { - SetSendAlgorithm(kCubic); - } - } else { - if (FLAGS_quic_reloadable_flag_quic_allow_new_bbr && - config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kTBBR)) { - SetSendAlgorithm(kBBR); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) { - if (ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) { - SetSendAlgorithm(kRenoBytes); - } else { - SetSendAlgorithm(kReno); - } - } else if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kBYTE)) { - SetSendAlgorithm(kCubic); - } + } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective_)) { + SetSendAlgorithm(kCubic); } using_pacing_ = !FLAGS_quic_disable_pacing_for_perf_tests; @@ -157,37 +136,19 @@ use_new_rto_ = true; } // Configure loss detection. - if (enable_client_connection_options) { - if (config.HasClientRequestedIndependentOption(kTIME, perspective_)) { - general_loss_algorithm_.SetLossDetectionType(kTime); - } - if (config.HasClientRequestedIndependentOption(kATIM, perspective_)) { - general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime); - } - if (FLAGS_quic_reloadable_flag_quic_enable_lazy_fack && - config.HasClientRequestedIndependentOption(kLFAK, perspective_)) { - general_loss_algorithm_.SetLossDetectionType(kLazyFack); - } - } else { - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kTIME)) { - general_loss_algorithm_.SetLossDetectionType(kTime); - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kATIM)) { - general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime); - } - if (FLAGS_quic_reloadable_flag_quic_enable_lazy_fack && - config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kLFAK)) { - general_loss_algorithm_.SetLossDetectionType(kLazyFack); - } + if (config.HasClientRequestedIndependentOption(kTIME, perspective_)) { + general_loss_algorithm_.SetLossDetectionType(kTime); + } + if (config.HasClientRequestedIndependentOption(kATIM, perspective_)) { + general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime); + } + if (config.HasClientRequestedIndependentOption(kLFAK, perspective_)) { + general_loss_algorithm_.SetLossDetectionType(kLazyFack); } if (config.HasClientSentConnectionOption(kUNDO, perspective_)) { undo_pending_retransmits_ = true; } - if (FLAGS_quic_reloadable_flag_quic_conservative_handshake_retransmits && - config.HasClientSentConnectionOption(kCONH, perspective_)) { + if (config.HasClientSentConnectionOption(kCONH, perspective_)) { conservative_handshake_retransmits_ = true; } send_algorithm_->SetFromConfig(config, perspective_); @@ -339,6 +300,10 @@ } // Packet was acked, so remove it from our unacked packet list. QUIC_DVLOG(1) << ENDPOINT << "Got an ack for packet " << packet_number; + if (it->largest_acked > 0) { + largest_packet_peer_knows_is_acked_ = + std::max(largest_packet_peer_knows_is_acked_, it->largest_acked); + } // If data is associated with the most recent transmission of this // packet, then inform the caller. if (it->in_flight) { @@ -741,18 +706,6 @@ } QuicTime::Delta send_delta = ack_receive_time - transmission_info.sent_time; - const int kMaxSendDeltaSeconds = 30; - if (!FLAGS_quic_reloadable_flag_quic_allow_large_send_deltas && - send_delta.ToSeconds() > kMaxSendDeltaSeconds) { - // send_delta can be very high if local clock is changed mid-connection. - QUIC_LOG_FIRST_N(WARNING, 10) - << "Excessive send delta: " << send_delta.ToSeconds() - << ", setting to: " << kMaxSendDeltaSeconds - << " largest_observed:" << ack_frame.largest_observed - << " ack_receive_time:" << ack_receive_time.ToDebuggingValue() - << " sent_time:" << transmission_info.sent_time.ToDebuggingValue(); - return false; - } rtt_stats_.UpdateRtt(send_delta, ack_frame.ack_delay_time, ack_receive_time); return true;
diff --git a/net/quic/core/quic_sent_packet_manager.h b/net/quic/core/quic_sent_packet_manager.h index c135b2f9..e2af107 100644 --- a/net/quic/core/quic_sent_packet_manager.h +++ b/net/quic/core/quic_sent_packet_manager.h
@@ -79,8 +79,6 @@ // Called with the path may be degrading. Note that the path may only be // temporarily degrading. - // TODO(jri): With multipath, this method should probably have a path_id - // parameter, and should maybe result in the path being marked as inactive. virtual void OnPathDegrading() = 0; // Called when the Path MTU may have increased. @@ -222,6 +220,10 @@ const SendAlgorithmInterface* GetSendAlgorithm() const; + QuicPacketNumber largest_packet_peer_knows_is_acked() const { + return largest_packet_peer_knows_is_acked_; + } + private: friend class test::QuicConnectionPeer; friend class test::QuicSentPacketManagerPeer; @@ -402,6 +404,9 @@ // of time with no loss events. QuicSustainedBandwidthRecorder sustained_bandwidth_recorder_; + // The largest acked value that was sent in an ack, which has then been acked. + QuicPacketNumber largest_packet_peer_knows_is_acked_; + DISALLOW_COPY_AND_ASSIGN(QuicSentPacketManager); };
diff --git a/net/quic/core/quic_sent_packet_manager_test.cc b/net/quic/core/quic_sent_packet_manager_test.cc index b0f4c34..ac47ba6 100644 --- a/net/quic/core/quic_sent_packet_manager_test.cc +++ b/net/quic/core/quic_sent_packet_manager_test.cc
@@ -28,7 +28,6 @@ namespace net { namespace test { namespace { - // Default packet length. const uint32_t kDefaultLength = 1000; @@ -192,9 +191,8 @@ SerializedPacket CreatePacket(QuicPacketNumber packet_number, bool retransmittable) { - SerializedPacket packet(kDefaultPathId, packet_number, - PACKET_6BYTE_PACKET_NUMBER, nullptr, kDefaultLength, - false, false); + SerializedPacket packet(packet_number, PACKET_6BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, false, false); if (retransmittable) { packet.retransmittable_frames.push_back( QuicFrame(new QuicStreamFrame(kStreamId, false, 0, StringPiece()))); @@ -226,13 +224,15 @@ HAS_RETRANSMITTABLE_DATA); } - void SendAckPacket(QuicPacketNumber packet_number) { + void SendAckPacket(QuicPacketNumber packet_number, + QuicPacketNumber largest_acked) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, NO_RETRANSMITTABLE_DATA)) .Times(1) .WillOnce(Return(false)); SerializedPacket packet(CreatePacket(packet_number, false)); + packet.largest_acked = largest_acked; manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA); } @@ -536,8 +536,10 @@ } TEST_F(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { + FLAGS_quic_reloadable_flag_quic_no_stop_waiting_frames = true; + EXPECT_EQ(0u, manager_.largest_packet_peer_knows_is_acked()); SendDataPacket(1); - SendAckPacket(2); + SendAckPacket(2, 1); // Now ack the ack and expect an RTT update. QuicAckFrame ack_frame = InitAckFrame(2); @@ -545,13 +547,15 @@ ExpectAck(1); manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_EQ(1u, manager_.largest_packet_peer_knows_is_acked()); - SendAckPacket(3); + SendAckPacket(3, 3); // Now ack the ack and expect only an RTT update. ack_frame = InitAckFrame(3); ExpectUpdatedRtt(3); manager_.OnIncomingAck(ack_frame, clock_.Now()); + EXPECT_EQ(3u, manager_.largest_packet_peer_knows_is_acked()); } TEST_F(QuicSentPacketManagerTest, Rtt) { @@ -1109,7 +1113,6 @@ TEST_F(QuicSentPacketManagerTest, GetConservativeTransmissionTimeCryptoHandshake) { - FLAGS_quic_reloadable_flag_quic_conservative_handshake_retransmits = true; QuicConfig config; QuicTagVector options; options.push_back(kCONH); @@ -1403,7 +1406,6 @@ TEST_F(QuicSentPacketManagerTest, NegotiateClientCongestionControlFromOptions) { FLAGS_quic_reloadable_flag_quic_allow_new_bbr = true; - FLAGS_quic_reloadable_flag_quic_client_connection_options = true; QuicConfig config; QuicTagVector options; @@ -1718,8 +1720,8 @@ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), 1, _, _)) .Times(1) .WillOnce(Return(true)); - SerializedPacket packet(kDefaultPathId, 1, PACKET_6BYTE_PACKET_NUMBER, - nullptr, kDefaultLength + 100, false, false); + SerializedPacket packet(1, PACKET_6BYTE_PACKET_NUMBER, nullptr, + kDefaultLength + 100, false, false); manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
diff --git a/net/quic/core/quic_server_session_base_test.cc b/net/quic/core/quic_server_session_base_test.cc index 6e18cd5..9348fdfd 100644 --- a/net/quic/core/quic_server_session_base_test.cc +++ b/net/quic/core/quic_server_session_base_test.cc
@@ -474,9 +474,9 @@ // Bandwidth estimate has now changed sufficiently, enough time has passed, // and enough packets have been sent. - SerializedPacket packet( - kDefaultPathId, 1 + kMinPacketsBetweenServerConfigUpdates, - PACKET_6BYTE_PACKET_NUMBER, nullptr, 1000, false, false); + SerializedPacket packet(1 + kMinPacketsBetweenServerConfigUpdates, + PACKET_6BYTE_PACKET_NUMBER, nullptr, 1000, false, + false); sent_packet_manager->OnPacketSent(&packet, 0, now, NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); @@ -613,7 +613,7 @@ chlo.SetVector(kCOPT, QuicTagVector{kSREJ}); std::vector<QuicVersion> packet_version_list = {version}; std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( - 1, true, false, false, kDefaultPathId, 1, + 1, true, false, false, 1, chlo.GetSerialized().AsStringPiece().as_string(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &packet_version_list));
diff --git a/net/quic/core/quic_stream_sequencer_buffer.cc b/net/quic/core/quic_stream_sequencer_buffer.cc index 210bf56bd..b4d2736 100644 --- a/net/quic/core/quic_stream_sequencer_buffer.cc +++ b/net/quic/core/quic_stream_sequencer_buffer.cc
@@ -38,11 +38,7 @@ blocks_count_( ceil(static_cast<double>(max_capacity_bytes) / kBlockSizeBytes)), total_bytes_read_(0), - reduce_sequencer_buffer_memory_life_time_( - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time), // NOLINT - blocks_(reduce_sequencer_buffer_memory_life_time_ - ? nullptr - : new BufferBlock*[blocks_count_]()), + blocks_(nullptr), destruction_indicator_(123456) { CHECK_GT(blocks_count_, 1u) << "blocks_count_ = " << blocks_count_ @@ -56,7 +52,7 @@ } void QuicStreamSequencerBuffer::Clear() { - if (!reduce_sequencer_buffer_memory_life_time_ || blocks_ != nullptr) { + if (blocks_ != nullptr) { for (size_t i = 0; i < blocks_count_; ++i) { if (blocks_[i] != nullptr) { RetireBlock(i); @@ -175,7 +171,7 @@ bytes_avail = total_bytes_read_ + max_buffer_capacity_bytes_ - offset; } - if (reduce_sequencer_buffer_memory_life_time_ && blocks_ == nullptr) { + if (blocks_ == nullptr) { blocks_.reset(new BufferBlock*[blocks_count_]()); for (size_t i = 0; i < blocks_count_; ++i) { blocks_[i] = nullptr; @@ -464,10 +460,6 @@ } void QuicStreamSequencerBuffer::ReleaseWholeBuffer() { - if (!reduce_sequencer_buffer_memory_life_time_) { - // Don't release buffer if flag is off. - return; - } Clear(); blocks_.reset(nullptr); }
diff --git a/net/quic/core/quic_stream_sequencer_buffer.h b/net/quic/core/quic_stream_sequencer_buffer.h index 14d1014..bd57ac9 100644 --- a/net/quic/core/quic_stream_sequencer_buffer.h +++ b/net/quic/core/quic_stream_sequencer_buffer.h
@@ -166,10 +166,6 @@ // Count how many bytes are in buffer at this moment. size_t BytesBuffered() const; - bool reduce_sequencer_buffer_memory_life_time() const { - return reduce_sequencer_buffer_memory_life_time_; - } - private: friend class test::QuicStreamSequencerBufferPeer; @@ -237,10 +233,6 @@ // Contains Gaps which represents currently missing data. std::list<Gap> gaps_; - // If true, allocate buffer memory upon the first frame arrival and release - // the memory when stream is read closed. - bool reduce_sequencer_buffer_memory_life_time_; - // An ordered, variable-length list of blocks, with the length limited // such that the number of blocks never exceeds blocks_count_. // Each list entry can hold up to kBlockSizeBytes bytes.
diff --git a/net/quic/core/quic_stream_sequencer_buffer_test.cc b/net/quic/core/quic_stream_sequencer_buffer_test.cc index e3be181..1bf04cd 100644 --- a/net/quic/core/quic_stream_sequencer_buffer_test.cc +++ b/net/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -111,9 +111,7 @@ } TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithinBlock) { - if (FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time) { // NOLINT - EXPECT_FALSE(helper_->IsBufferAllocated()); - } + EXPECT_FALSE(helper_->IsBufferAllocated()); string source(1024, 'a'); size_t written; clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -472,11 +470,6 @@ TEST_F(QuicStreamSequencerBufferTest, ReleaseWholeBuffer) { // Tests that buffer is not deallocated unless ReleaseWholeBuffer() is called. - if (!FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time) { // NOLINT - // Won't release buffer when flag is off. - return; - } - string source(100, 'b'); clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); QuicTime t1 = clock_.ApproximateNow();
diff --git a/net/quic/core/quic_transmission_info.cc b/net/quic/core/quic_transmission_info.cc index 96cbfd24..d5654328 100644 --- a/net/quic/core/quic_transmission_info.cc +++ b/net/quic/core/quic_transmission_info.cc
@@ -16,7 +16,8 @@ is_unackable(false), has_crypto_handshake(false), num_padding_bytes(0), - retransmission(0) {} + retransmission(0), + largest_acked(0) {} QuicTransmissionInfo::QuicTransmissionInfo( EncryptionLevel level, @@ -35,7 +36,8 @@ is_unackable(false), has_crypto_handshake(has_crypto_handshake), num_padding_bytes(num_padding_bytes), - retransmission(0) {} + retransmission(0), + largest_acked(0) {} QuicTransmissionInfo::QuicTransmissionInfo(const QuicTransmissionInfo& other) = default;
diff --git a/net/quic/core/quic_transmission_info.h b/net/quic/core/quic_transmission_info.h index cce790e..6529f4e 100644 --- a/net/quic/core/quic_transmission_info.h +++ b/net/quic/core/quic_transmission_info.h
@@ -55,6 +55,8 @@ QuicPacketNumber retransmission; // Non-empty if there is a listener for this packet. std::list<AckListenerWrapper> ack_listeners; + // The largest_acked in the ack frame, if the packet contains an ack. + QuicPacketNumber largest_acked; }; } // namespace net
diff --git a/net/quic/core/quic_unacked_packet_map.cc b/net/quic/core/quic_unacked_packet_map.cc index 62a687c7..8c5fbf1 100644 --- a/net/quic/core/quic_unacked_packet_map.cc +++ b/net/quic/core/quic_unacked_packet_map.cc
@@ -43,6 +43,7 @@ QuicTransmissionInfo info( packet->encryption_level, packet->packet_number_length, transmission_type, sent_time, bytes_sent, has_crypto_handshake, packet->num_padding_bytes); + info.largest_acked = packet->largest_acked; if (old_packet_number > 0) { TransferRetransmissionInfo(old_packet_number, packet_number, transmission_type, &info);
diff --git a/net/quic/core/quic_unacked_packet_map_test.cc b/net/quic/core/quic_unacked_packet_map_test.cc index 443cae6..29c75bb 100644 --- a/net/quic/core/quic_unacked_packet_map_test.cc +++ b/net/quic/core/quic_unacked_packet_map_test.cc
@@ -30,9 +30,8 @@ SerializedPacket CreateRetransmittablePacketForStream( QuicPacketNumber packet_number, QuicStreamId stream_id) { - SerializedPacket packet(kDefaultPathId, packet_number, - PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, - false, false); + SerializedPacket packet(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, false, false); QuicStreamFrame* frame = new QuicStreamFrame(); frame->stream_id = stream_id; packet.retransmittable_frames.push_back(QuicFrame(frame)); @@ -41,9 +40,8 @@ SerializedPacket CreateNonRetransmittablePacket( QuicPacketNumber packet_number) { - return SerializedPacket(kDefaultPathId, packet_number, - PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, - false, false); + return SerializedPacket(packet_number, PACKET_1BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, false, false); } void VerifyInFlightPackets(QuicPacketNumber* packets, size_t num_packets) {
diff --git a/net/quic/core/quic_utils.cc b/net/quic/core/quic_utils.cc index 861ee3d6..0667768 100644 --- a/net/quic/core/quic_utils.cc +++ b/net/quic/core/quic_utils.cc
@@ -176,21 +176,6 @@ } // static -uint64_t QuicUtils::PackPathIdAndPacketNumber(QuicPathId path_id, - QuicPacketNumber packet_number) { - // Setting the nonce below relies on QuicPathId and QuicPacketNumber being - // specific sizes. - static_assert(sizeof(path_id) == 1, "Size of QuicPathId changed."); - static_assert(sizeof(packet_number) == 8, - "Size of QuicPacketNumber changed."); - // Use path_id and lower 7 bytes of packet_number as lower 8 bytes of nonce. - uint64_t path_id_packet_number = - (static_cast<uint64_t>(path_id) << 56) | packet_number; - DCHECK(path_id != kDefaultPathId || path_id_packet_number == packet_number); - return path_id_packet_number; -} - -// static PeerAddressChangeType QuicUtils::DetermineAddressChangeType( const QuicSocketAddress& old_address, const QuicSocketAddress& new_address) {
diff --git a/net/quic/core/quic_utils.h b/net/quic/core/quic_utils.h index c32e865..fe504551 100644 --- a/net/quic/core/quic_utils.h +++ b/net/quic/core/quic_utils.h
@@ -53,12 +53,6 @@ // Returns PeerAddressChangeType as a std::string. static std::string PeerAddressChangeTypeToString(PeerAddressChangeType type); - // Returns a packed representation of |path_id| and |packet_number| in which - // the highest byte is set to |path_id| and the lower 7 bytes are the lower - // 7 bytes of |packet_number|. - static uint64_t PackPathIdAndPacketNumber(QuicPathId path_id, - QuicPacketNumber packet_number); - // Determines and returns change type of address change from |old_address| to // |new_address|. static PeerAddressChangeType DetermineAddressChangeType(
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index 8c2e195..454bcb8 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -252,11 +252,16 @@ // static bool QuicConnectionPeer::HasRetransmittableFrames( QuicConnection* connection, - QuicPathId path_id, QuicPacketNumber packet_number) { return QuicSentPacketManagerPeer::HasRetransmittableFrames( GetSentPacketManager(connection), packet_number); } +// static +void QuicConnectionPeer::SetNoStopWaitingFrames(QuicConnection* connection, + bool no_stop_waiting_frames) { + connection->no_stop_waiting_frames_ = no_stop_waiting_frames; +} + } // namespace test } // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 64e0685..347f21b3 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h
@@ -113,8 +113,9 @@ static void SetAckDecimationDelay(QuicConnection* connection, float ack_decimation_delay); static bool HasRetransmittableFrames(QuicConnection* connection, - QuicPathId path_id, QuicPacketNumber packet_number); + static void SetNoStopWaitingFrames(QuicConnection* connection, + bool no_stop_waiting_frames); private: DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
diff --git a/net/quic/test_tools/quic_packet_creator_peer.cc b/net/quic/test_tools/quic_packet_creator_peer.cc index 840eec8..e8788d6 100644 --- a/net/quic/test_tools/quic_packet_creator_peer.cc +++ b/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -82,10 +82,5 @@ return creator->packet_.encryption_level; } -// static -QuicPathId QuicPacketCreatorPeer::GetCurrentPath(QuicPacketCreator* creator) { - return creator->packet_.path_id; -} - } // namespace test } // namespace net
diff --git a/net/quic/test_tools/quic_packet_creator_peer.h b/net/quic/test_tools/quic_packet_creator_peer.h index 5c190918..c798cb1 100644 --- a/net/quic/test_tools/quic_packet_creator_peer.h +++ b/net/quic/test_tools/quic_packet_creator_peer.h
@@ -40,7 +40,6 @@ char* buffer, size_t buffer_len); static EncryptionLevel GetEncryptionLevel(QuicPacketCreator* creator); - static QuicPathId GetCurrentPath(QuicPacketCreator* creator); private: DISALLOW_COPY_AND_ASSIGN(QuicPacketCreatorPeer);
diff --git a/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc b/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc index e7f38b2..a759104 100644 --- a/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc +++ b/net/quic/test_tools/quic_stream_sequencer_buffer_peer.cc
@@ -42,8 +42,7 @@ } bool QuicStreamSequencerBufferPeer::IsBlockArrayEmpty() { - if (FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time && // NOLINT - buffer_->blocks_ == nullptr) { + if (buffer_->blocks_ == nullptr) { return true; }
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 6f9ab7e..7c9fb11 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -557,13 +557,11 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const string& data) { - return ConstructEncryptedPacket(connection_id, version_flag, multipath_flag, - reset_flag, path_id, packet_number, data, - PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER); + return ConstructEncryptedPacket( + connection_id, version_flag, multipath_flag, reset_flag, packet_number, + data, PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER); } QuicEncryptedPacket* ConstructEncryptedPacket( @@ -571,14 +569,13 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length) { return ConstructEncryptedPacket( - connection_id, version_flag, multipath_flag, reset_flag, path_id, - packet_number, data, connection_id_length, packet_number_length, nullptr); + connection_id, version_flag, multipath_flag, reset_flag, packet_number, + data, connection_id_length, packet_number_length, nullptr); } QuicEncryptedPacket* ConstructEncryptedPacket( @@ -586,14 +583,13 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, QuicVersionVector* versions) { return ConstructEncryptedPacket(connection_id, version_flag, multipath_flag, - reset_flag, path_id, packet_number, data, + reset_flag, packet_number, data, connection_id_length, packet_number_length, versions, Perspective::IS_CLIENT); } @@ -602,7 +598,6 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const string& data, QuicConnectionIdLength connection_id_length, @@ -616,7 +611,6 @@ header.public_header.multipath_flag = multipath_flag; header.public_header.reset_flag = reset_flag; header.public_header.packet_number_length = packet_number_length; - header.path_id = path_id; header.packet_number = packet_number; QuicStreamFrame stream_frame(1, false, 0, StringPiece(data)); QuicFrame frame(&stream_frame); @@ -649,7 +643,6 @@ QuicConnectionId connection_id, bool version_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const string& data, QuicConnectionIdLength connection_id_length, @@ -662,7 +655,6 @@ header.public_header.version_flag = version_flag; header.public_header.reset_flag = reset_flag; header.public_header.packet_number_length = packet_number_length; - header.path_id = path_id; header.packet_number = packet_number; QuicStreamFrame stream_frame(1, false, 0, StringPiece(data)); QuicFrame frame(&stream_frame);
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index 5b53b4a6..d404341 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -74,7 +74,6 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const std::string& data, QuicConnectionIdLength connection_id_length, @@ -91,7 +90,6 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const std::string& data, QuicConnectionIdLength connection_id_length, @@ -104,7 +102,6 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const std::string& data, QuicConnectionIdLength connection_id_length, @@ -117,7 +114,6 @@ bool version_flag, bool multipath_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const std::string& data); @@ -136,7 +132,6 @@ QuicConnectionId connection_id, bool version_flag, bool reset_flag, - QuicPathId path_id, QuicPacketNumber packet_number, const std::string& data, QuicConnectionIdLength connection_id_length,
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 93ed695..6f12b97 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -598,20 +598,16 @@ QuicCryptoStream* crypto_stream = QuicSessionPeer::GetCryptoStream(client_->client()->session()); QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(crypto_stream); - EXPECT_NE( - FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer && - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time, // NOLINT - QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + EXPECT_NE(FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer, + QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); server_thread_->Pause(); QuicDispatcher* dispatcher = QuicServerPeer::GetDispatcher(server_thread_->server()); QuicSession* server_session = dispatcher->session_map().begin()->second.get(); crypto_stream = QuicSessionPeer::GetCryptoStream(server_session); sequencer = QuicStreamPeer::sequencer(crypto_stream); - EXPECT_NE( - FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer && - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time, // NOLINT - QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + EXPECT_NE(FLAGS_quic_reloadable_flag_quic_release_crypto_stream_buffer, + QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); } TEST_P(EndToEndTest, SimpleRequestResponsev6) { @@ -2213,8 +2209,8 @@ std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( client_->client()->session()->connection()->connection_id(), false, false, - false, kDefaultPathId, 1, "At least 20 characters.", - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER)); + false, 1, "At least 20 characters.", PACKET_8BYTE_CONNECTION_ID, + PACKET_6BYTE_PACKET_NUMBER)); // Damage the encrypted data. string damaged_packet(packet->data(), packet->length()); damaged_packet[30] ^= 0x01; @@ -2709,10 +2705,7 @@ QUIC_DVLOG(1) << "response body " << response_body; EXPECT_EQ(expected_body, response_body); } - EXPECT_NE( - FLAGS_quic_reloadable_flag_quic_headers_stream_release_sequencer_buffer && - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time, // NOLINT - QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); } TEST_P(EndToEndTestServerPush, ServerPushUnderLimit) { @@ -3017,10 +3010,7 @@ QuicHeadersStream* headers_stream = QuicSpdySessionPeer::GetHeadersStream(client_->client()->session()); QuicStreamSequencer* sequencer = QuicStreamPeer::sequencer(headers_stream); - EXPECT_NE( - FLAGS_quic_reloadable_flag_quic_headers_stream_release_sequencer_buffer && - FLAGS_quic_reloadable_flag_quic_reduce_sequencer_buffer_memory_life_time, // NOLINT - QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); + EXPECT_FALSE(QuicStreamSequencerPeer::IsUnderlyingBufferAllocated(sequencer)); } class EndToEndBufferedPacketsTest : public EndToEndTest {
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index b0cbb52..1ed9bd9b 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc
@@ -267,7 +267,7 @@ // Verify that a non-decryptable packet doesn't close the connection. QuicConnectionId connection_id = session_->connection()->connection_id(); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( - connection_id, false, false, false, kDefaultPathId, 100, "data", + connection_id, false, false, false, 100, "data", PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, nullptr, Perspective::IS_SERVER)); std::unique_ptr<QuicReceivedPacket> received( @@ -293,9 +293,8 @@ QuicConnectionId connection_id = session_->connection()->connection_id(); QuicVersionVector versions = {GetParam()}; std::unique_ptr<QuicEncryptedPacket> packet(ConstructMisFramedEncryptedPacket( - connection_id, false, false, kDefaultPathId, 100, "data", - PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, &versions, - Perspective::IS_SERVER)); + connection_id, false, false, 100, "data", PACKET_8BYTE_CONNECTION_ID, + PACKET_6BYTE_PACKET_NUMBER, &versions, Perspective::IS_SERVER)); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*packet, QuicTime::Zero())); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(1);
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 8470575..7aab02f 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -227,7 +227,7 @@ QuicPacketNumberLength packet_number_length) { ProcessPacket(client_address, connection_id, has_version_flag, has_multipath_flag, data, connection_id_length, - packet_number_length, kDefaultPathId, 1); + packet_number_length, 1); } // Process a packet using the first supported version. @@ -238,7 +238,6 @@ const string& data, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - QuicPathId path_id, QuicPacketNumber packet_number) { ProcessPacket(client_address, connection_id, has_version_flag, CurrentSupportedVersions().front(), data, @@ -256,7 +255,7 @@ QuicPacketNumber packet_number) { QuicVersionVector versions(SupportedVersions(version)); std::unique_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( - connection_id, has_version_flag, false, false, 0, packet_number, data, + connection_id, has_version_flag, false, false, packet_number, data, connection_id_length, packet_number_length, &versions)); std::unique_ptr<QuicReceivedPacket> received_packet( ConstructReceivedPacket(*packet, helper_.GetClock()->Now())); @@ -505,7 +504,6 @@ // connection. ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, - kDefaultPathId, QuicDispatcher::kMaxReasonableInitialPacketNumber); EXPECT_EQ(client_address, dispatcher_->current_client_address()); EXPECT_EQ(server_address_, dispatcher_->current_server_address()); @@ -528,7 +526,6 @@ // connection. ProcessPacket(client_address, connection_id, true, false, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, - kDefaultPathId, QuicDispatcher::kMaxReasonableInitialPacketNumber + 1); } @@ -1201,8 +1198,7 @@ for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) { ProcessPacket(client_address, conn_id, true, false, QuicStrCat("data packet ", i + 1), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId, - /*packet_number=*/i + 1); + PACKET_6BYTE_PACKET_NUMBER, /*packet_number=*/i + 1); } EXPECT_EQ(0u, dispatcher_->session_map().size()) << "No session should be created before CHLO arrives."; @@ -1256,7 +1252,6 @@ ProcessPacket(client_address, conn_id, true, false, QuicStrCat("data packet on connection ", i), PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, - kDefaultPathId, /*packet_number=*/2); } @@ -1331,8 +1326,7 @@ QuicConnectionId conn_id = 1; ProcessPacket(client_address, conn_id, true, false, QuicStrCat("data packet ", 2), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId, - /*packet_number=*/2); + PACKET_6BYTE_PACKET_NUMBER, /*packet_number=*/2); // When CHLO arrives, a new session should be created, and all packets // buffered should be delivered to the session. @@ -1366,8 +1360,7 @@ QuicConnectionId conn_id = 1; ProcessPacket(client_address, conn_id, true, false, QuicStrCat("data packet ", 2), PACKET_8BYTE_CONNECTION_ID, - PACKET_6BYTE_PACKET_NUMBER, kDefaultPathId, - /*packet_number=*/2); + PACKET_6BYTE_PACKET_NUMBER, /*packet_number=*/2); mock_helper_.AdvanceTime( QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)); @@ -1561,7 +1554,6 @@ QuicConnectionId conn_id = 1; ProcessPacket(client_addr_, conn_id, true, false, "data packet", PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, - kDefaultPathId, /*packet_number=*/1); // Fill packet buffer to full with CHLOs on other connections. Need to feed // extra CHLOs because the first |kMaxNumSessionsToCreate| are going to create
diff --git a/net/tools/quic/quic_packet_writer_wrapper.h b/net/tools/quic/quic_packet_writer_wrapper.h index 4fc75c6..50cc547 100644 --- a/net/tools/quic/quic_packet_writer_wrapper.h +++ b/net/tools/quic/quic_packet_writer_wrapper.h
@@ -38,6 +38,8 @@ // Takes ownership of |writer|. void set_writer(QuicPacketWriter* writer); + virtual void set_peer_address(const QuicSocketAddress& peer_address) {} + private: std::unique_ptr<QuicPacketWriter> writer_;
diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc index 47097a6..132720c 100644 --- a/net/tools/quic/quic_spdy_client_stream.cc +++ b/net/tools/quic/quic_spdy_client_stream.cc
@@ -62,8 +62,7 @@ return; } - if (FLAGS_quic_restart_flag_quic_supports_100_continue && - response_code_ == 100 && !has_preliminary_headers_) { + if (response_code_ == 100 && !has_preliminary_headers_) { // These are preliminary 100 Continue headers, not the actual response // headers. set_headers_decompressed(false);
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc index 915d539..8ac3680 100644 --- a/net/tools/quic/quic_spdy_client_stream_test.cc +++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -111,7 +111,6 @@ TEST_F(QuicSpdyClientStreamTest, TestFraming100Continue) { headers_[":status"] = "100"; - FLAGS_quic_restart_flag_quic_supports_100_continue = true; auto headers = AsHeaderList(headers_); stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), headers); @@ -123,20 +122,6 @@ EXPECT_EQ("", stream_->data()); } -TEST_F(QuicSpdyClientStreamTest, TestFraming100ContinueNoFlag) { - headers_[":status"] = "100"; - FLAGS_quic_restart_flag_quic_supports_100_continue = false; - auto headers = AsHeaderList(headers_); - stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(), - headers); - stream_->OnStreamFrame( - QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, body_)); - EXPECT_EQ(0u, stream_->preliminary_headers().size()); - EXPECT_EQ("100", stream_->response_headers().find(":status")->second); - EXPECT_EQ(100, stream_->response_code()); - EXPECT_EQ(body_, stream_->data()); -} - TEST_F(QuicSpdyClientStreamTest, TestFramingOnePacket) { auto headers = AsHeaderList(headers_); stream_->OnStreamHeaderList(false, headers.uncompressed_header_bytes(),
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index da49cfc3..1b6039a 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -15,7 +15,6 @@ #include "net/quic/core/quic_flags.h" #include "net/quic/core/quic_framer.h" #include "net/quic/core/quic_packets.h" -#include "net/quic/core/quic_server_session_base.h" #include "net/quic/core/quic_utils.h" #include "net/quic/platform/api/quic_clock.h" #include "net/quic/platform/api/quic_logging.h"
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc index a870e30..78fb04d 100644 --- a/net/tools/quic/quic_time_wait_list_manager_test.cc +++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -125,8 +125,7 @@ QuicConnectionId connection_id, QuicPacketNumber packet_number) { return net::test::ConstructEncryptedPacket(connection_id, false, false, - false, kDefaultPathId, - packet_number, "data"); + false, packet_number, "data"); } QuicFlagSaver flags_; // Save/restore all QUIC flag values.
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index 56fe712..1aa3a82 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -194,6 +194,11 @@ override_connection_id_ = connection_id; } +void MockableQuicClient::set_peer_address(const QuicSocketAddress& address) { + CHECK(test_writer_ != nullptr); + test_writer_->set_peer_address(address); +} + QuicTestClient::QuicTestClient(QuicSocketAddress server_address, const string& server_hostname, const QuicVersionVector& supported_versions)
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 9066b59..90610228 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -63,6 +63,7 @@ void set_track_last_incoming_packet(bool track) { track_last_incoming_packet_ = track; } + void set_peer_address(const QuicSocketAddress& address); private: QuicConnectionId override_connection_id_; // ConnectionId to use, if nonzero @@ -247,6 +248,10 @@ client_->set_server_address(server_address); } + void set_peer_address(const QuicSocketAddress& address) { + client_->set_peer_address(address); + } + // Explicitly set the SNI value for this client, overriding the default // behavior which extracts the SNI value from the request URL. void OverrideSni(const std::string& sni) {
diff --git a/remoting/host/disconnect_window_chromeos.cc b/remoting/host/disconnect_window_chromeos.cc index 367bd58..bb4b8ff 100644 --- a/remoting/host/disconnect_window_chromeos.cc +++ b/remoting/host/disconnect_window_chromeos.cc
@@ -4,8 +4,8 @@ #include <string> +#include "ash/common/system/tray/system_tray_notifier.h" #include "ash/common/wm_shell.h" -#include "ash/system/tray/system_tray_notifier.h" #include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h"
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index a778bf0..38df11c 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -848,6 +848,8 @@ crbug.com/698135 external/wpt/editing/run/delete.html [ Crash Failure Timeout ] crbug.com/698165 external/wpt/editing/run/forwarddelete.html [ Pass Timeout ] crbug.com/698165 external/wpt/editing/run/justifycenter.html [ Pass Timeout ] +crbug.com/698165 external/wpt/editing/run/multitest.html [ Pass Timeout ] +crbug.com/698165 external/wpt/editing/run/removeformat.html [ Pass Timeout ] crbug.com/688613 external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html [ Skip ] @@ -2283,17 +2285,6 @@ crbug.com/508734 external/wpt/html/browsers/browsing-the-web/history-traversal/browsing_context_name_cross_origin_3.html [ Failure ] crbug.com/508734 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Pass Failure Timeout ] -crbug.com/686159 crypto/subtle/hkdf/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/aes-kw/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/aes-ctr/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/pbkdf2/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/aes-cbc/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/hmac/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/aes-gcm/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/rsassa-pkcs1-v1_5/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/ecdsa/cloneKey.html [ NeedsManualRebaseline ] -crbug.com/686159 crypto/subtle/ecdh/cloneKey.html [ NeedsManualRebaseline ] - # Fail differently when run with --enable-wptserve: (crbug.com/508728) crbug.com/508728 crbug.com/664268 external/wpt/html/browsers/history/the-location-interface/reload_post_1.html [ Failure Timeout ] crbug.com/508728 external/wpt/webstorage/document-domain.html [ Failure Timeout ]
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/cloneKey-expected.txt index aa954b3..79a4e55 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/aes-cbc/cloneKey-expected.txt
@@ -18,7 +18,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010110031030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010110031030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -36,7 +36,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010120032000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010120032000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -54,7 +54,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010110451030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010110451030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -72,7 +72,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010120452000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010120452000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -90,7 +90,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010110c3011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010110c3011030112233445566778899aabbccddeeff PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -108,7 +108,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010120c3012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010120c3012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -126,7 +126,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010110021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010110021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -143,7 +143,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010120022000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010120022000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -160,7 +160,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010110441030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010110441030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -177,7 +177,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010120442000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010120442000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -194,7 +194,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010110c2011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010110c2011030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -211,7 +211,7 @@ PASS clonedKey.algorithm.name is "AES-CBC" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010120c2012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010120c2012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/aes-ctr/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/aes-ctr/cloneKey-expected.txt index 8e90c6b..fd70462 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/aes-ctr/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/aes-ctr/cloneKey-expected.txt
@@ -18,7 +18,7 @@ PASS clonedKey.algorithm.name is "AES-CTR" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010b10c1011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010b10c1011030112233445566778899aabbccddeeff PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -36,7 +36,7 @@ PASS clonedKey.algorithm.name is "AES-CTR" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010b20c1012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010b20c1012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -54,7 +54,7 @@ PASS clonedKey.algorithm.name is "AES-CTR" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010b10c0011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010b10c0011030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -71,7 +71,7 @@ PASS clonedKey.algorithm.name is "AES-CTR" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010b20c0012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010b20c0012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/aes-gcm/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/aes-gcm/cloneKey-expected.txt index ca5251ab..c66d1b7 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/aes-gcm/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/aes-gcm/cloneKey-expected.txt
@@ -18,7 +18,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010910031030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010910031030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -36,7 +36,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010920032000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010920032000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -54,7 +54,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010910451030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010910451030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -72,7 +72,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010920452000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010920452000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -90,7 +90,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010910c3011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010910c3011030112233445566778899aabbccddeeff PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -108,7 +108,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010920c3012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010920c3012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -126,7 +126,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010910021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010910021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -143,7 +143,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt" -Serialized key bytes: 4b010920022000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010920022000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -160,7 +160,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010910441030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b010910441030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -177,7 +177,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "decrypt,wrapKey" -Serialized key bytes: 4b010920442000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Serialized key bytes: 5c4b010920442000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -194,7 +194,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010910c2011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010910c2011030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -211,7 +211,7 @@ PASS clonedKey.algorithm.name is "AES-GCM" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "encrypt,wrapKey,unwrapKey" -Serialized key bytes: 4b010920c2012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010920c2012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/aes-kw/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/aes-kw/cloneKey-expected.txt index e7414d31..1be6f63 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/aes-kw/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/aes-kw/cloneKey-expected.txt
@@ -18,7 +18,7 @@ PASS clonedKey.algorithm.name is "AES-KW" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010c10c1011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010c10c1011030112233445566778899aabbccddeeff PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -36,7 +36,7 @@ PASS clonedKey.algorithm.name is "AES-KW" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010c20c1012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010c20c1012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS: Cloned key exported data should be [00112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f] and was PASS importedKey.extraProperty is "hi" @@ -54,7 +54,7 @@ PASS clonedKey.algorithm.name is "AES-KW" PASS clonedKey.algorithm.length is 128 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010c10c0011030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b010c10c0011030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -71,7 +71,7 @@ PASS clonedKey.algorithm.name is "AES-KW" PASS clonedKey.algorithm.length is 256 PASS clonedKey.usages.join(',') is "wrapKey,unwrapKey" -Serialized key bytes: 4b010c20c0012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f00 +Serialized key bytes: 5c4b010c20c0012000112233445546778899aabbccddeeff000102030405060708090a0b0c0d0e0f PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/cloneKey-expected.txt index 22828f6..af00cab 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/ecdh/cloneKey-expected.txt
@@ -18,7 +18,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050f0101015b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78 +Serialized key bytes: 5c4b050f0101015b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c7800 PASS: Cloned key exported data should be [3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78] and was PASS importedKey.extraProperty is "hi" @@ -36,7 +36,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050f0101005b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78 +Serialized key bytes: 5c4b050f0101005b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c7800 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -53,7 +53,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050f010201783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b926700 +Serialized key bytes: 5c4b050f010201783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267 PASS: Cloned key exported data should be [3076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267] and was PASS importedKey.extraProperty is "hi" @@ -71,7 +71,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050f010200783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b926700 +Serialized key bytes: 5c4b050f010200783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -88,7 +88,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050f0103019e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee +Serialized key bytes: 5c4b050f0103019e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee00 PASS: Cloned key exported data should be [30819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee] and was PASS importedKey.extraProperty is "hi" @@ -106,7 +106,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050f0103009e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee +Serialized key bytes: 5c4b050f0103009e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -123,7 +123,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b050f020181028a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c600 +Serialized key bytes: 5c4b050f020181028a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c6 PASS: Cloned key exported data should be [308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c6] and was PASS importedKey.extraProperty is "hi" @@ -141,7 +141,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b050f020180028a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c600 +Serialized key bytes: 5c4b050f020180028a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c6 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -158,7 +158,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b050f02028102b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e +Serialized key bytes: 5c4b050f02028102b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e00 PASS: Cloned key exported data should be [3081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e] and was PASS importedKey.extraProperty is "hi" @@ -176,7 +176,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b050f02028002b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e +Serialized key bytes: 5c4b050f02028002b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -193,7 +193,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b050f02038102f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d +Serialized key bytes: 5c4b050f02038102f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d00 PASS: Cloned key exported data should be [3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d] and was PASS importedKey.extraProperty is "hi" @@ -211,7 +211,7 @@ PASS clonedKey.algorithm.name is "ECDH" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b050f02038002f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d +Serialized key bytes: 5c4b050f02038002f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d00 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/ecdsa/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/ecdsa/cloneKey-expected.txt index 3cc9b97..9335d3b 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/ecdsa/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/ecdsa/cloneKey-expected.txt
@@ -18,7 +18,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050e0101015b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78 +Serialized key bytes: 5c4b050e0101015b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c7800 PASS: Cloned key exported data should be [3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78] and was PASS importedKey.extraProperty is "hi" @@ -36,7 +36,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b050e0101115b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78 +Serialized key bytes: 5c4b050e0101115b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c7800 PASS: Cloned key exported data should be [3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78] and was PASS importedKey.extraProperty is "hi" @@ -54,7 +54,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050e0101005b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78 +Serialized key bytes: 5c4b050e0101005b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c7800 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -71,7 +71,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b050e0101105b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c78 +Serialized key bytes: 5c4b050e0101105b3059301306072a8648ce3d020106082a8648ce3d030107034200049cb0cf69303dafc761d4e4687b4ecf039e6d34ab964af80810d8d558a4a8d6f72d51233a1788920a86ee08a1962c79efa317fb7879e297dad2146db995fa1c7800 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -88,7 +88,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050e010201783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b926700 +Serialized key bytes: 5c4b050e010201783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267 PASS: Cloned key exported data should be [3076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267] and was PASS importedKey.extraProperty is "hi" @@ -106,7 +106,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b050e010211783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b926700 +Serialized key bytes: 5c4b050e010211783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267 PASS: Cloned key exported data should be [3076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267] and was PASS importedKey.extraProperty is "hi" @@ -124,7 +124,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050e010200783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b926700 +Serialized key bytes: 5c4b050e010200783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -141,7 +141,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b050e010210783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b926700 +Serialized key bytes: 5c4b050e010210783076301006072a8648ce3d020106052b81040022036200040874a2e0b8ff448f0e54321e27f4f1e64d064cdeb7d26f458c32e930120f4e57dc85c2693f977eed4a8ecc8db981b4d91f69446df4f4c6f5de19003f45f891d0ebcd2fffdb5c81c040e8d6994c43c7feedb98a4a31edfb35e89a30013c3b9267 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -158,7 +158,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050e0103019e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee +Serialized key bytes: 5c4b050e0103019e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee00 PASS: Cloned key exported data should be [30819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee] and was PASS importedKey.extraProperty is "hi" @@ -176,7 +176,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b050e0103119e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee +Serialized key bytes: 5c4b050e0103119e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee00 PASS: Cloned key exported data should be [30819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee] and was PASS importedKey.extraProperty is "hi" @@ -194,7 +194,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b050e0103009e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee +Serialized key bytes: 5c4b050e0103009e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -211,7 +211,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b050e0103109e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee +Serialized key bytes: 5c4b050e0103109e0130819b301006072a8648ce3d020106052b81040023038186000400f50a08703250c15f043c8c46e99783435245cf98f4f2694b0e2f8d029a514dd6f0b086d4ed892000cd5590107aae69c4c0a7a95f7cf74e5770a07d5db55bce4ab400f2c770bab8b9be4cdb6ecd3dc26c698da0d2599cebf3d904f7f9ca3a55e64731810d73cd317264e50baba4bc2860857e16d6cbb79501bc9e3a32bd172ea8a71dee00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -228,7 +228,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b050e0201098a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c6 +Serialized key bytes: 5c4b050e0201098a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c600 PASS: Cloned key exported data should be [308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c6] and was PASS importedKey.extraProperty is "hi" @@ -246,7 +246,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b050e0201088a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c6 +Serialized key bytes: 5c4b050e0201088a01308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104201fe33950c5f461124ae992c2bdfdf1c73b1615f571bd567e60d19aa1f48cdf42a144034200047c110c66dcfda807f6e69e45ddb3c74f69a1484d203e8dc5ada8e9a9dd7cb3c70df448986e51bde5d1576f99901f9c2c6a806a47fd907643a72b835597efc8c600 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -263,7 +263,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b050e020209b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e00 +Serialized key bytes: 5c4b050e020209b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e PASS: Cloned key exported data should be [3081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e] and was PASS importedKey.extraProperty is "hi" @@ -281,7 +281,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-384" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b050e020208b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e00 +Serialized key bytes: 5c4b050e020208b9013081b6020100301006072a8648ce3d020106052b8104002204819e30819b0201010430a492ce8fa90084c227e1a32f7974d39e9ff67a7e8705ec3419b35fb607582bebd461e0b1520ac76ec2dd4e9b63ebae71a16403620004e55fee6c49d8d523f5ce7bf9c0425ce4ff650708b7de5cfb095901523979a7f042602db30854735369813b5c3f5ef86828f59cc5dc509892a988d38a8e2519de3d0c4fd0fbdb0993e38f18506c17606c5e24249246f1ce94983a5361c5be983e PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -298,7 +298,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b050e020309f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d00 +Serialized key bytes: 5c4b050e020309f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d PASS: Cloned key exported data should be [3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d] and was PASS importedKey.extraProperty is "hi" @@ -316,7 +316,7 @@ PASS clonedKey.algorithm.name is "ECDSA" PASS clonedKey.algorithm.namedCurve is "P-521" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b050e020308f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d00 +Serialized key bytes: 5c4b050e020308f1013081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044201bd56bd106118eda246155bd43b42b8e13f0a6e25dd3bb376026fab4dc92b6157bc6dfec2d15dd3d0cf2a39aa68494042af48ba9601118da82c6f2108a3a203ad74a181890381860004012fbcaeffa6a51f3ee4d3d2b51c5dec6d7c726ca353fc014ea2bf7cfbb9b910d32cbfa6a00fe39b6cdb8946f22775398b2e233c0cf144d78c8a7742b5c7a3bb5d23009cdef823dd7bf9a79e8cceacd2e4527c231d0ae5967af0958e931d7ddccf2805a3e618dc3039fec9febbd33052fe4c0fee98f033106064982d88f4e03549d4a64d PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/cloneKey-expected.txt index 3f3c40c..ec493bd 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/hkdf/cloneKey-expected.txt
@@ -16,7 +16,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b0610800200 +Serialized key bytes: 5c4b061080020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -31,7 +31,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06108002013000 +Serialized key bytes: 5c4b061080020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -46,7 +46,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06108002080011223344554677 +Serialized key bytes: 5c4b0610800208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -61,7 +61,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061080020b00112233445546778899aa00 +Serialized key bytes: 5c4b061080020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -76,7 +76,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061080021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b061080021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -91,7 +91,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200000 +Serialized key bytes: 5c4b06102000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -106,7 +106,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200130 +Serialized key bytes: 5c4b061020013000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -121,7 +121,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b06102008001122334455467700 +Serialized key bytes: 5c4b061020080011223344554677 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -136,7 +136,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200b00112233445546778899aa +Serialized key bytes: 5c4b0610200b00112233445546778899aa00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -151,7 +151,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610201030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b0610201030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -166,7 +166,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a00200 +Serialized key bytes: 5c4b0610a0020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -181,7 +181,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a002013000 +Serialized key bytes: 5c4b0610a0020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -196,7 +196,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a002080011223344554677 +Serialized key bytes: 5c4b0610a00208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -211,7 +211,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a0020b00112233445546778899aa00 +Serialized key bytes: 5c4b0610a0020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -226,7 +226,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a0021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b0610a0021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -241,7 +241,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b0610800200 +Serialized key bytes: 5c4b061080020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -256,7 +256,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06108002013000 +Serialized key bytes: 5c4b061080020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -271,7 +271,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06108002080011223344554677 +Serialized key bytes: 5c4b0610800208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -286,7 +286,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061080020b00112233445546778899aa00 +Serialized key bytes: 5c4b061080020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -301,7 +301,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061080021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b061080021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -316,7 +316,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200000 +Serialized key bytes: 5c4b06102000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -331,7 +331,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200130 +Serialized key bytes: 5c4b061020013000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -346,7 +346,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b06102008001122334455467700 +Serialized key bytes: 5c4b061020080011223344554677 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -361,7 +361,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200b00112233445546778899aa +Serialized key bytes: 5c4b0610200b00112233445546778899aa00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -376,7 +376,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610201030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b0610201030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -391,7 +391,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a00200 +Serialized key bytes: 5c4b0610a0020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -406,7 +406,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a002013000 +Serialized key bytes: 5c4b0610a0020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -421,7 +421,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a002080011223344554677 +Serialized key bytes: 5c4b0610a00208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -436,7 +436,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a0020b00112233445546778899aa00 +Serialized key bytes: 5c4b0610a0020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -451,7 +451,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a0021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b0610a0021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -466,7 +466,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b0610800200 +Serialized key bytes: 5c4b061080020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -481,7 +481,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06108002013000 +Serialized key bytes: 5c4b061080020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -496,7 +496,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06108002080011223344554677 +Serialized key bytes: 5c4b0610800208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -511,7 +511,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061080020b00112233445546778899aa00 +Serialized key bytes: 5c4b061080020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -526,7 +526,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061080021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b061080021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -541,7 +541,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200000 +Serialized key bytes: 5c4b06102000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -556,7 +556,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200130 +Serialized key bytes: 5c4b061020013000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -571,7 +571,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b06102008001122334455467700 +Serialized key bytes: 5c4b061020080011223344554677 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -586,7 +586,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610200b00112233445546778899aa +Serialized key bytes: 5c4b0610200b00112233445546778899aa00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -601,7 +601,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0610201030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b0610201030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -616,7 +616,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a00200 +Serialized key bytes: 5c4b0610a0020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -631,7 +631,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a002013000 +Serialized key bytes: 5c4b0610a0020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -646,7 +646,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a002080011223344554677 +Serialized key bytes: 5c4b0610a00208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -661,7 +661,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a0020b00112233445546778899aa00 +Serialized key bytes: 5c4b0610a0020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -676,7 +676,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "HKDF" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0610a0021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b0610a0021030112233445566778899aabbccddeeff00 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/hmac/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/hmac/cloneKey-expected.txt index 5f57e09..0c3233e 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/hmac/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/hmac/cloneKey-expected.txt
@@ -20,7 +20,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02010509013000 +Serialized key bytes: 5c4b020105090130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -40,7 +40,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02080509080011223344554677 +Serialized key bytes: 5c4b0208050908001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -60,7 +60,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b020b05090b00112233445546778899aa00 +Serialized key bytes: 5c4b020b05090b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -80,7 +80,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b021005091030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021005091030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -100,7 +100,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02010511013000 +Serialized key bytes: 5c4b020105110130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -120,7 +120,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02080511080011223344554677 +Serialized key bytes: 5c4b0208051108001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -140,7 +140,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b020b05110b00112233445546778899aa00 +Serialized key bytes: 5c4b020b05110b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -160,7 +160,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b021005111030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021005111030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -180,7 +180,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02010519013000 +Serialized key bytes: 5c4b020105190130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -200,7 +200,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02080519080011223344554677 +Serialized key bytes: 5c4b0208051908001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -220,7 +220,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b020b05190b00112233445546778899aa00 +Serialized key bytes: 5c4b020b05190b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -240,7 +240,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b021005191030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021005191030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -260,7 +260,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02010508013000 +Serialized key bytes: 5c4b020105080130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -279,7 +279,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02080508080011223344554677 +Serialized key bytes: 5c4b0208050808001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -298,7 +298,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b020b05080b00112233445546778899aa00 +Serialized key bytes: 5c4b020b05080b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -317,7 +317,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b021005081030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021005081030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -336,7 +336,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02010510013000 +Serialized key bytes: 5c4b020105100130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -355,7 +355,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02080510080011223344554677 +Serialized key bytes: 5c4b0208051008001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -374,7 +374,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b020b05100b00112233445546778899aa00 +Serialized key bytes: 5c4b020b05100b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -393,7 +393,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b021005101030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021005101030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -412,7 +412,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02010518013000 +Serialized key bytes: 5c4b020105180130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -431,7 +431,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02080518080011223344554677 +Serialized key bytes: 5c4b0208051808001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -450,7 +450,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b020b05180b00112233445546778899aa00 +Serialized key bytes: 5c4b020b05180b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -469,7 +469,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b021005181030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021005181030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -488,7 +488,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02010609013000 +Serialized key bytes: 5c4b020106090130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -508,7 +508,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02080609080011223344554677 +Serialized key bytes: 5c4b0208060908001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -528,7 +528,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b020b06090b00112233445546778899aa00 +Serialized key bytes: 5c4b020b06090b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -548,7 +548,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b021006091030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021006091030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -568,7 +568,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02010611013000 +Serialized key bytes: 5c4b020106110130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -588,7 +588,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02080611080011223344554677 +Serialized key bytes: 5c4b0208061108001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -608,7 +608,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b020b06110b00112233445546778899aa00 +Serialized key bytes: 5c4b020b06110b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -628,7 +628,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b021006111030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021006111030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -648,7 +648,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02010619013000 +Serialized key bytes: 5c4b020106190130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -668,7 +668,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02080619080011223344554677 +Serialized key bytes: 5c4b0208061908001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -688,7 +688,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b020b06190b00112233445546778899aa00 +Serialized key bytes: 5c4b020b06190b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -708,7 +708,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b021006191030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021006191030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -728,7 +728,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02010608013000 +Serialized key bytes: 5c4b020106080130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -747,7 +747,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02080608080011223344554677 +Serialized key bytes: 5c4b0208060808001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -766,7 +766,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b020b06080b00112233445546778899aa00 +Serialized key bytes: 5c4b020b06080b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -785,7 +785,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b021006081030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021006081030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -804,7 +804,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02010610013000 +Serialized key bytes: 5c4b020106100130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -823,7 +823,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02080610080011223344554677 +Serialized key bytes: 5c4b0208061008001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -842,7 +842,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b020b06100b00112233445546778899aa00 +Serialized key bytes: 5c4b020b06100b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -861,7 +861,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b021006101030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021006101030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -880,7 +880,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02010618013000 +Serialized key bytes: 5c4b020106180130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -899,7 +899,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02080618080011223344554677 +Serialized key bytes: 5c4b0208061808001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -918,7 +918,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b020b06180b00112233445546778899aa00 +Serialized key bytes: 5c4b020b06180b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -937,7 +937,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b021006181030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021006181030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -956,7 +956,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02010809013000 +Serialized key bytes: 5c4b020108090130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -976,7 +976,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02080809080011223344554677 +Serialized key bytes: 5c4b0208080908001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -996,7 +996,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b020b08090b00112233445546778899aa00 +Serialized key bytes: 5c4b020b08090b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -1016,7 +1016,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b021008091030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021008091030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -1036,7 +1036,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02010811013000 +Serialized key bytes: 5c4b020108110130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -1056,7 +1056,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02080811080011223344554677 +Serialized key bytes: 5c4b0208081108001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -1076,7 +1076,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b020b08110b00112233445546778899aa00 +Serialized key bytes: 5c4b020b08110b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -1096,7 +1096,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b021008111030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021008111030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -1116,7 +1116,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02010819013000 +Serialized key bytes: 5c4b020108190130 PASS: Cloned key exported data should be [30] and was PASS importedKey.extraProperty is "hi" @@ -1136,7 +1136,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02080819080011223344554677 +Serialized key bytes: 5c4b0208081908001122334455467700 PASS: Cloned key exported data should be [0011223344554677] and was PASS importedKey.extraProperty is "hi" @@ -1156,7 +1156,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b020b08190b00112233445546778899aa00 +Serialized key bytes: 5c4b020b08190b00112233445546778899aa PASS: Cloned key exported data should be [00112233445546778899aa] and was PASS importedKey.extraProperty is "hi" @@ -1176,7 +1176,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b021008191030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021008191030112233445566778899aabbccddeeff00 PASS: Cloned key exported data should be [30112233445566778899aabbccddeeff] and was PASS importedKey.extraProperty is "hi" @@ -1196,7 +1196,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02010808013000 +Serialized key bytes: 5c4b020108080130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1215,7 +1215,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b02080808080011223344554677 +Serialized key bytes: 5c4b0208080808001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1234,7 +1234,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b020b08080b00112233445546778899aa00 +Serialized key bytes: 5c4b020b08080b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1253,7 +1253,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b021008081030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021008081030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1272,7 +1272,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02010810013000 +Serialized key bytes: 5c4b020108100130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1291,7 +1291,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b02080810080011223344554677 +Serialized key bytes: 5c4b0208081008001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1310,7 +1310,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b020b08100b00112233445546778899aa00 +Serialized key bytes: 5c4b020b08100b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1329,7 +1329,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b021008101030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021008101030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1348,7 +1348,7 @@ PASS clonedKey.algorithm.length is 8 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02010818013000 +Serialized key bytes: 5c4b020108180130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1367,7 +1367,7 @@ PASS clonedKey.algorithm.length is 64 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b02080818080011223344554677 +Serialized key bytes: 5c4b0208081808001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1386,7 +1386,7 @@ PASS clonedKey.algorithm.length is 88 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b020b08180b00112233445546778899aa00 +Serialized key bytes: 5c4b020b08180b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -1405,7 +1405,7 @@ PASS clonedKey.algorithm.length is 128 PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign,verify" -Serialized key bytes: 4b021008181030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b021008181030112233445566778899aabbccddeeff00 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/pbkdf2/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/pbkdf2/cloneKey-expected.txt index 986e63f..c15ec53 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/pbkdf2/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/pbkdf2/cloneKey-expected.txt
@@ -16,7 +16,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b0611800200 +Serialized key bytes: 5c4b061180020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -31,7 +31,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06118002013000 +Serialized key bytes: 5c4b061180020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -46,7 +46,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06118002080011223344554677 +Serialized key bytes: 5c4b0611800208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -61,7 +61,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061180020b00112233445546778899aa00 +Serialized key bytes: 5c4b061180020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -76,7 +76,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061180021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b061180021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -91,7 +91,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200000 +Serialized key bytes: 5c4b06112000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -106,7 +106,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200130 +Serialized key bytes: 5c4b061120013000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -121,7 +121,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b06112008001122334455467700 +Serialized key bytes: 5c4b061120080011223344554677 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -136,7 +136,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200b00112233445546778899aa +Serialized key bytes: 5c4b0611200b00112233445546778899aa00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -151,7 +151,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611201030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b0611201030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -166,7 +166,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a00200 +Serialized key bytes: 5c4b0611a0020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -181,7 +181,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a002013000 +Serialized key bytes: 5c4b0611a0020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -196,7 +196,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a002080011223344554677 +Serialized key bytes: 5c4b0611a00208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -211,7 +211,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a0020b00112233445546778899aa00 +Serialized key bytes: 5c4b0611a0020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -226,7 +226,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a0021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b0611a0021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -241,7 +241,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b0611800200 +Serialized key bytes: 5c4b061180020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -256,7 +256,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06118002013000 +Serialized key bytes: 5c4b061180020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -271,7 +271,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06118002080011223344554677 +Serialized key bytes: 5c4b0611800208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -286,7 +286,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061180020b00112233445546778899aa00 +Serialized key bytes: 5c4b061180020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -301,7 +301,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061180021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b061180021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -316,7 +316,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200000 +Serialized key bytes: 5c4b06112000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -331,7 +331,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200130 +Serialized key bytes: 5c4b061120013000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -346,7 +346,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b06112008001122334455467700 +Serialized key bytes: 5c4b061120080011223344554677 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -361,7 +361,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200b00112233445546778899aa +Serialized key bytes: 5c4b0611200b00112233445546778899aa00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -376,7 +376,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611201030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b0611201030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -391,7 +391,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a00200 +Serialized key bytes: 5c4b0611a0020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -406,7 +406,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a002013000 +Serialized key bytes: 5c4b0611a0020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -421,7 +421,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a002080011223344554677 +Serialized key bytes: 5c4b0611a00208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -436,7 +436,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a0020b00112233445546778899aa00 +Serialized key bytes: 5c4b0611a0020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -451,7 +451,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a0021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b0611a0021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -466,7 +466,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b0611800200 +Serialized key bytes: 5c4b061180020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -481,7 +481,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06118002013000 +Serialized key bytes: 5c4b061180020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -496,7 +496,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b06118002080011223344554677 +Serialized key bytes: 5c4b0611800208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -511,7 +511,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061180020b00112233445546778899aa00 +Serialized key bytes: 5c4b061180020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -526,7 +526,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveBits" -Serialized key bytes: 4b061180021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b061180021030112233445566778899aabbccddeeff00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -541,7 +541,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200000 +Serialized key bytes: 5c4b06112000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -556,7 +556,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200130 +Serialized key bytes: 5c4b061120013000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -571,7 +571,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b06112008001122334455467700 +Serialized key bytes: 5c4b061120080011223344554677 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -586,7 +586,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611200b00112233445546778899aa +Serialized key bytes: 5c4b0611200b00112233445546778899aa00 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -601,7 +601,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey" -Serialized key bytes: 4b0611201030112233445566778899aabbccddeeff00 +Serialized key bytes: 5c4b0611201030112233445566778899aabbccddeeff PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -616,7 +616,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a00200 +Serialized key bytes: 5c4b0611a0020000 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -631,7 +631,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a002013000 +Serialized key bytes: 5c4b0611a0020130 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -646,7 +646,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a002080011223344554677 +Serialized key bytes: 5c4b0611a00208001122334455467700 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -661,7 +661,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a0020b00112233445546778899aa00 +Serialized key bytes: 5c4b0611a0020b00112233445546778899aa PASS importedKey.extraProperty is "hi" PASS importedKey.type is "secret" @@ -676,7 +676,7 @@ PASS clonedKey.extractable is false PASS clonedKey.algorithm.name is "PBKDF2" PASS clonedKey.usages.join(',') is "deriveKey,deriveBits" -Serialized key bytes: 4b0611a0021030112233445566778899aabbccddeeff +Serialized key bytes: 5c4b0611a0021030112233445566778899aabbccddeeff00 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/crypto/subtle/rsassa-pkcs1-v1_5/cloneKey-expected.txt b/third_party/WebKit/LayoutTests/crypto/subtle/rsassa-pkcs1-v1_5/cloneKey-expected.txt index f91eb56a..3208500 100644 --- a/third_party/WebKit/LayoutTests/crypto/subtle/rsassa-pkcs1-v1_5/cloneKey-expected.txt +++ b/third_party/WebKit/LayoutTests/crypto/subtle/rsassa-pkcs1-v1_5/cloneKey-expected.txt
@@ -22,7 +22,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018008030100010501a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010501a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS: Cloned key exported data should be [30819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001] and was PASS importedKey.extraProperty is "hi" @@ -44,7 +44,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018010030100010501a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010501a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS: Cloned key exported data should be [30820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001] and was PASS importedKey.extraProperty is "hi" @@ -66,7 +66,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018008030100010511a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010511a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS: Cloned key exported data should be [30819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001] and was PASS importedKey.extraProperty is "hi" @@ -88,7 +88,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018010030100010511a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010511a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS: Cloned key exported data should be [30820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001] and was PASS importedKey.extraProperty is "hi" @@ -110,7 +110,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018008030100010500a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010500a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -131,7 +131,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018010030100010500a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010500a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -152,7 +152,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018008030100010510a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010510a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -173,7 +173,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018010030100010510a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010510a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -194,7 +194,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018008030100010601a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010601a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS: Cloned key exported data should be [30819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001] and was PASS importedKey.extraProperty is "hi" @@ -216,7 +216,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018010030100010601a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010601a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS: Cloned key exported data should be [30820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001] and was PASS importedKey.extraProperty is "hi" @@ -238,7 +238,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018008030100010611a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010611a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS: Cloned key exported data should be [30819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001] and was PASS importedKey.extraProperty is "hi" @@ -260,7 +260,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018010030100010611a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010611a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS: Cloned key exported data should be [30820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001] and was PASS importedKey.extraProperty is "hi" @@ -282,7 +282,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018008030100010600a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010600a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -303,7 +303,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018010030100010600a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010600a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -324,7 +324,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018008030100010610a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010610a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -345,7 +345,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018010030100010610a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010610a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -366,7 +366,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018008030100010801a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010801a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS: Cloned key exported data should be [30819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001] and was PASS importedKey.extraProperty is "hi" @@ -388,7 +388,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018010030100010801a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010801a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS: Cloned key exported data should be [30820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001] and was PASS importedKey.extraProperty is "hi" @@ -410,7 +410,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018008030100010811a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010811a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS: Cloned key exported data should be [30819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001] and was PASS importedKey.extraProperty is "hi" @@ -432,7 +432,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018010030100010811a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010811a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS: Cloned key exported data should be [30820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001] and was PASS importedKey.extraProperty is "hi" @@ -454,7 +454,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018008030100010800a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010800a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -475,7 +475,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "" -Serialized key bytes: 4b0403018010030100010800a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010800a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -496,7 +496,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018008030100010810a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a410203010001 +Serialized key bytes: 5c4b0403018008030100010810a20130819f300d06092a864886f70d010101050003818d0030818902818100b289c62ecc3ddf64154817203439eaa0dc07a65954429a7b6098a77235673d96df1f06bd3c1ae73990867199e678bf95b3728fcd4686136e6ee9dd4c09eb490eb7cb953c388668b759263f61d6a7dfcabf27b5c9d6972455b12b66d483843286d6b871f35f912a773c97c1932255fcee05ce7b8af213879f017de4232a306a41020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "public" @@ -517,7 +517,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "verify" -Serialized key bytes: 4b0403018010030100010810a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef0203010001 +Serialized key bytes: 5c4b0403018010030100010810a60230820122300d06092a864886f70d01010105000382010f003082010a0282010100b4c8b631194aef0154b1479ab7a534b60ca878981108680f0ae6b7c88cb6010f6dbf9f665646208410575cb923b26bf874a24b4cd801c9bba967062ae506cdcf307add4380d0d93077a4c1f0fc06d498dc729f811335c530b90fe9bf9f3979ccec050a48e8923045b19368e1e89ea4157538e8059e53320f47c155f1741310a93ed153a7f3af2d46c388b95d82518527a02b7bd9ab7edc4bcb737677f679c5c6de5e1ebed3a29d6b99b8eace2d59ceb533e001cf39c5671495d51d3ee34406ea4fdb0c626dee68da256b8a12f9f65059ccc85a2190ce1385152d62785e00cae702e77c4c597b86a6268adbf043dda68881c790f1517671fb7d198fca5ba97bef020301000100 PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -538,7 +538,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028008030100010509f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d00 +Serialized key bytes: 5c4b0403028008030100010509f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d PASS: Cloned key exported data should be [30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d] and was PASS importedKey.extraProperty is "hi" @@ -560,7 +560,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028010030100010509c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed00 +Serialized key bytes: 5c4b0403028010030100010509c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed PASS: Cloned key exported data should be [308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed] and was PASS importedKey.extraProperty is "hi" @@ -582,7 +582,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028008030100010508f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d00 +Serialized key bytes: 5c4b0403028008030100010508f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -603,7 +603,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-1" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028010030100010508c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed00 +Serialized key bytes: 5c4b0403028010030100010508c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -624,7 +624,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028008030100010609f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d00 +Serialized key bytes: 5c4b0403028008030100010609f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d PASS: Cloned key exported data should be [30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d] and was PASS importedKey.extraProperty is "hi" @@ -646,7 +646,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028010030100010609c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed00 +Serialized key bytes: 5c4b0403028010030100010609c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed PASS: Cloned key exported data should be [308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed] and was PASS importedKey.extraProperty is "hi" @@ -668,7 +668,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028008030100010608f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d00 +Serialized key bytes: 5c4b0403028008030100010608f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -689,7 +689,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-256" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028010030100010608c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed00 +Serialized key bytes: 5c4b0403028010030100010608c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -710,7 +710,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028008030100010809f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d00 +Serialized key bytes: 5c4b0403028008030100010809f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d PASS: Cloned key exported data should be [30820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d] and was PASS importedKey.extraProperty is "hi" @@ -732,7 +732,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028010030100010809c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed00 +Serialized key bytes: 5c4b0403028010030100010809c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed PASS: Cloned key exported data should be [308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed] and was PASS importedKey.extraProperty is "hi" @@ -754,7 +754,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028008030100010808f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d00 +Serialized key bytes: 5c4b0403028008030100010808f90430820275020100300d06092a864886f70d01010105000482025f3082025b02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d PASS importedKey.extraProperty is "hi" PASS importedKey.type is "private" @@ -775,7 +775,7 @@ PASS: clonedKey.algorithm.publicExponent should be [010001] and was PASS clonedKey.algorithm.hash.name is "SHA-512" PASS clonedKey.usages.join(',') is "sign" -Serialized key bytes: 4b0403028010030100010808c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed00 +Serialized key bytes: 5c4b0403028010030100010808c109308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100e085e33c42d3f3d63434e0bf1b812c444e790ff6c0becf2cc9de895afa601457bd0fafa81e2b977ab818d086d018491d7ff45be40e916c4c81b3d055ac1803b514e1010b983ff072b77fa228dd47024e65a3c72ab4e2ed02901ba43351dcd87beef92036983c42495d9efec5b4ea1113848b53287099cff1ba58a7829af733f19269101da8c10aa1d5d6b34d381dbb0704e58904c3504a1922f6956e95596780a5db08fe944ff3056ec070eafa66f8c1c5d7dcde4ce2c2694f240aec528eb699089e29f669fb3405c47d6309a609936e8b64e003b5f40743be6b7c2d5673e305cc4e2d154b2a046fba889b60913271b00d5321fd15f82cc41b2894ffc2e54d0b0203010001028201007ae930b59b8bf66f6c130a79f42fa9b117187521caf069f005eeda58c0b9fa48f1c9f58a5e41d4e22c880117dc317f4d33efeca2134b8ef2ef0a25e1d09d30e25fb4b162cc8d2c2f50bf0161c78908fd2bed15aa0e6e2ffb78327998529748b7c7e1ffbd8367718e423f390fb8736eb7b596a4067e65e58d5a4b1020927f03a293d5d3b32931d2a06542e9bbeab7e90085afc9fe145d1c28f44a97f8d9eb8c41913ed9f40261ac5f86806254e26aa8502b92779794a7b08ea299865cbdfeab4dd16307169902b46dbe132b035f7e2742f779f5b39a0b40099434a8af14c78f705abaa7474633a7c6306b2673a97aae35b6a3bf6a5fdd9a6b8d17bd6bbfa1872902818100f2bdbf99a43a4064ac5c85ccff42cccf14fa35250a8d77db6746478d0aea456377dc304688a55b1d2b14c46189ff4f92b078902ff66d144116038667cbbf5bfe80a775aa6eb9885686193debf030eaba00a8cbf26a4fdce1cb433a3a0ccd9696d64448141b0c5d9dfb32bdc29a271594d8e2bc0639daeec705b2cc12419876b702818100ecc964d844657b98dc6b3c6df58a4b5adff0cf5ac1a68679de2baccb4cda1b767f879e441769e5cc0065d8e573f9d728bbd4e25553ee8a2ba779eb219ad0a108daea34e7054d1767e644bdb63880234ac8143a9dda28d3f9196508088e2722ab86a3aa10e599b3caf226e69bee90a1ae7f289b945a34a4fed5e34f9d216b284d028180150ba27afda4174523347a5d459c5309793620396feac8037bb6ba295e52e565345520d25cb2896dc3f86ef64df296c18f0f44e103aa7d610f398b03a0c49c833a404a91563c3bb7d4b4878bd72d468c8dd614a895d30ac180cff952631dc7fa97e51fa2ae9da9d83299399e8fa2e7da19dbbe95839a99ad23af56c6166dd38d02818005da6497c3f90e391519c180a65528cfb2416d9ebcb2b5184619a647d03a83fb45e3c051c692638fcb62b91dd2e4162177a327851c720510572f7854785337e7d4217df547f843dfd99d516333ba5724fe1521edccfabd62a6f20c64c9bec5e89f876428cec421e19e62bfc892f918460bf6a101e5c8ef5b2d46552d792a00f102818100b7d0e59415405a3ce9503e95078078518d381f4273106d67863cfee642d2b82186d9932b7cd921bf1867257473ccd2058d9c88a223701701aa8370b90878df96a6950e3b3ed52326a5cabbf376c97aa644c50fafe38f7496fb9e69efdd138b3525d8b7ac162bd75fe84cb4ce7066d6b786e80c42d5e63059ae939c7bcfa497ed PASS successfullyParsed is true
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 5c8e3d3..373b7e4f 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -3556,7 +3556,8 @@ return roundedIntPoint(layoutItem.absoluteToLocal(point, UseTransforms)); } -IntRect FrameView::convertToContainingWidget(const IntRect& localRect) const { +IntRect FrameView::convertToContainingFrameViewBase( + const IntRect& localRect) const { if (const FrameView* parentView = toFrameView(parent())) { // Get our layoutObject in the parent view LayoutPartItem layoutItem = m_frame->ownerLayoutItem(); @@ -3573,7 +3574,7 @@ return localRect; } -IntRect FrameView::convertFromContainingWidget( +IntRect FrameView::convertFromContainingFrameViewBase( const IntRect& parentRect) const { if (const FrameView* parentView = toFrameView(parent())) { // Get our layoutObject in the parent view @@ -3591,7 +3592,7 @@ return parentRect; } -IntPoint FrameView::convertToContainingWidget( +IntPoint FrameView::convertToContainingFrameViewBase( const IntPoint& localPoint) const { if (const FrameView* parentView = toFrameView(parent())) { // Get our layoutObject in the parent view @@ -3610,7 +3611,7 @@ return localPoint; } -IntPoint FrameView::convertFromContainingWidget( +IntPoint FrameView::convertFromContainingFrameViewBase( const IntPoint& parentPoint) const { if (const FrameView* parentView = toFrameView(parent())) { // Get our layoutObject in the parent view
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h index e02bffd3..fb96df8c 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.h +++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -954,10 +954,10 @@ // Override FrameViewBase methods to do point conversion via layoutObjects, in // order to take transforms into account. - IntRect convertToContainingWidget(const IntRect&) const override; - IntRect convertFromContainingWidget(const IntRect&) const override; - IntPoint convertToContainingWidget(const IntPoint&) const override; - IntPoint convertFromContainingWidget(const IntPoint&) const override; + IntRect convertToContainingFrameViewBase(const IntRect&) const override; + IntRect convertFromContainingFrameViewBase(const IntRect&) const override; + IntPoint convertToContainingFrameViewBase(const IntPoint&) const override; + IntPoint convertFromContainingFrameViewBase(const IntPoint&) const override; void didChangeGlobalRootScroller() override;
diff --git a/third_party/WebKit/Source/platform/FrameViewBase.cpp b/third_party/WebKit/Source/platform/FrameViewBase.cpp index b48054ff..b1c9347 100644 --- a/third_party/WebKit/Source/platform/FrameViewBase.cpp +++ b/third_party/WebKit/Source/platform/FrameViewBase.cpp
@@ -62,14 +62,14 @@ if (const FrameViewBase* parentFrameViewBase = parent()) { IntRect parentRect = parentFrameViewBase->convertFromRootFrame(rectInRootFrame); - return convertFromContainingWidget(parentRect); + return convertFromContainingFrameViewBase(parentRect); } return rectInRootFrame; } IntRect FrameViewBase::convertToRootFrame(const IntRect& localRect) const { if (const FrameViewBase* parentFrameViewBase = parent()) { - IntRect parentRect = convertToContainingWidget(localRect); + IntRect parentRect = convertToContainingFrameViewBase(localRect); return parentFrameViewBase->convertToRootFrame(parentRect); } return localRect; @@ -80,7 +80,7 @@ if (const FrameViewBase* parentFrameViewBase = parent()) { IntPoint parentPoint = parentFrameViewBase->convertFromRootFrame(pointInRootFrame); - return convertFromContainingWidget(parentPoint); + return convertFromContainingFrameViewBase(parentPoint); } return pointInRootFrame; } @@ -108,13 +108,13 @@ IntPoint FrameViewBase::convertToRootFrame(const IntPoint& localPoint) const { if (const FrameViewBase* parentFrameViewBase = parent()) { - IntPoint parentPoint = convertToContainingWidget(localPoint); + IntPoint parentPoint = convertToContainingFrameViewBase(localPoint); return parentFrameViewBase->convertToRootFrame(parentPoint); } return localPoint; } -IntRect FrameViewBase::convertToContainingWidget( +IntRect FrameViewBase::convertToContainingFrameViewBase( const IntRect& localRect) const { if (const FrameViewBase* parentFrameViewBase = parent()) { IntRect parentRect(localRect); @@ -125,7 +125,7 @@ return localRect; } -IntRect FrameViewBase::convertFromContainingWidget( +IntRect FrameViewBase::convertFromContainingFrameViewBase( const IntRect& parentRect) const { if (const FrameViewBase* parentFrameViewBase = parent()) { IntRect localRect = parentRect; @@ -137,7 +137,7 @@ return parentRect; } -IntPoint FrameViewBase::convertToContainingWidget( +IntPoint FrameViewBase::convertToContainingFrameViewBase( const IntPoint& localPoint) const { if (const FrameViewBase* parentFrameViewBase = parent()) return parentFrameViewBase->convertChildToSelf(this, localPoint); @@ -145,7 +145,7 @@ return localPoint; } -IntPoint FrameViewBase::convertFromContainingWidget( +IntPoint FrameViewBase::convertFromContainingFrameViewBase( const IntPoint& parentPoint) const { if (const FrameViewBase* parentFrameViewBase = parent()) return parentFrameViewBase->convertSelfToChild(this, parentPoint);
diff --git a/third_party/WebKit/Source/platform/FrameViewBase.h b/third_party/WebKit/Source/platform/FrameViewBase.h index 6692b28..cc66a10 100644 --- a/third_party/WebKit/Source/platform/FrameViewBase.h +++ b/third_party/WebKit/Source/platform/FrameViewBase.h
@@ -112,10 +112,10 @@ virtual void widgetGeometryMayHaveChanged() {} - virtual IntRect convertToContainingWidget(const IntRect&) const; - virtual IntRect convertFromContainingWidget(const IntRect&) const; - virtual IntPoint convertToContainingWidget(const IntPoint&) const; - virtual IntPoint convertFromContainingWidget(const IntPoint&) const; + virtual IntRect convertToContainingFrameViewBase(const IntRect&) const; + virtual IntRect convertFromContainingFrameViewBase(const IntRect&) const; + virtual IntPoint convertToContainingFrameViewBase(const IntPoint&) const; + virtual IntPoint convertFromContainingFrameViewBase(const IntPoint&) const; // Virtual methods to convert points to/from child frameviewbases. virtual IntPoint convertChildToSelf(const FrameViewBase*,
diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm index ff066d61..7313cccb 100644 --- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm +++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm
@@ -235,7 +235,7 @@ ASSERT(scrollerImp == scrollbarPainterForScrollbar(*scrollbar)); - return scrollbar->convertFromContainingWidget( + return scrollbar->convertFromContainingFrameViewBase( blink::IntPoint(pointInContentArea)); } @@ -493,7 +493,7 @@ DCHECK_EQ(scrollerImp, scrollbarPainterForScrollbar(*_scrollbar)); - return _scrollbar->convertFromContainingWidget( + return _scrollbar->convertFromContainingFrameViewBase( _scrollbar->getScrollableArea()->lastKnownMousePosition()); } @@ -1072,7 +1072,7 @@ IntRect rectInViewCoordinates = scrollerThumb; if (Scrollbar* verticalScrollbar = m_scrollableArea->verticalScrollbar()) rectInViewCoordinates = - verticalScrollbar->convertToContainingWidget(scrollerThumb); + verticalScrollbar->convertToContainingFrameViewBase(scrollerThumb); if (rectInViewCoordinates == m_visibleScrollerThumbRect) return;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h index 6c5a924..c1953af1 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -187,22 +187,26 @@ virtual IntRect convertFromScrollbarToContainingWidget( const Scrollbar& scrollbar, const IntRect& scrollbarRect) const { - return scrollbar.FrameViewBase::convertToContainingWidget(scrollbarRect); + return scrollbar.FrameViewBase::convertToContainingFrameViewBase( + scrollbarRect); } virtual IntRect convertFromContainingWidgetToScrollbar( const Scrollbar& scrollbar, const IntRect& parentRect) const { - return scrollbar.FrameViewBase::convertFromContainingWidget(parentRect); + return scrollbar.FrameViewBase::convertFromContainingFrameViewBase( + parentRect); } virtual IntPoint convertFromScrollbarToContainingWidget( const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const { - return scrollbar.FrameViewBase::convertToContainingWidget(scrollbarPoint); + return scrollbar.FrameViewBase::convertToContainingFrameViewBase( + scrollbarPoint); } virtual IntPoint convertFromContainingWidgetToScrollbar( const Scrollbar& scrollbar, const IntPoint& parentPoint) const { - return scrollbar.FrameViewBase::convertFromContainingWidget(parentPoint); + return scrollbar.FrameViewBase::convertFromContainingFrameViewBase( + parentPoint); } virtual Scrollbar* horizontalScrollbar() const { return nullptr; }
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp index b3ec4ef..5f01f0c 100644 --- a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp +++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
@@ -570,39 +570,40 @@ return m_scrollableArea && m_scrollableArea->isActive(); } -IntRect Scrollbar::convertToContainingWidget(const IntRect& localRect) const { +IntRect Scrollbar::convertToContainingFrameViewBase( + const IntRect& localRect) const { if (m_scrollableArea) return m_scrollableArea->convertFromScrollbarToContainingWidget(*this, localRect); - return FrameViewBase::convertToContainingWidget(localRect); + return FrameViewBase::convertToContainingFrameViewBase(localRect); } -IntRect Scrollbar::convertFromContainingWidget( +IntRect Scrollbar::convertFromContainingFrameViewBase( const IntRect& parentRect) const { if (m_scrollableArea) return m_scrollableArea->convertFromContainingWidgetToScrollbar(*this, parentRect); - return FrameViewBase::convertFromContainingWidget(parentRect); + return FrameViewBase::convertFromContainingFrameViewBase(parentRect); } -IntPoint Scrollbar::convertToContainingWidget( +IntPoint Scrollbar::convertToContainingFrameViewBase( const IntPoint& localPoint) const { if (m_scrollableArea) return m_scrollableArea->convertFromScrollbarToContainingWidget(*this, localPoint); - return FrameViewBase::convertToContainingWidget(localPoint); + return FrameViewBase::convertToContainingFrameViewBase(localPoint); } -IntPoint Scrollbar::convertFromContainingWidget( +IntPoint Scrollbar::convertFromContainingFrameViewBase( const IntPoint& parentPoint) const { if (m_scrollableArea) return m_scrollableArea->convertFromContainingWidgetToScrollbar( *this, parentPoint); - return FrameViewBase::convertFromContainingWidget(parentPoint); + return FrameViewBase::convertFromContainingFrameViewBase(parentPoint); } float Scrollbar::scrollableAreaCurrentPos() const {
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.h b/third_party/WebKit/Source/platform/scroll/Scrollbar.h index 8a1f8d6..b465474 100644 --- a/third_party/WebKit/Source/platform/scroll/Scrollbar.h +++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
@@ -156,11 +156,11 @@ ScrollbarTheme& theme() const { return m_theme; } - IntRect convertToContainingWidget(const IntRect&) const override; - IntRect convertFromContainingWidget(const IntRect&) const override; + IntRect convertToContainingFrameViewBase(const IntRect&) const override; + IntRect convertFromContainingFrameViewBase(const IntRect&) const override; - IntPoint convertToContainingWidget(const IntPoint&) const override; - IntPoint convertFromContainingWidget(const IntPoint&) const override; + IntPoint convertToContainingFrameViewBase(const IntPoint&) const override; + IntPoint convertFromContainingFrameViewBase(const IntPoint&) const override; void moveThumb(int pos, bool draggingDocument = false);
diff --git a/ui/arc/notification/arc_notification_manager.cc b/ui/arc/notification/arc_notification_manager.cc index 3810bb3..b4619203 100644 --- a/ui/arc/notification/arc_notification_manager.cc +++ b/ui/arc/notification/arc_notification_manager.cc
@@ -7,8 +7,8 @@ #include <memory> #include <utility> +#include "ash/common/system/toast/toast_manager.h" #include "ash/common/wm_shell.h" -#include "ash/system/toast/toast_manager.h" #include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h"