Chromium Code Reviews| Index: ui/app_list/views/app_list_view.cc | 
| diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc | 
| index 08ff586e0718196f00aa7d3b2ef2b0615af3deba..009e3b7e782f215d006dd7c48befa19981def868 100644 | 
| --- a/ui/app_list/views/app_list_view.cc | 
| +++ b/ui/app_list/views/app_list_view.cc | 
| @@ -56,6 +56,15 @@ namespace { | 
| // The margin from the edge to the speech UI. | 
| const int kSpeechUIMargin = 12; | 
| +// The height/width of the shelf. | 
| +int kShelfSize = 48; | 
| 
 
vadimt
2017/05/26 01:27:57
I hope there is no constant or literal with the sa
 
newcomer
2017/05/26 17:11:27
There is, but it is in Ash which we cannot access
 
vadimt
2017/05/26 17:58:55
Nah, you can just leave this.
 
newcomer
2017/05/26 23:20:20
Acknowledged.
 
 | 
| + | 
| +// The height of the peeking launcher. | 
| +int kPeekingLauncherHeight = 320; | 
| + | 
| +int kLauncherThresholdDenominator = 3; | 
| 
 
vadimt
2017/05/26 01:27:57
Comments.
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| +int kLauncherDragVelocityThreshold = 25; | 
| 
 
vadimt
2017/05/26 01:27:57
Comment; it should make it clear what the units ar
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + | 
| // The vertical position for the appearing animation of the speech UI. | 
| const float kSpeechUIAppearingPosition = 12; | 
| @@ -175,14 +184,26 @@ AppListView::AppListView(AppListViewDelegate* delegate) | 
| search_box_focus_host_(nullptr), | 
| search_box_widget_(nullptr), | 
| search_box_view_(nullptr), | 
| + fullscreen_widget_bounds_(), | 
| 
 
vadimt
2017/05/26 01:27:57
No need for default constructor here.
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + display_observer_(this), | 
| overlay_view_(nullptr), | 
| animation_observer_(new HideViewAnimationObserver()) { | 
| CHECK(delegate); | 
| delegate_->GetSpeechUI()->AddObserver(this); | 
| + | 
| + if (features::IsFullscreenAppListEnabled()) | 
| + display_observer_.Add(display::Screen::GetScreen()); | 
| + | 
| + // display::Screen::GetScreen()->AddObserver(this); | 
| 
 
vadimt
2017/05/26 01:27:57
Remove
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| } | 
| AppListView::~AppListView() { | 
| + // Remove this instance from the DisplayManager's list of observers. | 
| + if (features::IsFullscreenAppListEnabled()) | 
| + display_observer_.Remove(display::Screen::GetScreen()); | 
| + // display::Screen::GetScreen()->RemoveObserver(this); | 
| 
 
vadimt
2017/05/26 01:27:56
Remove
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + | 
| delegate_->GetSpeechUI()->RemoveObserver(this); | 
| animation_observer_.reset(); | 
| // Remove child views first to ensure no remaining dependencies on delegate_. | 
| @@ -203,8 +224,10 @@ void AppListView::Initialize(gfx::NativeView parent, int initial_apps_page) { | 
| InitChildWidgets(); | 
| AddChildView(overlay_view_); | 
| + | 
| if (delegate_) | 
| delegate_->ViewInitialized(); | 
| + | 
| UMA_HISTOGRAM_TIMES("Apps.AppListCreationTime", | 
| base::Time::Now() - start_time); | 
| } | 
| @@ -330,6 +353,15 @@ void AppListView::InitContents(gfx::NativeView parent, int initial_apps_page) { | 
| FROM_HERE_WITH_EXPLICIT_FUNCTION( | 
| "440224, 441028 AppListView::InitContents")); | 
| + if (features::IsFullscreenAppListEnabled()) { | 
| + // The shield view that colors the background of the launcher and makes it | 
| + // transparent. | 
| + launcher_background_shield_ = new views::View; | 
| + launcher_background_shield_->SetPaintToLayer(ui::LAYER_SOLID_COLOR); | 
| + launcher_background_shield_->layer()->SetColor(SK_ColorBLACK); | 
| + launcher_background_shield_->layer()->SetOpacity(0.8f); | 
| 
 
vadimt
2017/05/26 01:27:57
Constant.
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + AddChildView(launcher_background_shield_); | 
| + } | 
| app_list_main_view_ = new AppListMainView(delegate_); | 
| AddChildView(app_list_main_view_); | 
| app_list_main_view_->SetPaintToLayer(); | 
| @@ -338,6 +370,7 @@ void AppListView::InitContents(gfx::NativeView parent, int initial_apps_page) { | 
| // This will be added to the |search_box_widget_| after the app list widget is | 
| // initialized. | 
| search_box_view_ = new SearchBoxView(app_list_main_view_, delegate_); | 
| + search_box_view_->SetAppListView(this); | 
| search_box_view_->SetPaintToLayer(); | 
| search_box_view_->layer()->SetFillsBoundsOpaquely(false); | 
| search_box_view_->layer()->SetMasksToBounds(true); | 
| @@ -348,7 +381,7 @@ void AppListView::InitContents(gfx::NativeView parent, int initial_apps_page) { | 
| FROM_HERE_WITH_EXPLICIT_FUNCTION( | 
| "440224, 441028 AppListView::InitContents1")); | 
| - app_list_main_view_->Init(parent, initial_apps_page, search_box_view_); | 
| + app_list_main_view_->Init(parent, initial_apps_page, search_box_view_, this); | 
| // TODO(vadimt): Remove ScopedTracker below once crbug.com/440224 and | 
| // crbug.com/441028 are fixed. | 
| @@ -404,21 +437,34 @@ void AppListView::InitChildWidgets() { | 
| void AppListView::InitializeFullscreen(gfx::NativeView parent, | 
| int initial_apps_page) { | 
| - views::Widget* widget = new views::Widget; | 
| + UpdateDimensions(); | 
| + | 
| + gfx::Rect app_list_overlay_view_bounds( | 
| + display_work_area_bounds_.x(), default_peeking_launcher_y_, | 
| + display_work_area_bounds_.width(), | 
| + display_work_area_bounds_.height() + kShelfSize); | 
| + | 
| + fullscreen_widget_ = new views::Widget; | 
| views::Widget::InitParams app_list_overlay_view_params( | 
| views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); | 
| + app_list_overlay_view_params.name = "AppList"; | 
| app_list_overlay_view_params.parent = parent; | 
| app_list_overlay_view_params.delegate = this; | 
| app_list_overlay_view_params.opacity = | 
| views::Widget::InitParams::TRANSLUCENT_WINDOW; | 
| - app_list_overlay_view_params.bounds = | 
| - display::Screen::GetScreen()-> | 
| - GetDisplayNearestView(parent).work_area(); | 
| - widget->Init(app_list_overlay_view_params); | 
| - widget->GetLayer()->SetBackgroundBlur(10); | 
| + app_list_overlay_view_params.bounds = app_list_overlay_view_bounds; | 
| + app_list_overlay_view_params.layer_type = ui::LAYER_SOLID_COLOR; | 
| + fullscreen_widget_->Init(app_list_overlay_view_params); | 
| + fullscreen_widget_bounds_ = fullscreen_widget_->GetWindowBoundsInScreen(); | 
| overlay_view_ = new AppListOverlayView(0 /* no corners */); | 
| + | 
| + // Launcher + shelf height, used in HandleDrag. | 
| + launcher_threshold_ = | 
| + (default_peeking_launcher_y_ + fullscreen_widget_bounds_.height() - | 
| + fullscreen_widget_bounds_.y()) / | 
| + kLauncherThresholdDenominator; | 
| } | 
| void AppListView::InitializeBubble(gfx::NativeView parent, | 
| @@ -428,7 +474,7 @@ void AppListView::InitializeBubble(gfx::NativeView parent, | 
| set_shadow(views::BubbleBorder::NO_ASSETS); | 
| // This creates the app list widget. (Before this, child widgets cannot be | 
| - // created.) | 
| + // created. | 
| views::BubbleDialogDelegateView::CreateBubble(this); | 
| SetBubbleArrow(views::BubbleBorder::FLOAT); | 
| @@ -443,6 +489,89 @@ void AppListView::InitializeBubble(gfx::NativeView parent, | 
| overlay_view_->SetBoundsRect(GetContentsBounds()); | 
| } | 
| +void AppListView::HandleDrag(gfx::Point location, ui::EventType type) { | 
| + int new_y_position; | 
| 
 
vadimt
2017/05/26 01:27:57
Make a constant variable in each switch branches,
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + switch (type) { | 
| + case ui::ET_GESTURE_SCROLL_BEGIN: | 
| + case ui::ET_MOUSE_PRESSED: { | 
| + // Drag start, grab the initial_drag_separation_ to maintain the relative | 
| + // position of the top of the widget and the mouse/gesture. | 
| + initial_drag_separation_ = location.y(); | 
| + fullscreen_widget_bounds_ = fullscreen_widget_->GetWindowBoundsInScreen(); | 
| + break; | 
| + } | 
| + case ui::ET_GESTURE_SCROLL_UPDATE: | 
| + case ui::ET_MOUSE_DRAGGED: { | 
| + // Drag update, update the bounds of the widget while maintaining the | 
| + // relative position of the top of the widget and the mouse/gesture. | 
| + // Block drags north of 0 and recalculate the initial_drag_separation_. | 
| + new_y_position = location.y() - initial_drag_separation_ + | 
| + fullscreen_widget_bounds_.y(); | 
| + if (new_y_position < 0) { | 
| + fullscreen_widget_bounds_.set_y(0); | 
| + initial_drag_separation_ = location.y(); | 
| + } else { | 
| + fullscreen_widget_bounds_.set_y(new_y_position); | 
| + } | 
| + fullscreen_widget_->SetBounds(fullscreen_widget_bounds_); | 
| + break; | 
| + } | 
| + | 
| + case ui::ET_GESTURE_END: | 
| + case ui::ET_MOUSE_RELEASED: { | 
| + // Drag completion, either snap to fullscreen or close the App List based | 
| + // on where the drag ended. If fling velocity was over the threshold, snap | 
| + // to the next state in the direction of the fling. | 
| + new_y_position = location.y() - initial_drag_separation_ + | 
| + fullscreen_widget_bounds_.y(); | 
| + if (std::abs(last_fling_velocity_) > kLauncherDragVelocityThreshold) { | 
| + // If the user releases drag with velocity over the threshold, snap to | 
| + // the next state, ignoring the drag release position. | 
| + if (is_fullscreen_launcher_) { | 
| + if (last_fling_velocity_ > 0) | 
| + ToPeeking(); | 
| 
 
vadimt
2017/05/26 01:27:57
{}, as this is a complex if
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + } else { | 
| + if (last_fling_velocity_ > 0) { | 
| 
 
vadimt
2017/05/26 01:27:57
No need for placing 'else' contents in {}, unless
 
newcomer
2017/05/26 17:11:27
I did it for clarity but I see how it isn't necess
 
 | 
| + CloseAppList(); | 
| + } else if (last_fling_velocity_ < 0) { | 
| + ToFullscreen(); | 
| + } | 
| + } | 
| + last_fling_velocity_ = 0; | 
| + } else { | 
| + // The drag release velocity was too low, so use the release point. | 
| + int launcher_snap_y = | 
| + is_fullscreen_launcher_ ? 0 : default_peeking_launcher_y_; | 
| + // If the user releases +/- 1/3 of launcher_threshold_ , snap to the | 
| + // next state. | 
| + if (std::abs(launcher_snap_y - new_y_position) < | 
| + (launcher_threshold_)) { | 
| + // If the drag released to the state above. | 
| + if (is_fullscreen_launcher_) { | 
| + ToFullscreen(); | 
| + } else { | 
| + ToPeeking(); | 
| + } | 
| + } else if ((launcher_snap_y + (launcher_threshold_)) < new_y_position) { | 
| + // If the user released to the state below. | 
| + if (is_fullscreen_launcher_) { | 
| + ToPeeking(); | 
| + } else { | 
| + CloseAppList(); | 
| + } | 
| + } else { | 
| + // if the user released to the state above, go to the state above. | 
| + ToFullscreen(); | 
| + } | 
| + } | 
| + break; | 
| + } | 
| + default: | 
| + NOTREACHED(); | 
| + break; | 
| + } | 
| +} | 
| + | 
| void AppListView::OnBeforeBubbleWidgetInit(views::Widget::InitParams* params, | 
| views::Widget* widget) const { | 
| if (!params->native_widget) { | 
| @@ -476,6 +605,38 @@ void AppListView::GetWidgetHitTestMask(gfx::Path* mask) const { | 
| mask->addRect(gfx::RectToSkRect(GetBubbleFrameView()->GetContentsBounds())); | 
| } | 
| +void AppListView::OnMouseEvent(ui::MouseEvent* event) { | 
| + if (!launcher_background_shield_) | 
| + return; | 
| + | 
| + switch (event->type()) { | 
| + case ui::ET_MOUSE_PRESSED: | 
| + case ui::ET_MOUSE_DRAGGED: | 
| + case ui::ET_MOUSE_RELEASED: | 
| + HandleDrag(event->location(), event->type()); | 
| + event->SetHandled(); | 
| + break; | 
| + default: | 
| + break; | 
| + } | 
| +} | 
| + | 
| +void AppListView::OnGestureEvent(ui::GestureEvent* event) { | 
| + if (!launcher_background_shield_) | 
| + return; | 
| + switch (event->type()) { | 
| 
 
vadimt
2017/05/26 01:27:57
Empty line before.
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + case ui::ET_GESTURE_SCROLL_UPDATE: | 
| + last_fling_velocity_ = event->details().velocity_y(); | 
| 
 
vadimt
2017/05/26 01:27:57
break;
If this is what you wanted, this don't use
 
newcomer
2017/05/26 17:11:27
Done.
 
 | 
| + case ui::ET_GESTURE_SCROLL_BEGIN: | 
| + case ui::ET_GESTURE_END: | 
| + HandleDrag(event->location(), event->type()); | 
| + event->SetHandled(); | 
| + break; | 
| + default: | 
| + break; | 
| + } | 
| +} | 
| + | 
| bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) { | 
| DCHECK_EQ(ui::VKEY_ESCAPE, accelerator.key_code()); | 
| @@ -491,6 +652,23 @@ bool AppListView::AcceleratorPressed(const ui::Accelerator& accelerator) { | 
| } | 
| void AppListView::Layout() { | 
| + // If the fullscreen feature has been enabled. | 
| + if (launcher_background_shield_) { | 
| + UpdateDimensions(); | 
| + | 
| + gfx::Rect recomputed_fullscreen_widget_bounds( | 
| + display_work_area_bounds_.x(), default_peeking_launcher_y_, | 
| + display_work_area_bounds_.width(), | 
| + display_work_area_bounds_.height() + kShelfSize); | 
| + | 
| + fullscreen_widget_bounds_ = recomputed_fullscreen_widget_bounds; | 
| + | 
| + if (is_fullscreen_launcher_) { | 
| + ToFullscreen(); | 
| + } else { | 
| + ToPeeking(); | 
| + } | 
| + } | 
| const gfx::Rect contents_bounds = GetContentsBounds(); | 
| // Make sure to layout |app_list_main_view_| and |speech_view_| at the center | 
| @@ -511,6 +689,11 @@ void AppListView::Layout() { | 
| speech_bounds.Inset(-speech_view_->GetInsets()); | 
| speech_view_->SetBoundsRect(speech_bounds); | 
| } | 
| + // If the fullscreen feature has been enabled. | 
| + if (launcher_background_shield_) { | 
| + app_list_main_view_->contents_view()->Layout(); | 
| + launcher_background_shield_->SetBoundsRect(contents_bounds); | 
| + } | 
| } | 
| void AppListView::SchedulePaintInRect(const gfx::Rect& rect) { | 
| @@ -519,6 +702,35 @@ void AppListView::SchedulePaintInRect(const gfx::Rect& rect) { | 
| GetBubbleFrameView()->SchedulePaint(); | 
| } | 
| +void AppListView::UpdateDimensions() { | 
| + display_work_area_bounds_ = display::Screen::GetScreen() | 
| + ->GetDisplayNearestView(parent_window()) | 
| + .work_area(); | 
| + default_peeking_launcher_y_ = | 
| + display_work_area_bounds_.height() + kShelfSize - kPeekingLauncherHeight; | 
| +} | 
| + | 
| +void AppListView::ToFullscreen() { | 
| + fullscreen_widget_bounds_.set_y(0); | 
| + fullscreen_widget_->SetBounds(fullscreen_widget_bounds_); | 
| + is_fullscreen_launcher_ = true; | 
| + launcher_threshold_ = (fullscreen_widget_bounds_.height() + kShelfSize) / | 
| + kLauncherThresholdDenominator; | 
| +} | 
| + | 
| +void AppListView::ToPeeking() { | 
| + fullscreen_widget_bounds_.set_y(default_peeking_launcher_y_); | 
| + fullscreen_widget_->SetBounds(fullscreen_widget_bounds_); | 
| + is_fullscreen_launcher_ = false; | 
| + launcher_threshold_ = (fullscreen_widget_bounds_.height() + kShelfSize - | 
| + kPeekingLauncherHeight) / | 
| + kLauncherThresholdDenominator; | 
| +} | 
| + | 
| +bool AppListView::IsFullscreen() const { | 
| + return is_fullscreen_launcher_; | 
| +} | 
| + | 
| void AppListView::OnWidgetDestroying(views::Widget* widget) { | 
| BubbleDialogDelegateView::OnWidgetDestroying(widget); | 
| if (delegate_ && widget == GetWidget()) | 
| @@ -603,4 +815,9 @@ void AppListView::OnSpeechRecognitionStateChanged( | 
| } | 
| } | 
| +void AppListView::OnDisplayMetricsChanged(const display::Display& display, | 
| + uint32_t changed_metrics) { | 
| + Layout(); | 
| +} | 
| + | 
| } // namespace app_list |