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, &params);
-  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, &params);
+  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, &params);
+  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, &center_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(), &params);
+  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(&current_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, &params);
+  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(&current);
+    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(&current_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(), &params);
+  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, &params);
+  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,
+          &params);
+  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,
+                                              &params);
+  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(), &params);
+    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(), &params);
+  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(),
+          &params);
+  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, &params);
+  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, &params);
+  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(),
+          &params_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(), &params);
+    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, &params);
+  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, &params);
+  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, &params);
+  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], &params);
+  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(&current_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, &params);
-  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, &center_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(), &params);
-  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(&current);
-    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(&current_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(&current_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, &params);
-  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(), &params);
-  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, &params);
-  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,
-          &params);
-  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,
-                                              &params);
-  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(), &params);
-    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(), &params);
-  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(),
-          &params);
-  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, &params);
-  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, &params);
-  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(),
-          &params_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(), &params);
-    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, &params);
-  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, &params);
-  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, &params);
-  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], &params);
-  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(&current_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"