| 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 060e7d718b0806e9c333653e0f6d5274b17a4e10..a4a57f9f653204b1215849092131bfa153412077 100644
|
| --- a/ui/app_list/views/app_list_view.cc
|
| +++ b/ui/app_list/views/app_list_view.cc
|
| @@ -53,10 +53,27 @@ namespace app_list {
|
| namespace {
|
|
|
| // The margin from the edge to the speech UI.
|
| -const int kSpeechUIMargin = 12;
|
| +constexpr int kSpeechUIMargin = 12;
|
| +
|
| +// The height/width of the shelf.
|
| +constexpr int kShelfSize = 48;
|
| +
|
| +// The height of the peeking launcher.
|
| +constexpr int kPeekingLauncherHeight = 320;
|
| +
|
| +// The fraction of launcher height that the launcher must be released at in
|
| +// order to transition to the next state.
|
| +constexpr int kLauncherThresholdDenominator = 3;
|
| +
|
| +// The velocity the launcher must be dragged in order to transition to the next
|
| +// state, measured in DIPs/event.
|
| +constexpr int kLauncherDragVelocityThreshold = 25;
|
| +
|
| +// The opacity of the launcher background.
|
| +constexpr float kLauncherOpacity = 0.8;
|
|
|
| // The vertical position for the appearing animation of the speech UI.
|
| -const float kSpeechUIAppearingPosition = 12;
|
| +constexpr float kSpeechUIAppearingPosition = 12;
|
|
|
| // This view forwards the focus to the search box widget by providing it as a
|
| // FocusTraversable when a focus search is provided.
|
| @@ -174,11 +191,15 @@ AppListView::AppListView(AppListViewDelegate* delegate)
|
| search_box_focus_host_(nullptr),
|
| search_box_widget_(nullptr),
|
| search_box_view_(nullptr),
|
| + 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());
|
| }
|
|
|
| AppListView::~AppListView() {
|
| @@ -202,8 +223,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);
|
| }
|
| @@ -236,10 +259,18 @@ void AppListView::CloseAppList() {
|
|
|
| void AppListView::UpdateBounds() {
|
| // if the AppListView is a bubble
|
| - if (!features::IsFullscreenAppListEnabled())
|
| + if (!launcher_background_shield_)
|
| SizeToContents();
|
| }
|
|
|
| +void AppListView::UpdateDimensions() {
|
| + display_work_area_bounds_ = display::Screen::GetScreen()
|
| + ->GetDisplayNearestView(parent_window())
|
| + .work_area();
|
| + default_y_for_state_ =
|
| + display_work_area_bounds_.height() + kShelfSize - kPeekingLauncherHeight;
|
| +}
|
| +
|
| void AppListView::SetAppListOverlayVisible(bool visible) {
|
| DCHECK(overlay_view_);
|
|
|
| @@ -329,14 +360,23 @@ void AppListView::InitContents(gfx::NativeView parent, int initial_apps_page) {
|
| FROM_HERE_WITH_EXPLICIT_FUNCTION(
|
| "440224, 441028 AppListView::InitContents"));
|
|
|
| - app_list_main_view_ = new AppListMainView(delegate_);
|
| + 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(kLauncherOpacity);
|
| + AddChildView(launcher_background_shield_);
|
| + }
|
| + app_list_main_view_ = new AppListMainView(delegate_, this);
|
| AddChildView(app_list_main_view_);
|
| app_list_main_view_->SetPaintToLayer();
|
| app_list_main_view_->layer()->SetFillsBoundsOpaquely(false);
|
| app_list_main_view_->layer()->SetMasksToBounds(true);
|
| // 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_ = new SearchBoxView(app_list_main_view_, delegate_, this);
|
| search_box_view_->SetPaintToLayer();
|
| search_box_view_->layer()->SetFillsBoundsOpaquely(false);
|
| search_box_view_->layer()->SetMasksToBounds(true);
|
| @@ -403,21 +443,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_y_for_state_,
|
| + 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_y_for_state_ + fullscreen_widget_bounds_.height() -
|
| + fullscreen_widget_bounds_.y()) /
|
| + kLauncherThresholdDenominator;
|
| }
|
|
|
| void AppListView::InitializeBubble(gfx::NativeView parent,
|
| @@ -427,7 +480,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);
|
| @@ -442,6 +495,96 @@ void AppListView::InitializeBubble(gfx::NativeView parent,
|
| overlay_view_->SetBoundsRect(GetContentsBounds());
|
| }
|
|
|
| +void AppListView::HandleDrag(const gfx::Point& location, ui::EventType type) {
|
| + switch (type) {
|
| + case ui::ET_GESTURE_SCROLL_BEGIN:
|
| + case ui::ET_MOUSE_PRESSED: {
|
| + StartDrag(location);
|
| + break;
|
| + }
|
| + case ui::ET_GESTURE_SCROLL_UPDATE:
|
| + case ui::ET_MOUSE_DRAGGED: {
|
| + UpdateDrag(location);
|
| + break;
|
| + }
|
| + case ui::ET_GESTURE_END:
|
| + case ui::ET_MOUSE_RELEASED: {
|
| + EndDrag(location);
|
| + break;
|
| + }
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +}
|
| +
|
| +void AppListView::StartDrag(const gfx::Point& location) {
|
| + initial_drag_separation_ = location.y();
|
| + fullscreen_widget_bounds_ = fullscreen_widget_->GetWindowBoundsInScreen();
|
| +}
|
| +
|
| +void AppListView::UpdateDrag(const gfx::Point& location) {
|
| + // 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_.
|
| + int const 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_);
|
| +}
|
| +
|
| +void AppListView::EndDrag(const gfx::Point& location) {
|
| + // Change the launcher state based on where the drag ended. If fling velocity
|
| + // was over the threshold, snap to the next state in the direction of the
|
| + // fling.
|
| + int const 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();
|
| + }
|
| + } else {
|
| + if (last_fling_velocity_ > 0) {
|
| + 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_y_for_state_;
|
| + // 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();
|
| + }
|
| + }
|
| +}
|
| +
|
| void AppListView::OnBeforeBubbleWidgetInit(views::Widget::InitParams* params,
|
| views::Widget* widget) const {
|
| if (!params->native_widget) {
|
| @@ -475,6 +618,42 @@ 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()) {
|
| + case ui::ET_GESTURE_SCROLL_UPDATE:
|
| + last_fling_velocity_ = event->details().velocity_y();
|
| + HandleDrag(event->location(), event->type());
|
| + event->SetHandled();
|
| + break;
|
| + 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());
|
|
|
| @@ -510,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) {
|
| @@ -518,6 +702,27 @@ void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
|
| GetBubbleFrameView()->SchedulePaint();
|
| }
|
|
|
| +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_y_for_state_);
|
| + 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())
|
| @@ -602,4 +807,25 @@ void AppListView::OnSpeechRecognitionStateChanged(
|
| }
|
| }
|
|
|
| +void AppListView::OnDisplayMetricsChanged(const display::Display& display,
|
| + uint32_t changed_metrics) {
|
| + if (!launcher_background_shield_)
|
| + return;
|
| +
|
| + UpdateDimensions();
|
| +
|
| + gfx::Rect recomputed_fullscreen_widget_bounds(
|
| + display_work_area_bounds_.x(), default_y_for_state_,
|
| + 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();
|
| + }
|
| +}
|
| +
|
| } // namespace app_list
|
|
|