123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/app_list/views/apps_container_view.h"
- #include <algorithm>
- #include <memory>
- #include <utility>
- #include <vector>
- #include "ash/app_list/app_list_model_provider.h"
- #include "ash/app_list/app_list_util.h"
- #include "ash/app_list/views/app_list_a11y_announcer.h"
- #include "ash/app_list/views/app_list_folder_view.h"
- #include "ash/app_list/views/app_list_item_view.h"
- #include "ash/app_list/views/app_list_keyboard_controller.h"
- #include "ash/app_list/views/app_list_main_view.h"
- #include "ash/app_list/views/app_list_nudge_controller.h"
- #include "ash/app_list/views/app_list_toast_container_view.h"
- #include "ash/app_list/views/app_list_toast_view.h"
- #include "ash/app_list/views/app_list_view.h"
- #include "ash/app_list/views/contents_view.h"
- #include "ash/app_list/views/continue_section_view.h"
- #include "ash/app_list/views/folder_background_view.h"
- #include "ash/app_list/views/page_switcher.h"
- #include "ash/app_list/views/recent_apps_view.h"
- #include "ash/app_list/views/search_box_view.h"
- #include "ash/app_list/views/search_result_page_dialog_controller.h"
- #include "ash/app_list/views/suggestion_chip_container_view.h"
- #include "ash/constants/ash_features.h"
- #include "ash/controls/gradient_layer_delegate.h"
- #include "ash/keyboard/ui/keyboard_ui_controller.h"
- #include "ash/public/cpp/app_list/app_list_config.h"
- #include "ash/public/cpp/app_list/app_list_model_delegate.h"
- #include "ash/public/cpp/app_list/app_list_switches.h"
- #include "ash/public/cpp/shelf_config.h"
- #include "ash/public/cpp/style/color_provider.h"
- #include "ash/search_box/search_box_constants.h"
- #include "ash/strings/grit/ash_strings.h"
- #include "base/bind.h"
- #include "base/check.h"
- #include "base/command_line.h"
- #include "base/cxx17_backports.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/time/time.h"
- #include "ui/base/l10n/l10n_util.h"
- #include "ui/base/metadata/metadata_impl_macros.h"
- #include "ui/color/color_id.h"
- #include "ui/compositor/layer.h"
- #include "ui/compositor/layer_animation_element.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/gfx/geometry/rect_conversions.h"
- #include "ui/gfx/geometry/transform.h"
- #include "ui/gfx/paint_vector_icon.h"
- #include "ui/strings/grit/ui_strings.h"
- #include "ui/views/accessibility/view_accessibility.h"
- #include "ui/views/animation/animation_builder.h"
- #include "ui/views/controls/button/label_button.h"
- #include "ui/views/controls/separator.h"
- #include "ui/views/controls/textfield/textfield.h"
- #include "ui/views/focus/focus_manager.h"
- #include "ui/views/layout/flex_layout.h"
- #include "ui/views/view_class_properties.h"
- #include "ui/views/view_utils.h"
- namespace ash {
- namespace {
- // The number of rows for portrait mode with mode productivity launcher
- // enabled.
- constexpr int kPreferredGridRowsInPortraitProductivityLauncher = 5;
- // The number of columns for portrait mode with productivity launcher enabled.
- constexpr int kPreferredGridColumnsInPortraitProductivityLauncher = 5;
- // The long apps grid dimension when productivity launcher is not enabled:
- // * number of columns in landscape mode
- // * number of rows in portrait mode
- constexpr int kPreferredGridColumns = 5;
- // The short apps grid dimension when productivity launcher is not enabled:
- // * number of rows in landscape mode
- // * number of columns in portrait mode
- constexpr int kPreferredGridRows = 4;
- // The range of app list transition progress in which the suggestion chips'
- // opacity changes from 0 to 1.
- constexpr float kSuggestionChipOpacityStartProgress = 0.66;
- constexpr float kSuggestionChipOpacityEndProgress = 1;
- // Range of the height of centerline above screen bottom that all apps should
- // change opacity. NOTE: this is used to change page switcher's opacity as
- // well.
- constexpr float kAppsOpacityChangeStart = 8.0f;
- constexpr float kAppsOpacityChangeEnd = 144.0f;
- // The app list transition progress value for fullscreen state.
- constexpr float kAppListFullscreenProgressValue = 2.0;
- // The amount by which the apps container UI should be offset downwards when
- // shown on non apps page UI.
- constexpr int kNonAppsStateVerticalOffset = 24;
- // The opacity the apps container UI should have when shown on non apps page UI.
- constexpr float kNonAppsStateOpacity = 0.1;
- // The ratio of allowed bounds for apps grid view to its maximum margin.
- constexpr int kAppsGridMarginRatio = 16;
- constexpr int kAppsGridMarginRatioForSmallWidth = 12;
- constexpr int kAppsGridMarginRatioForSmallHeight = 24;
- // The margins within the apps container for app list folder view.
- constexpr int kFolderMargin = 16;
- // The suggestion chip container height.
- constexpr int kSuggestionChipContainerHeight = 32;
- // The suggestion chip container top margin.
- constexpr int kSuggestionChipContainerTopMargin = 16;
- // The horizontal margin between the apps grid view and the page switcher.
- constexpr int kGridToPageSwitcherMargin = 8;
- // Minimal horizontal distance from the page switcher to apps container bounds.
- constexpr int kPageSwitcherEndMargin = 16;
- // The minimum amount of vertical margin between the apps container edges and
- // the its contents.
- constexpr int kMinimumVerticalContainerMargin = 24;
- // The vertical margin above the `AppsGridView`. The space between suggestion
- // chips and the app grid. With Productivity launcher, the space between the
- // search box and the app grid.
- constexpr int kAppGridTopMargin = 24;
- // The number of columns available for the ContinueSectionView.
- constexpr int kContinueColumnCount = 4;
- // The vertical spacing between recent apps and continue section view.
- constexpr int kRecentAppsTopMargin = 16;
- // The vertical spacing above and below the separator when using kRegular/kDense
- // AppListConfigType.
- constexpr int kRegularSeparatorVerticalInset = 16;
- constexpr int kDenseSeparatorVerticalInset = 8;
- // The width of the separator.
- constexpr int kSeparatorWidth = 240;
- // The actual height of the fadeout gradient mask at the top and bottom of the
- // `scrollable_container_`.
- constexpr int kDefaultFadeoutMaskHeight = 16;
- // Max amount of time to wait for zero state results when refreshing recent apps
- // and continue section when launcher becomes visible.
- constexpr base::TimeDelta kZeroStateSearchTimeout = base::Milliseconds(16);
- } // namespace
- // A view that contains continue section, recent apps and a separator view,
- // which is shown when any of other views is shown.
- // The view is intended to be a wrapper around suggested content views that
- // makes applying identical transforms to suggested content views easier.
- class AppsContainerView::ContinueContainer : public views::View {
- public:
- ContinueContainer(AppListKeyboardController* keyboard_controller,
- AppListViewDelegate* view_delegate,
- views::Separator* separator)
- : view_delegate_(view_delegate), separator_(separator) {
- DCHECK(view_delegate_);
- DCHECK(separator_);
- SetPaintToLayer(ui::LAYER_NOT_DRAWN);
- SetLayoutManager(std::make_unique<views::FlexLayout>())
- ->SetOrientation(views::LayoutOrientation::kVertical);
- continue_section_ = AddChildView(std::make_unique<ContinueSectionView>(
- view_delegate, kContinueColumnCount,
- /*tablet_mode=*/true));
- continue_section_->SetPaintToLayer();
- continue_section_->layer()->SetFillsBoundsOpaquely(false);
- recent_apps_ = AddChildView(
- std::make_unique<RecentAppsView>(keyboard_controller, view_delegate));
- recent_apps_->SetPaintToLayer();
- recent_apps_->layer()->SetFillsBoundsOpaquely(false);
- UpdateRecentAppsMargins();
- UpdateContinueSectionVisibility();
- }
- // views::View:
- void ChildVisibilityChanged(views::View* child) override {
- if (child == recent_apps_ || child == continue_section_)
- UpdateSeparatorVisibility();
- if (child == continue_section_)
- UpdateRecentAppsMargins();
- }
- bool HasRecentApps() const { return recent_apps_->GetVisible(); }
- void UpdateAppListConfig(AppListConfig* config) {
- recent_apps_->UpdateAppListConfig(config);
- }
- void UpdateContinueSectionVisibility() {
- // The continue section view and recent apps view manage their own
- // visibility internally.
- continue_section_->UpdateElementsVisibility();
- recent_apps_->UpdateVisibility();
- UpdateSeparatorVisibility();
- }
- // Animates a fade-in for the continue section, recent apps and separator.
- void FadeInViews() {
- continue_section_->layer()->SetOpacity(0.0f);
- recent_apps_->layer()->SetOpacity(0.0f);
- separator_->layer()->SetOpacity(0.0f);
- views::AnimationBuilder()
- .SetPreemptionStrategy(ui::LayerAnimator::PreemptionStrategy::
- IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
- .Once()
- .At(base::Milliseconds(100))
- .SetOpacity(continue_section_, 1.0f)
- .SetOpacity(recent_apps_, 1.0f)
- .SetOpacity(separator_, 1.0f)
- .SetDuration(base::Milliseconds(200));
- }
- ContinueSectionView* continue_section() { return continue_section_; }
- RecentAppsView* recent_apps() { return recent_apps_; }
- private:
- void UpdateRecentAppsMargins() {
- // Remove recent apps top margin if continue section is hidden.
- recent_apps_->SetProperty(
- views::kMarginsKey,
- gfx::Insets::TLBR(
- continue_section_->GetVisible() ? kRecentAppsTopMargin : 0, 0, 0,
- 0));
- }
- void UpdateSeparatorVisibility() {
- separator_->SetVisible(recent_apps_->GetVisible() ||
- continue_section_->GetVisible());
- }
- AppListViewDelegate* const view_delegate_;
- ContinueSectionView* continue_section_ = nullptr;
- RecentAppsView* recent_apps_ = nullptr;
- views::Separator* separator_ = nullptr;
- };
- AppsContainerView::AppsContainerView(ContentsView* contents_view)
- : contents_view_(contents_view),
- app_list_keyboard_controller_(
- std::make_unique<AppListKeyboardController>(this)),
- app_list_nudge_controller_(std::make_unique<AppListNudgeController>()) {
- AppListModelProvider::Get()->AddObserver(this);
- SetPaintToLayer(ui::LAYER_NOT_DRAWN);
- scrollable_container_ = AddChildView(std::make_unique<views::View>());
- scrollable_container_->SetPaintToLayer(ui::LAYER_NOT_DRAWN);
- AppListViewDelegate* view_delegate =
- contents_view_->GetAppListMainView()->view_delegate();
- // The bounds of the |scrollable_container_| will visually clip the
- // |continue_container_| and |apps_grid_view_| layers.
- scrollable_container_->layer()->SetMasksToBounds(true);
- AppListA11yAnnouncer* a11y_announcer =
- contents_view->app_list_view()->a11y_announcer();
- if (features::IsProductivityLauncherEnabled()) {
- separator_ = scrollable_container_->AddChildView(
- std::make_unique<views::Separator>());
- separator_->SetColorId(ui::kColorAshSystemUIMenuSeparator);
- separator_->SetPreferredSize(
- gfx::Size(kSeparatorWidth, views::Separator::kThickness));
- // Initially set the vertical inset to kRegularSeparatorVerticalInset. The
- // value will be updated in `AppsContainerView::UpdateAppListConfig()`
- separator_->SetProperty(views::kMarginsKey,
- gfx::Insets::VH(kRegularSeparatorVerticalInset, 0));
- separator_->SetPaintToLayer();
- separator_->layer()->SetFillsBoundsOpaquely(false);
- // Visibility for `separator_` will be managed by the `continue_container_`.
- separator_->SetVisible(false);
- dialog_controller_ = std::make_unique<SearchResultPageDialogController>(
- contents_view_->GetSearchBoxView());
- continue_container_ =
- scrollable_container_->AddChildView(std::make_unique<ContinueContainer>(
- app_list_keyboard_controller_.get(), view_delegate, separator_));
- continue_container_->continue_section()->SetNudgeController(
- app_list_nudge_controller_.get());
- // Update the suggestion tasks after the app list nudge controller is set in
- // continue section.
- continue_container_->continue_section()->UpdateSuggestionTasks();
- // Add a empty container view. A toast view should be added to
- // `toast_container_` when the app list starts temporary sorting.
- if (features::IsLauncherAppSortEnabled()) {
- toast_container_ = scrollable_container_->AddChildView(
- std::make_unique<AppListToastContainerView>(
- app_list_nudge_controller_.get(),
- app_list_keyboard_controller_.get(), a11y_announcer,
- view_delegate,
- /*delegate=*/this, /*tablet_mode=*/true));
- toast_container_->SetPaintToLayer(ui::LAYER_NOT_DRAWN);
- }
- } else {
- // Add child view at index 0 so focus traversal goes to suggestion chips
- // before the views in the scrollable_container.
- suggestion_chip_container_view_ = AddChildViewAt(
- std::make_unique<SuggestionChipContainerView>(contents_view), 0);
- }
- apps_grid_view_ =
- scrollable_container_->AddChildView(std::make_unique<PagedAppsGridView>(
- contents_view, a11y_announcer,
- /*folder_delegate=*/nullptr,
- /*folder_controller=*/this,
- /*container_delegate=*/this, app_list_keyboard_controller_.get()));
- apps_grid_view_->Init();
- apps_grid_view_->pagination_model()->AddObserver(this);
- if (features::IsProductivityLauncherEnabled())
- apps_grid_view_->set_margin_for_gradient_mask(kDefaultFadeoutMaskHeight);
- // Page switcher should be initialized after AppsGridView.
- auto page_switcher = std::make_unique<PageSwitcher>(
- apps_grid_view_->pagination_model(), true /* vertical */,
- contents_view->app_list_view()->is_tablet_mode());
- page_switcher_ = AddChildView(std::move(page_switcher));
- auto app_list_folder_view = std::make_unique<AppListFolderView>(
- this, apps_grid_view_, contents_view_, a11y_announcer, view_delegate);
- folder_background_view_ = AddChildView(
- std::make_unique<FolderBackgroundView>(app_list_folder_view.get()));
- app_list_folder_view_ = AddChildView(std::move(app_list_folder_view));
- // The folder view is initially hidden.
- app_list_folder_view_->SetVisible(false);
- // NOTE: At this point, the apps grid folder and recent apps grids are not
- // fully initialized - they require an `app_list_config_` instance (because
- // they contain AppListItemView), which in turn requires widget, and the
- // view's contents bounds to be correctly calculated. The initialization
- // will be completed in `OnBoundsChanged()` when the apps container bounds are
- // first set.
- }
- AppsContainerView::~AppsContainerView() {
- AppListModelProvider::Get()->RemoveObserver(this);
- apps_grid_view_->pagination_model()->RemoveObserver(this);
- // Make sure |page_switcher_| is deleted before |apps_grid_view_| because
- // |page_switcher_| uses the PaginationModel owned by |apps_grid_view_|.
- delete page_switcher_;
- // App list folder view, if shown, may reference/observe a root apps grid view
- // item (associated with the item for which the folder is shown). Delete
- // `app_list_folder_view_` explicitly to ensure it's deleted before
- // `apps_grid_view_`.
- delete app_list_folder_view_;
- }
- void AppsContainerView::UpdateTopLevelGridDimensions() {
- const GridLayout grid_layout = CalculateGridLayout();
- apps_grid_view_->SetMaxColumnsAndRows(
- /*max_columns=*/grid_layout.columns,
- /*max_rows_on_first_page=*/grid_layout.first_page_rows,
- /*max_rows=*/grid_layout.rows);
- }
- gfx::Rect AppsContainerView::CalculateAvailableBoundsForAppsGrid(
- const gfx::Rect& contents_bounds) const {
- gfx::Rect available_bounds = contents_bounds;
- // Reserve horizontal margins to accommodate page switcher.
- available_bounds.Inset(
- gfx::Insets::VH(0, GetMinHorizontalMarginForAppsGrid()));
- // Reserve vertical space for search box and suggestion chips.
- available_bounds.Inset(gfx::Insets().set_top(GetMinTopMarginForAppsGrid(
- contents_view_->GetSearchBoxSize(AppListState::kStateApps))));
- // Remove space for vertical margins at the top and bottom of the apps
- // container.
- if (features::IsProductivityLauncherEnabled()) {
- available_bounds.Inset(gfx::Insets::VH(GetIdealVerticalMargin(), 0));
- } else {
- available_bounds.Inset(gfx::Insets::VH(kMinimumVerticalContainerMargin, 0));
- }
- return available_bounds;
- }
- void AppsContainerView::UpdateAppListConfig(const gfx::Rect& contents_bounds) {
- // For productivity launcher, the rows for this grid layout will be ignored
- // during creation of a new config.
- GridLayout grid_layout = CalculateGridLayout();
- const gfx::Rect available_bounds =
- CalculateAvailableBoundsForAppsGrid(contents_bounds);
- std::unique_ptr<AppListConfig> new_config =
- AppListConfigProvider::Get().CreateForFullscreenAppList(
- display::Screen::GetScreen()
- ->GetDisplayNearestView(GetWidget()->GetNativeView())
- .work_area()
- .size(),
- grid_layout.rows, grid_layout.columns, available_bounds.size(),
- app_list_config_.get());
- // `CreateForFullscreenAppList()` will create a new config only if it differs
- // from the current `app_list_config_`. Nothing to do if the old
- // `AppListConfig` can be used for the updated apps container bounds.
- if (!new_config)
- return;
- // Keep old config around until child views have been updated to use the new
- // config.
- auto old_config = std::move(app_list_config_);
- app_list_config_ = std::move(new_config);
- // Invalidate the cached container margins - app list config change generally
- // changes preferred apps grid margins, which can influence the container
- // margins.
- cached_container_margins_ = CachedContainerMargins();
- if (separator_) {
- const int separator_vertical_inset =
- app_list_config_->type() == AppListConfigType::kRegular
- ? kRegularSeparatorVerticalInset
- : kDenseSeparatorVerticalInset;
- separator_->SetProperty(views::kMarginsKey,
- gfx::Insets::VH(separator_vertical_inset, 0));
- }
- apps_grid_view()->UpdateAppListConfig(app_list_config_.get());
- app_list_folder_view()->UpdateAppListConfig(app_list_config_.get());
- if (continue_container_)
- continue_container_->UpdateAppListConfig(app_list_config_.get());
- }
- void AppsContainerView::OnActiveAppListModelsChanged(
- AppListModel* model,
- SearchModel* search_model) {
- // Nothing to do if the apps grid views have not yet been initialized.
- if (!app_list_config_)
- return;
- UpdateForActiveAppListModel();
- }
- void AppsContainerView::ShowFolderForItemView(AppListItemView* folder_item_view,
- bool focus_name_input,
- base::OnceClosure hide_callback) {
- // Prevent new animations from starting if there are currently animations
- // pending. This fixes crbug.com/357099.
- if (app_list_folder_view_->IsAnimationRunning())
- return;
- DCHECK(folder_item_view->is_folder());
- UMA_HISTOGRAM_ENUMERATION("Apps.AppListFolderOpened",
- kFullscreenAppListFolders, kMaxFolderOpened);
- app_list_folder_view_->ConfigureForFolderItemView(folder_item_view,
- std::move(hide_callback));
- SetShowState(SHOW_ACTIVE_FOLDER, false);
- // If there is no selected view in the root grid when a folder is opened,
- // silently focus the first item in the folder to avoid showing the selection
- // highlight or announcing to A11y, but still ensuring the arrow keys navigate
- // from the first item.
- if (focus_name_input) {
- app_list_folder_view_->FocusNameInput();
- } else {
- const bool silently = !apps_grid_view()->has_selected_view();
- app_list_folder_view_->FocusFirstItem(silently);
- }
- // Disable all the items behind the folder so that they will not be reached
- // during focus traversal.
- DisableFocusForShowingActiveFolder(true);
- }
- void AppsContainerView::ShowApps(AppListItemView* folder_item_view,
- bool select_folder) {
- DVLOG(1) << __FUNCTION__;
- if (app_list_folder_view_->IsAnimationRunning())
- return;
- const bool animate = !!folder_item_view;
- SetShowState(SHOW_APPS, animate);
- DisableFocusForShowingActiveFolder(false);
- if (folder_item_view) {
- // Focus `folder_item_view` but only show the selection highlight if there
- // was already one showing.
- if (select_folder)
- folder_item_view->RequestFocus();
- else
- folder_item_view->SilentlyRequestFocus();
- }
- }
- void AppsContainerView::ResetForShowApps() {
- DVLOG(1) << __FUNCTION__;
- UpdateSuggestionChips();
- UpdateRecentApps(/*needs_layout=*/false);
- SetShowState(SHOW_APPS, false);
- DisableFocusForShowingActiveFolder(false);
- }
- void AppsContainerView::SetDragAndDropHostOfCurrentAppList(
- ApplicationDragAndDropHost* drag_and_drop_host) {
- apps_grid_view()->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
- app_list_folder_view()->items_grid_view()->SetDragAndDropHostOfCurrentAppList(
- drag_and_drop_host);
- }
- void AppsContainerView::ReparentFolderItemTransit(
- AppListFolderItem* folder_item) {
- if (app_list_folder_view_->IsAnimationRunning())
- return;
- SetShowState(SHOW_ITEM_REPARENT, false);
- DisableFocusForShowingActiveFolder(false);
- }
- bool AppsContainerView::IsInFolderView() const {
- return show_state_ == SHOW_ACTIVE_FOLDER;
- }
- void AppsContainerView::ReparentDragEnded() {
- DVLOG(1) << __FUNCTION__;
- // The container will be showing apps if the folder was deleted mid-drag.
- if (show_state_ == SHOW_APPS)
- return;
- DCHECK_EQ(SHOW_ITEM_REPARENT, show_state_);
- show_state_ = AppsContainerView::SHOW_APPS;
- }
- void AppsContainerView::OnAppListVisibilityWillChange(bool visible) {
- // Start zero state search to refresh contents of the continue section and
- // recent apps (which are only shown for productivity launcher).
- // NOTE: Request another layout after recent apps get updated to handle the
- // case when recent apps get updated during app list state change animation.
- // The apps container layout may get dropped by the app list contents view,
- // so invalidating recent apps layout when recent apps visibiltiy changes
- // will not work well).
- // TODO(https://crbug.com/1306613): Remove explicit layout once the linked
- // issue is fixed.
- if (visible && features::IsProductivityLauncherEnabled()) {
- contents_view_->GetAppListMainView()->view_delegate()->StartZeroStateSearch(
- base::BindOnce(&AppsContainerView::UpdateRecentApps,
- weak_ptr_factory_.GetWeakPtr(),
- /*needs_layout=*/true),
- kZeroStateSearchTimeout);
- }
- }
- void AppsContainerView::OnAppListVisibilityChanged(bool shown) {
- if (toast_container_) {
- // Updates the visibility state in toast container.
- AppListToastContainerView::VisibilityState state =
- shown ? (is_active_page_
- ? AppListToastContainerView::VisibilityState::kShown
- : AppListToastContainerView::VisibilityState::
- kShownInBackground)
- : AppListToastContainerView::VisibilityState::kHidden;
- toast_container_->UpdateVisibilityState(state);
- // Check if the reorder nudge view needs update if the app list is showing.
- if (shown)
- toast_container_->MaybeUpdateReorderNudgeView();
- }
- // Layout requests may get ignored by apps container's view hierarchy while
- // app list animation is in progress - relayout the container if it needs
- // layout at this point.
- // TODO(https://crbug.com/1306613): Remove explicit layout once the linked
- // issue gets fixed.
- if (shown && needs_layout())
- Layout();
- }
- // PaginationModelObserver:
- void AppsContainerView::SelectedPageChanged(int old_selected,
- int new_selected) {
- // There is no |continue_container_| to translate when productivity launcher
- // is not enabled, so return early.
- if (!features::IsProductivityLauncherEnabled())
- return;
- // |continue_container_| is hidden above the grid when not on the first page.
- gfx::Transform transform;
- gfx::Vector2dF translate;
- translate.set_y(-scrollable_container_->bounds().height() * new_selected);
- transform.Translate(translate);
- continue_container_->layer()->SetTransform(transform);
- separator_->layer()->SetTransform(transform);
- if (toast_container_)
- toast_container_->layer()->SetTransform(transform);
- }
- void AppsContainerView::TransitionChanged() {
- // There is no |continue_container_| to translate when productivity launcher
- // is not enabled, so return early.
- if (!features::IsProductivityLauncherEnabled())
- return;
- auto* pagination_model = apps_grid_view_->pagination_model();
- const PaginationModel::Transition& transition =
- pagination_model->transition();
- if (!pagination_model->is_valid_page(transition.target_page))
- return;
- // Because |continue_container_| only shows on the first page, only update its
- // transform if its page is involved in the transition. Otherwise, there is
- // no need to transform the |continue_container_| because it will remain
- // hidden throughout the transition.
- if (transition.target_page == 0 || pagination_model->selected_page() == 0) {
- const int page_height = scrollable_container_->bounds().height();
- gfx::Vector2dF translate;
- if (transition.target_page == 0) {
- // Scroll the continue section down from above.
- translate.set_y(-page_height + page_height * transition.progress);
- } else {
- // Scroll the continue section upwards
- translate.set_y(-page_height * transition.progress);
- }
- gfx::Transform transform;
- transform.Translate(translate);
- continue_container_->layer()->SetTransform(transform);
- separator_->layer()->SetTransform(transform);
- if (toast_container_)
- toast_container_->layer()->SetTransform(transform);
- }
- }
- void AppsContainerView::TransitionStarted() {
- MaybeCreateGradientMask();
- }
- void AppsContainerView::TransitionEnded() {
- // TODO(crbug.com/1285184): Sometimes gradient mask is not removed because
- // this function does not get called in some cases.
- // Gradient mask is no longer necessary once transition is finished.
- MaybeRemoveGradientMask();
- }
- void AppsContainerView::ScrollStarted() {
- MaybeCreateGradientMask();
- }
- void AppsContainerView::ScrollEnded() {
- // Need to reset the mask because transition will not happen in some
- // cases. (See https://crbug.com/1049275)
- MaybeRemoveGradientMask();
- }
- // PagedAppsGridView::ContainerDelegate:
- bool AppsContainerView::IsPointWithinPageFlipBuffer(
- const gfx::Point& point_in_apps_grid) const {
- // The page flip buffer is the work area bounds excluding shelf bounds, which
- // is the same as AppsContainerView's bounds.
- gfx::Point point = point_in_apps_grid;
- ConvertPointToTarget(apps_grid_view_, this, &point);
- return this->GetContentsBounds().Contains(point);
- }
- bool AppsContainerView::IsPointWithinBottomDragBuffer(
- const gfx::Point& point,
- int page_flip_zone_size) const {
- // The bottom drag buffer is between the bottom of apps grid and top of shelf.
- gfx::Point point_in_parent = point;
- ConvertPointToTarget(apps_grid_view_, this, &point_in_parent);
- gfx::Rect parent_rect = this->GetContentsBounds();
- const int kBottomDragBufferMax = parent_rect.bottom();
- const int kBottomDragBufferMin = scrollable_container_->bounds().bottom() -
- apps_grid_view_->GetInsets().bottom() -
- page_flip_zone_size;
- return point_in_parent.y() > kBottomDragBufferMin &&
- point_in_parent.y() < kBottomDragBufferMax;
- }
- void AppsContainerView::MaybeCreateGradientMask() {
- if (features::IsBackgroundBlurEnabled()) {
- if (!layer()->layer_mask_layer() && !gradient_layer_delegate_) {
- gradient_layer_delegate_ =
- std::make_unique<GradientLayerDelegate>(/*animate_in=*/false);
- UpdateGradientMaskBounds();
- }
- if (gradient_layer_delegate_) {
- scrollable_container_->layer()->SetMaskLayer(
- gradient_layer_delegate_->layer());
- }
- }
- }
- void AppsContainerView::MaybeRemoveGradientMask() {
- if (scrollable_container_->layer()->layer_mask_layer() &&
- !keep_gradient_mask_for_cardified_state_) {
- scrollable_container_->layer()->SetMaskLayer(nullptr);
- }
- }
- void AppsContainerView::OnCardifiedStateStarted() {
- keep_gradient_mask_for_cardified_state_ = true;
- MaybeCreateGradientMask();
- }
- void AppsContainerView::OnCardifiedStateEnded() {
- keep_gradient_mask_for_cardified_state_ = false;
- MaybeRemoveGradientMask();
- }
- void AppsContainerView::OnNudgeRemoved() {
- const int continue_container_height =
- continue_container_->GetPreferredSize().height();
- const int toast_container_height =
- toast_container_ ? toast_container_->GetPreferredSize().height() : 0;
- apps_grid_view_->ConfigureFirstPagePadding(
- continue_container_height + toast_container_height + GetSeparatorHeight(),
- continue_container_->HasRecentApps());
- UpdateTopLevelGridDimensions();
- apps_grid_view_->AnimateOnNudgeRemoved();
- }
- void AppsContainerView::UpdateForNewSortingOrder(
- const absl::optional<AppListSortOrder>& new_order,
- bool animate,
- base::OnceClosure update_position_closure,
- base::OnceClosure animation_done_closure) {
- DCHECK(features::IsLauncherAppSortEnabled());
- DCHECK_EQ(animate, !update_position_closure.is_null());
- DCHECK(!animation_done_closure || animate);
- // A11y announcements must happen before animations, otherwise the undo
- // guidance is spoken first because focus moves immediately to the undo button
- // on the toast.
- if (new_order) {
- toast_container_->AnnounceSortOrder(*new_order);
- } else if (animate) {
- toast_container_->AnnounceUndoSort();
- }
- if (!animate) {
- // Reordering is not required so update the undo toast and return early.
- app_list_nudge_controller_->OnTemporarySortOrderChanged(new_order);
- toast_container_->OnTemporarySortOrderChanged(new_order);
- HandleFocusAfterSort();
- return;
- }
- // If app list sort order change is animated, hide any open folders as part of
- // animation. If the update is not animated, e.g. when committing sort order,
- // keep the folder open to prevent folder closure when apps within the folder
- // are reordered, or whe the folder gets renamed.
- SetShowState(SHOW_APPS, /*show_apps_with_animation=*/false);
- DisableFocusForShowingActiveFolder(false);
- // If `apps_grid_view_` is under page transition animation, finish the
- // animation before starting the reorder animation.
- ash::PaginationModel* pagination_model = apps_grid_view_->pagination_model();
- if (pagination_model->has_transition())
- pagination_model->FinishAnimation();
- // Abort the old reorder animation if any before closure update to avoid data
- // races on closures.
- apps_grid_view_->MaybeAbortWholeGridAnimation();
- DCHECK(!update_position_closure_);
- update_position_closure_ = std::move(update_position_closure);
- DCHECK(!reorder_animation_done_closure_);
- reorder_animation_done_closure_ = std::move(animation_done_closure);
- views::AnimationBuilder animation_builder =
- apps_grid_view_->FadeOutVisibleItemsForReorder(base::BindRepeating(
- &AppsContainerView::OnAppsGridViewFadeOutAnimationEnded,
- weak_ptr_factory_.GetWeakPtr(), new_order));
- // Configure the toast fade out animation if the toast is going to be hidden.
- const bool current_toast_visible = toast_container_->IsToastVisible();
- const bool target_toast_visible =
- toast_container_->GetVisibilityForSortOrder(new_order);
- if (current_toast_visible && !target_toast_visible) {
- animation_builder.GetCurrentSequence().SetOpacity(toast_container_->layer(),
- 0.f);
- }
- }
- void AppsContainerView::UpdateContinueSectionVisibility() {
- if (!continue_container_)
- return;
- // Get the continue container's height before Layout().
- const int initial_height = continue_container_->height();
- // Update continue container visibility and bounds.
- continue_container_->UpdateContinueSectionVisibility();
- Layout();
- // Only play animations if the tablet mode app list is visible. This function
- // can be called in clamshell mode when the tablet app list is cached.
- if (!contents_view_->app_list_view()->is_tablet_mode())
- return;
- // The change in continue container height is the amount by which the apps
- // grid view will be offset.
- const int vertical_offset = initial_height - continue_container_->height();
- AppListViewDelegate* view_delegate =
- contents_view_->GetAppListMainView()->view_delegate();
- if (view_delegate->ShouldHideContinueSection()) {
- // Continue section is being hidden. Slide each row of app icons up with a
- // different offset per row.
- apps_grid_view_->SlideVisibleItemsForHideContinueSection(vertical_offset);
- // Don't try to fade out the views on hide because they are already
- // invisible.
- return;
- }
- // Continue section is being shown. Transform the apps grid view up to its
- // original pre-Layout() position.
- gfx::Transform transform;
- transform.Translate(0, vertical_offset);
- apps_grid_view_->SetTransform(transform);
- // Animate to the identity transform to slide the apps grid view down to its
- // final position.
- views::AnimationBuilder()
- .SetPreemptionStrategy(ui::LayerAnimator::PreemptionStrategy::
- IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
- .Once()
- .SetTransform(apps_grid_view_, gfx::Transform(),
- gfx::Tween::ACCEL_LIN_DECEL_100_3)
- .SetDuration(base::Milliseconds(300));
- // Fade in the continue tasks and recent apps views.
- continue_container_->FadeInViews();
- }
- ContinueSectionView* AppsContainerView::GetContinueSectionView() {
- if (!continue_container_)
- return nullptr;
- return continue_container_->continue_section();
- }
- RecentAppsView* AppsContainerView::GetRecentAppsView() {
- if (!continue_container_)
- return nullptr;
- return continue_container_->recent_apps();
- }
- AppsGridView* AppsContainerView::GetAppsGridView() {
- return apps_grid_view_;
- }
- AppListToastContainerView* AppsContainerView::GetToastContainerView() {
- return toast_container_;
- }
- void AppsContainerView::UpdateControlVisibility(AppListViewState app_list_state,
- bool is_in_drag) {
- if (app_list_state == AppListViewState::kClosed)
- return;
- SetCanProcessEventsWithinSubtree(
- app_list_state == AppListViewState::kFullscreenAllApps ||
- app_list_state == AppListViewState::kPeeking);
- apps_grid_view_->UpdateControlVisibility(app_list_state, is_in_drag);
- page_switcher_->SetVisible(
- is_in_drag || app_list_state == AppListViewState::kFullscreenAllApps ||
- app_list_state == AppListViewState::kFullscreenSearch);
- // Ignore button press during dragging to avoid app list item views' opacity
- // being set to wrong value.
- page_switcher_->set_ignore_button_press(is_in_drag);
- if (suggestion_chip_container_view_) {
- suggestion_chip_container_view_->SetVisible(
- app_list_state == AppListViewState::kFullscreenAllApps ||
- app_list_state == AppListViewState::kPeeking || is_in_drag);
- }
- }
- void AppsContainerView::AnimateOpacity(float current_progress,
- AppListViewState target_view_state,
- const OpacityAnimator& animator) {
- if (suggestion_chip_container_view_) {
- const bool target_suggestion_chip_visibility =
- target_view_state == AppListViewState::kFullscreenAllApps ||
- target_view_state == AppListViewState::kPeeking;
- animator.Run(suggestion_chip_container_view_,
- target_suggestion_chip_visibility);
- }
- if (!apps_grid_view_->layer()->GetAnimator()->IsAnimatingProperty(
- ui::LayerAnimationElement::OPACITY)) {
- apps_grid_view_->UpdateOpacity(true /*restore_opacity*/,
- kAppsOpacityChangeStart,
- kAppsOpacityChangeEnd);
- apps_grid_view_->layer()->SetOpacity(current_progress > 1.0f ? 1.0f : 0.0f);
- }
- const bool target_grid_visibility =
- target_view_state == AppListViewState::kFullscreenAllApps ||
- target_view_state == AppListViewState::kFullscreenSearch;
- animator.Run(apps_grid_view_, target_grid_visibility);
- animator.Run(page_switcher_, target_grid_visibility);
- }
- void AppsContainerView::AnimateYPosition(AppListViewState target_view_state,
- const TransformAnimator& animator,
- float default_offset) {
- // Apps container position is calculated for app list progress relative to
- // peeking state, which may not match the progress value used to calculate
- // |default_offset| - when showing search results page, the transform offset
- // is calculated using progress relative to AppListViewState::kHalf.
- const float progress =
- contents_view_->app_list_view()->GetAppListTransitionProgress(
- AppListView::kProgressFlagNone |
- AppListView::kProgressFlagWithTransform);
- const int current_suggestion_chip_y = GetExpectedSuggestionChipY(progress);
- const int target_suggestion_chip_y = GetExpectedSuggestionChipY(
- AppListView::GetTransitionProgressForState(target_view_state));
- const int offset = current_suggestion_chip_y - target_suggestion_chip_y;
- if (suggestion_chip_container_view_) {
- suggestion_chip_container_view_->SetY(target_suggestion_chip_y);
- animator.Run(offset, suggestion_chip_container_view_->layer());
- }
- scrollable_container_->SetY(target_suggestion_chip_y + chip_grid_y_distance_);
- animator.Run(offset, scrollable_container_->layer());
- page_switcher_->SetY(target_suggestion_chip_y + chip_grid_y_distance_);
- animator.Run(offset, page_switcher_->layer());
- }
- void AppsContainerView::OnTabletModeChanged(bool started) {
- if (suggestion_chip_container_view_)
- suggestion_chip_container_view_->OnTabletModeChanged(started);
- apps_grid_view_->OnTabletModeChanged(started);
- app_list_folder_view_->OnTabletModeChanged(started);
- page_switcher_->set_is_tablet_mode(started);
- }
- void AppsContainerView::Layout() {
- gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
- return;
- // Layout suggestion chips.
- gfx::Rect chip_container_rect = rect;
- chip_container_rect.set_y(GetExpectedSuggestionChipY(
- contents_view_->app_list_view()->GetAppListTransitionProgress(
- AppListView::kProgressFlagNone)));
- if (suggestion_chip_container_view_) {
- chip_container_rect.set_height(kSuggestionChipContainerHeight);
- chip_container_rect.Inset(gfx::Insets::VH(0, GetIdealHorizontalMargin()));
- suggestion_chip_container_view_->SetBoundsRect(chip_container_rect);
- } else {
- chip_container_rect.set_height(0);
- }
- // Set bounding box for the folder view - the folder may overlap with
- // suggestion chips, but not the search box.
- gfx::Rect folder_bounding_box = rect;
- int top_folder_inset = chip_container_rect.y();
- int bottom_folder_inset = kFolderMargin;
- if (features::IsProductivityLauncherEnabled())
- top_folder_inset += kFolderMargin;
- // Account for the hotseat which overlaps with contents bounds in tablet mode.
- if (contents_view_->app_list_view()->is_tablet_mode())
- bottom_folder_inset += ShelfConfig::Get()->hotseat_bottom_padding();
- folder_bounding_box.Inset(gfx::Insets::TLBR(
- top_folder_inset, kFolderMargin, bottom_folder_inset, kFolderMargin));
- app_list_folder_view_->SetBoundingBox(folder_bounding_box);
- // Leave the same available bounds for the apps grid view in both
- // fullscreen and peeking state to avoid resizing the view during
- // animation and dragging, which is an expensive operation.
- rect.set_y(chip_container_rect.bottom());
- rect.set_height(rect.height() -
- GetExpectedSuggestionChipY(kAppListFullscreenProgressValue) -
- chip_container_rect.height());
- // Layout apps grid.
- const gfx::Insets grid_insets = apps_grid_view_->GetInsets();
- const gfx::Insets margins = CalculateMarginsForAvailableBounds(
- GetContentsBounds(),
- contents_view_->GetSearchBoxSize(AppListState::kStateApps));
- gfx::Rect grid_rect = rect;
- grid_rect.Inset(gfx::Insets::TLBR(kAppGridTopMargin, margins.left(),
- margins.bottom(), margins.right()));
- // The grid rect insets are added to calculated margins. Given that the
- // grid bounds rect should include insets, they have to be removed from
- // added margins.
- grid_rect.Inset(-grid_insets);
- gfx::Rect scrollable_bounds = grid_rect;
- // With productivity launcher enabled, add space to the top of the
- // `scrollable_container_` bounds to make room for the gradient mask to be
- // placed above the continue section.
- if (features::IsProductivityLauncherEnabled())
- scrollable_bounds.Inset(
- gfx::Insets::TLBR(-kDefaultFadeoutMaskHeight, 0, 0, 0));
- scrollable_container_->SetBoundsRect(scrollable_bounds);
- if (gradient_layer_delegate_)
- UpdateGradientMaskBounds();
- bool separator_need_centering = false;
- bool first_page_config_changed = false;
- if (features::IsProductivityLauncherEnabled()) {
- const int continue_container_height =
- continue_container_->GetPreferredSize().height();
- continue_container_->SetBoundsRect(gfx::Rect(0, kDefaultFadeoutMaskHeight,
- grid_rect.width(),
- continue_container_height));
- const int toast_container_height =
- toast_container_ ? toast_container_->GetPreferredSize().height() : 0;
- if (toast_container_) {
- toast_container_->SetBoundsRect(gfx::Rect(
- 0, continue_container_->bounds().bottom() + GetSeparatorHeight(),
- grid_rect.width(), toast_container_height));
- }
- // When no views are shown between the recent apps and the apps grid,
- // vertically center the separator between them.
- if (toast_container_height == 0 && continue_container_->HasRecentApps())
- separator_need_centering = true;
- // Setting this offset prevents the app items in the grid from overlapping
- // with the continue section.
- first_page_config_changed = apps_grid_view_->ConfigureFirstPagePadding(
- continue_container_height + toast_container_height +
- GetSeparatorHeight(),
- continue_container_->HasRecentApps());
- }
- // Make sure that UpdateTopLevelGridDimensions() happens after setting the
- // apps grid's first page offset, because it can change the number of rows
- // shown in the grid.
- UpdateTopLevelGridDimensions();
- gfx::Rect apps_grid_bounds(grid_rect.size());
- // Set the apps grid bounds y to make room for the top gradient mask.
- if (features::IsProductivityLauncherEnabled())
- apps_grid_bounds.set_y(kDefaultFadeoutMaskHeight);
- if (apps_grid_view_->bounds() != apps_grid_bounds) {
- apps_grid_view_->SetBoundsRect(apps_grid_bounds);
- } else if (first_page_config_changed) {
- // Apps grid layout depends on the continue container bounds, so explicitly
- // call layout to ensure apps grid view gets laid out even if its bounds do
- // not change.
- apps_grid_view_->Layout();
- }
- if (separator_) {
- if (separator_need_centering) {
- // Center the separator between the recent apps and the first row of the
- // apps grid. This is done after the apps grid layout so the correct
- // tile padding is used.
- const int centering_offset =
- continue_container_->bounds().bottom() +
- apps_grid_view_->GetUnscaledFirstPageTilePadding() +
- GetSeparatorHeight() / 2;
- separator_->SetBoundsRect(
- gfx::Rect(gfx::Point((grid_rect.width() - kSeparatorWidth) / 2,
- centering_offset),
- gfx::Size(kSeparatorWidth, 1)));
- } else {
- separator_->SetBoundsRect(gfx::Rect(
- (grid_rect.width() - kSeparatorWidth) / 2,
- continue_container_->bounds().bottom() +
- separator_->GetProperty(views::kMarginsKey)->height() / 2,
- kSeparatorWidth, 1));
- }
- }
- // Record the distance of y position between suggestion chip container
- // and apps grid view to avoid duplicate calculation of apps grid view's
- // y position during dragging.
- chip_grid_y_distance_ = scrollable_container_->y() - chip_container_rect.y();
- // Layout page switcher.
- const int page_switcher_width = page_switcher_->GetPreferredSize().width();
- const gfx::Rect page_switcher_bounds(
- grid_rect.right() + kGridToPageSwitcherMargin, grid_rect.y(),
- page_switcher_width, grid_rect.height());
- page_switcher_->SetBoundsRect(page_switcher_bounds);
- switch (show_state_) {
- case SHOW_APPS:
- break;
- case SHOW_ACTIVE_FOLDER: {
- app_list_folder_view_->UpdatePreferredBounds();
- folder_background_view_->SetBoundsRect(rect);
- app_list_folder_view_->SetBoundsRect(
- app_list_folder_view_->preferred_bounds());
- break;
- }
- case SHOW_ITEM_REPARENT:
- case SHOW_NONE:
- break;
- }
- }
- bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) {
- if (show_state_ == SHOW_APPS)
- return apps_grid_view_->OnKeyPressed(event);
- else
- return app_list_folder_view_->OnKeyPressed(event);
- }
- const char* AppsContainerView::GetClassName() const {
- return "AppsContainerView";
- }
- void AppsContainerView::OnBoundsChanged(const gfx::Rect& old_bounds) {
- const bool creating_initial_config = !app_list_config_;
- // The size and layout of apps grid items depend on the dimensions of the
- // display on which the apps container is shown. Given that the apps container
- // is shown in fullscreen app list view (and covers complete app list view
- // bounds), changes in the `AppsContainerView` bounds can be used as a proxy
- // to detect display size changes.
- UpdateAppListConfig(GetContentsBounds());
- DCHECK(app_list_config_);
- UpdateTopLevelGridDimensions();
- // Finish initialization of views that require app list config.
- if (creating_initial_config)
- UpdateForActiveAppListModel();
- }
- void AppsContainerView::AddedToWidget() {
- GetFocusManager()->AddFocusChangeListener(this);
- }
- void AppsContainerView::RemovedFromWidget() {
- GetFocusManager()->RemoveFocusChangeListener(this);
- }
- void AppsContainerView::OnDidChangeFocus(View* focused_before,
- View* focused_now) {
- // Ensure that `continue_container_` is visible (the first page is active)
- // after moving focus down from the last row on 2nd+ page to the search box
- // and then to `continue_container_`.
- if (!is_active_page_)
- return;
- if (!continue_container_ || !continue_container_->Contains(focused_now))
- return;
- if (apps_grid_view_->pagination_model()->selected_page() != 0)
- apps_grid_view_->pagination_model()->SelectPage(0, /*animate=*/false);
- }
- void AppsContainerView::OnGestureEvent(ui::GestureEvent* event) {
- // Ignore tap/long-press, allow those to pass to the ancestor view.
- if (event->type() == ui::ET_GESTURE_TAP ||
- event->type() == ui::ET_GESTURE_LONG_PRESS) {
- return;
- }
- // Will forward events to |apps_grid_view_| if they occur in the same y-region
- if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN &&
- event->location().y() <= apps_grid_view_->bounds().y()) {
- return;
- }
- // If a folder is currently opening or closing, we should ignore the event.
- // This is here until the animation for pagination while closing folders is
- // fixed: https://crbug.com/875133
- if (app_list_folder_view_->IsAnimationRunning()) {
- event->SetHandled();
- return;
- }
- // Temporary event for use by |apps_grid_view_|
- ui::GestureEvent grid_event(*event);
- ConvertEventToTarget(apps_grid_view_, &grid_event);
- apps_grid_view_->OnGestureEvent(&grid_event);
- // If the temporary event was handled, we don't want to handle it again.
- if (grid_event.handled())
- event->SetHandled();
- }
- void AppsContainerView::OnShown() {
- DVLOG(1) << __FUNCTION__;
- // Explicitly hide the virtual keyboard before showing the apps container
- // view. This prevents the virtual keyboard's "transient blur" feature from
- // kicking in - if a text input loses focus, and a text input gains it within
- // seconds, the virtual keyboard gets reshown. This is undesirable behavior
- // for the app list (where search box gets focus by default).
- if (keyboard::KeyboardUIController::HasInstance())
- keyboard::KeyboardUIController::Get()->HideKeyboardExplicitlyBySystem();
- GetViewAccessibility().OverrideIsLeaf(false);
- is_active_page_ = true;
- // Update the continue section.
- if (continue_container_)
- continue_container_->continue_section()->SetShownInBackground(false);
- // Updates the visibility state in toast container.
- if (toast_container_) {
- toast_container_->UpdateVisibilityState(
- AppListToastContainerView::VisibilityState::kShown);
- }
- if (dialog_controller_)
- dialog_controller_->Reset(/*enabled=*/true);
- }
- void AppsContainerView::OnWillBeHidden() {
- DVLOG(1) << __FUNCTION__;
- if (show_state_ == SHOW_ACTIVE_FOLDER)
- app_list_folder_view_->CloseFolderPage();
- else
- apps_grid_view_->CancelDragWithNoDropAnimation();
- }
- void AppsContainerView::OnHidden() {
- // Apps container view is shown faded behind the search results UI - hide its
- // contents from the screen reader as the apps grid is not normally
- // actionable in this state.
- GetViewAccessibility().OverrideIsLeaf(true);
- is_active_page_ = false;
- // Update the continue section.
- if (continue_container_)
- continue_container_->continue_section()->SetShownInBackground(true);
- // Updates the visibility state in toast container.
- if (toast_container_) {
- toast_container_->UpdateVisibilityState(
- AppListToastContainerView::VisibilityState::kShownInBackground);
- }
- if (dialog_controller_)
- dialog_controller_->Reset(/*enabled=*/false);
- }
- void AppsContainerView::OnAnimationStarted(AppListState from_state,
- AppListState to_state) {
- gfx::Rect contents_bounds = GetDefaultContentsBounds();
- const gfx::Rect from_rect =
- GetPageBoundsForState(from_state, contents_bounds, gfx::Rect());
- const gfx::Rect to_rect =
- GetPageBoundsForState(to_state, contents_bounds, gfx::Rect());
- if (from_rect != to_rect) {
- DCHECK_EQ(from_rect.size(), to_rect.size());
- DCHECK_EQ(from_rect.x(), to_rect.x());
- SetBoundsRect(to_rect);
- gfx::Transform initial_transform;
- initial_transform.Translate(0, from_rect.y() - to_rect.y());
- layer()->SetTransform(initial_transform);
- auto settings = contents_view_->CreateTransitionAnimationSettings(layer());
- layer()->SetTransform(gfx::Transform());
- }
- // Set the page opacity.
- auto settings = contents_view_->CreateTransitionAnimationSettings(layer());
- UpdateContainerOpacityForState(to_state);
- }
- void AppsContainerView::UpdatePageOpacityForState(AppListState state,
- float search_box_opacity,
- bool restore_opacity) {
- UpdateContainerOpacityForState(state);
- const float progress =
- contents_view_->app_list_view()->GetAppListTransitionProgress(
- AppListView::kProgressFlagNone);
- UpdateContentsOpacity(progress, restore_opacity);
- }
- void AppsContainerView::UpdatePageBoundsForState(
- AppListState state,
- const gfx::Rect& contents_bounds,
- const gfx::Rect& search_box_bounds) {
- AppListPage::UpdatePageBoundsForState(state, contents_bounds,
- search_box_bounds);
- const float progress =
- contents_view_->app_list_view()->GetAppListTransitionProgress(
- AppListView::kProgressFlagNone);
- UpdateContentsYPosition(progress);
- }
- gfx::Rect AppsContainerView::GetPageBoundsForState(
- AppListState state,
- const gfx::Rect& contents_bounds,
- const gfx::Rect& search_box_bounds) const {
- if (state == AppListState::kStateApps)
- return contents_bounds;
- gfx::Rect bounds = contents_bounds;
- bounds.Offset(0, kNonAppsStateVerticalOffset);
- return bounds;
- }
- int AppsContainerView::GetMinHorizontalMarginForAppsGrid() const {
- return kPageSwitcherEndMargin + kGridToPageSwitcherMargin +
- page_switcher_->GetPreferredSize().width();
- }
- int AppsContainerView::GetMinTopMarginForAppsGrid(
- const gfx::Size& search_box_size) const {
- const int suggestion_chip_container_size =
- features::IsProductivityLauncherEnabled()
- ? 0
- : kSuggestionChipContainerHeight + kSuggestionChipContainerTopMargin;
- return search_box_size.height() + kAppGridTopMargin +
- suggestion_chip_container_size;
- }
- int AppsContainerView::GetIdealHorizontalMargin() const {
- if (features::IsProductivityLauncherEnabled())
- return 24;
- const int available_width = GetContentsBounds().width();
- if (available_width >=
- kAppsGridMarginRatio * GetMinHorizontalMarginForAppsGrid()) {
- return available_width / kAppsGridMarginRatio;
- }
- return available_width / kAppsGridMarginRatioForSmallWidth;
- }
- int AppsContainerView::GetIdealVerticalMargin() const {
- if (!features::IsProductivityLauncherEnabled())
- return GetContentsBounds().height() / kAppsGridMarginRatio;
- const int screen_height =
- display::Screen::GetScreen()
- ->GetDisplayNearestView(GetWidget()->GetNativeView())
- .bounds()
- .height();
- const float margin_ratio = (screen_height <= 800)
- ? kAppsGridMarginRatioForSmallHeight
- : kAppsGridMarginRatio;
- return std::max(kMinimumVerticalContainerMargin,
- static_cast<int>(screen_height / margin_ratio));
- }
- const gfx::Insets& AppsContainerView::CalculateMarginsForAvailableBounds(
- const gfx::Rect& available_bounds,
- const gfx::Size& search_box_size) {
- if (cached_container_margins_.bounds_size == available_bounds.size() &&
- cached_container_margins_.search_box_size == search_box_size) {
- return cached_container_margins_.margins;
- }
- // For productivity launcher, the `grid_layout`'s rows will be ignored because
- // the vertical margin will be constant.
- const GridLayout grid_layout = CalculateGridLayout();
- const gfx::Size min_grid_size = apps_grid_view()->GetMinimumTileGridSize(
- grid_layout.columns, grid_layout.rows);
- const gfx::Size max_grid_size = apps_grid_view()->GetMaximumTileGridSize(
- grid_layout.columns, grid_layout.rows);
- int available_height = available_bounds.height();
- // Add search box, and suggestion chips container height (with its margins to
- // search box and apps grid) to non apps grid size.
- // NOTE: Not removing bottom apps grid inset because they are included into
- // the total margin values.
- available_height -= GetMinTopMarginForAppsGrid(search_box_size);
- // Calculates margin value to ensure the apps grid size is within required
- // bounds.
- // |ideal_margin|: The value the margin would have with no restrictions on
- // grid size.
- // |available_size|: The available size for apps grid in the dimension where
- // margin is applied.
- // |min_size|: The min allowed size for apps grid in the dimension where
- // margin is applied.
- // |max_size|: The max allowed size for apps grid in the dimension where
- // margin is applied.
- const auto calculate_margin = [](int ideal_margin, int available_size,
- int min_size, int max_size) -> int {
- const int ideal_size = available_size - 2 * ideal_margin;
- if (ideal_size < min_size)
- return ideal_margin - (min_size - ideal_size + 1) / 2;
- if (ideal_size > max_size)
- return ideal_margin + (ideal_size - max_size) / 2;
- return ideal_margin;
- };
- int vertical_margin = 0;
- if (features::IsProductivityLauncherEnabled()) {
- // Productivity launcher does not have a preset number of rows per page.
- // Instead of adjusting the margins to fit a set number of rows, the grid
- // will change the number of rows to fit within the provided space.
- vertical_margin = GetIdealVerticalMargin();
- } else {
- vertical_margin =
- calculate_margin(GetIdealVerticalMargin(), available_height,
- min_grid_size.height(), max_grid_size.height());
- }
- const int horizontal_margin =
- calculate_margin(GetIdealHorizontalMargin(), available_bounds.width(),
- min_grid_size.width(), max_grid_size.width());
- const int min_horizontal_margin = GetMinHorizontalMarginForAppsGrid();
- cached_container_margins_.margins = gfx::Insets::TLBR(
- std::max(vertical_margin, kMinimumVerticalContainerMargin),
- std::max(horizontal_margin, min_horizontal_margin),
- std::max(vertical_margin, kMinimumVerticalContainerMargin),
- std::max(horizontal_margin, min_horizontal_margin));
- cached_container_margins_.bounds_size = available_bounds.size();
- cached_container_margins_.search_box_size = search_box_size;
- return cached_container_margins_.margins;
- }
- void AppsContainerView::UpdateRecentApps(bool needs_layout) {
- RecentAppsView* recent_apps = GetRecentAppsView();
- if (!recent_apps || !app_list_config_)
- return;
- AppListModelProvider* const model_provider = AppListModelProvider::Get();
- recent_apps->SetModels(model_provider->search_model(),
- model_provider->model());
- if (needs_layout)
- Layout();
- }
- void AppsContainerView::UpdateSuggestionChips() {
- if (!suggestion_chip_container_view_)
- return;
- suggestion_chip_container_view_->SetResults(
- AppListModelProvider::Get()->search_model()->results());
- }
- base::ScopedClosureRunner AppsContainerView::DisableSuggestionChipsBlur() {
- if (!suggestion_chip_container_view_)
- return base::ScopedClosureRunner(base::DoNothing());
- ++suggestion_chips_blur_disabler_count_;
- if (suggestion_chips_blur_disabler_count_ == 1)
- suggestion_chip_container_view_->SetBlurDisabled(true);
- return base::ScopedClosureRunner(
- base::BindOnce(&AppsContainerView::OnSuggestionChipsBlurDisablerReleased,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void AppsContainerView::SetShowState(ShowState show_state,
- bool show_apps_with_animation) {
- if (show_state_ == show_state)
- return;
- show_state_ = show_state;
- // Layout before showing animation because the animation's target bounds are
- // calculated based on the layout.
- Layout();
- switch (show_state_) {
- case SHOW_APPS:
- page_switcher_->SetCanProcessEventsWithinSubtree(true);
- folder_background_view_->SetVisible(false);
- apps_grid_view_->ResetForShowApps();
- app_list_folder_view_->ResetItemsGridForClose();
- if (show_apps_with_animation) {
- app_list_folder_view_->ScheduleShowHideAnimation(false, false);
- } else {
- app_list_folder_view_->HideViewImmediately();
- }
- break;
- case SHOW_ACTIVE_FOLDER:
- page_switcher_->SetCanProcessEventsWithinSubtree(false);
- folder_background_view_->SetVisible(true);
- app_list_folder_view_->ScheduleShowHideAnimation(true, false);
- break;
- case SHOW_ITEM_REPARENT:
- page_switcher_->SetCanProcessEventsWithinSubtree(true);
- folder_background_view_->SetVisible(false);
- app_list_folder_view_->ScheduleShowHideAnimation(false, true);
- break;
- default:
- NOTREACHED();
- }
- }
- void AppsContainerView::UpdateContainerOpacityForState(AppListState state) {
- const float target_opacity =
- state == AppListState::kStateApps ? 1.0f : kNonAppsStateOpacity;
- if (layer()->GetTargetOpacity() != target_opacity)
- layer()->SetOpacity(target_opacity);
- }
- void AppsContainerView::UpdateContentsOpacity(float progress,
- bool restore_opacity) {
- apps_grid_view_->UpdateOpacity(restore_opacity, kAppsOpacityChangeStart,
- kAppsOpacityChangeEnd);
- // Updates the opacity of page switcher buttons. The same rule as all apps in
- // AppsGridView.
- AppListView* app_list_view = contents_view_->app_list_view();
- int screen_bottom = app_list_view->GetScreenBottom();
- gfx::Rect switcher_bounds = page_switcher_->GetBoundsInScreen();
- float centerline_above_work_area =
- std::max<float>(screen_bottom - switcher_bounds.CenterPoint().y(), 0.f);
- float opacity =
- std::min(std::max((centerline_above_work_area - kAppsOpacityChangeStart) /
- (kAppsOpacityChangeEnd - kAppsOpacityChangeStart),
- 0.f),
- 1.0f);
- page_switcher_->layer()->SetOpacity(restore_opacity ? 1.0f : opacity);
- if (suggestion_chip_container_view_) {
- // Changes the opacity of suggestion chips between 0 and 1 when app list
- // transition progress changes between |kSuggestionChipOpacityStartProgress|
- // and |kSuggestionChipOpacityEndProgress|.
- float chips_opacity =
- base::clamp((progress - kSuggestionChipOpacityStartProgress) /
- (kSuggestionChipOpacityEndProgress -
- kSuggestionChipOpacityStartProgress),
- 0.0f, 1.0f);
- suggestion_chip_container_view_->layer()->SetOpacity(
- restore_opacity ? 1.0 : chips_opacity);
- }
- }
- void AppsContainerView::UpdateContentsYPosition(float progress) {
- const int current_suggestion_chip_y = GetExpectedSuggestionChipY(progress);
- if (suggestion_chip_container_view_)
- suggestion_chip_container_view_->SetY(current_suggestion_chip_y);
- scrollable_container_->SetY(current_suggestion_chip_y +
- chip_grid_y_distance_);
- page_switcher_->SetY(current_suggestion_chip_y + chip_grid_y_distance_);
- // If app list is in drag, reset transforms that might started animating in
- // AnimateYPosition().
- if (contents_view_->app_list_view()->is_in_drag()) {
- if (suggestion_chip_container_view_)
- suggestion_chip_container_view_->layer()->SetTransform(gfx::Transform());
- scrollable_container_->layer()->SetTransform(gfx::Transform());
- page_switcher_->layer()->SetTransform(gfx::Transform());
- }
- }
- void AppsContainerView::DisableFocusForShowingActiveFolder(bool disabled) {
- if (suggestion_chip_container_view_) {
- suggestion_chip_container_view_->DisableFocusForShowingActiveFolder(
- disabled);
- }
- if (auto* recent_apps = GetRecentAppsView(); recent_apps) {
- recent_apps->DisableFocusForShowingActiveFolder(disabled);
- }
- if (auto* continue_section = GetContinueSectionView(); continue_section) {
- continue_section->DisableFocusForShowingActiveFolder(disabled);
- }
- if (toast_container_) {
- toast_container_->DisableFocusForShowingActiveFolder(disabled);
- }
- apps_grid_view_->DisableFocusForShowingActiveFolder(disabled);
- // Ignore the page switcher in accessibility tree so that buttons inside it
- // will not be accessed by ChromeVox.
- SetViewIgnoredForAccessibility(page_switcher_, disabled);
- }
- int AppsContainerView::GetExpectedSuggestionChipY(float progress) {
- const gfx::Rect search_box_bounds =
- contents_view_->GetSearchBoxExpectedBoundsForProgress(
- AppListState::kStateApps, progress);
- if (!suggestion_chip_container_view_)
- return search_box_bounds.bottom();
- return search_box_bounds.bottom() + kSuggestionChipContainerTopMargin;
- }
- AppsContainerView::GridLayout AppsContainerView::CalculateGridLayout() const {
- DCHECK(GetWidget());
- // Adapt columns and rows based on the display/root window size.
- const gfx::Size size =
- display::Screen::GetScreen()
- ->GetDisplayNearestView(GetWidget()->GetNativeView())
- .work_area()
- .size();
- const bool is_portrait_mode = size.height() > size.width();
- const int available_height =
- CalculateAvailableBoundsForAppsGrid(GetContentsBounds()).height();
- int preferred_columns = 0;
- int preferred_rows = 0;
- int preferred_rows_first_page = 0;
- if (is_portrait_mode) {
- preferred_rows = features::IsProductivityLauncherEnabled()
- ? kPreferredGridRowsInPortraitProductivityLauncher
- : kPreferredGridColumns;
- preferred_rows_first_page = preferred_rows;
- preferred_columns =
- features::IsProductivityLauncherEnabled()
- ? kPreferredGridColumnsInPortraitProductivityLauncher
- : kPreferredGridRows;
- } else {
- preferred_rows = kPreferredGridRows;
- preferred_rows_first_page = preferred_rows;
- // In landscape mode, the first page should show the preferred number of
- // rows as well as an additional row for recent apps when possible.
- if (continue_container_ && continue_container_->HasRecentApps())
- preferred_rows_first_page++;
- preferred_columns = kPreferredGridColumns;
- }
- GridLayout result;
- result.columns = preferred_columns;
- result.rows =
- apps_grid_view_->CalculateMaxRows(available_height, preferred_rows);
- result.first_page_rows = apps_grid_view_->CalculateFirstPageMaxRows(
- available_height, preferred_rows_first_page);
- return result;
- }
- void AppsContainerView::UpdateForActiveAppListModel() {
- AppListModel* const model = AppListModelProvider::Get()->model();
- apps_grid_view_->SetModel(model);
- apps_grid_view_->SetItemList(model->top_level_item_list());
- UpdateRecentApps(/*needs_layout=*/false);
- UpdateSuggestionChips();
- // If model changes, close the folder view if it's open, as the associated
- // item list is about to go away.
- SetShowState(SHOW_APPS, false);
- }
- void AppsContainerView::OnSuggestionChipsBlurDisablerReleased() {
- DCHECK_GT(suggestion_chips_blur_disabler_count_, 0u);
- --suggestion_chips_blur_disabler_count_;
- if (suggestion_chips_blur_disabler_count_ == 0)
- suggestion_chip_container_view_->SetBlurDisabled(false);
- }
- void AppsContainerView::UpdateGradientMaskBounds() {
- const gfx::Rect container_bounds = scrollable_container_->bounds();
- const gfx::Rect top_gradient_bounds(0, 0, container_bounds.width(),
- kDefaultFadeoutMaskHeight);
- const gfx::Rect bottom_gradient_bounds(
- 0, container_bounds.height() - kDefaultFadeoutMaskHeight,
- container_bounds.width(), kDefaultFadeoutMaskHeight);
- gradient_layer_delegate_->set_start_fade_zone({top_gradient_bounds,
- /*fade_in=*/true,
- /*is_horizontal=*/false});
- gradient_layer_delegate_->set_end_fade_zone({bottom_gradient_bounds,
- /*fade_in=*/false,
- /*is_horizonal=*/false});
- gradient_layer_delegate_->layer()->SetBounds(container_bounds);
- }
- void AppsContainerView::OnAppsGridViewFadeOutAnimationEnded(
- const absl::optional<AppListSortOrder>& new_order,
- bool abort) {
- // Update item positions after the fade out animation but before the fade in
- // animation. NOTE: `update_position_closure_` can be empty in some edge
- // cases. For example, the app list is set with a new order denoted by Order
- // A. Then before the fade out animation is completed, the app list order is
- // reset with the old value. In this case, `update_position_closure_` for
- // Order A is never called. As a result, the closure for resetting the order
- // is empty.
- // Also update item positions only when the fade out animation ends normally.
- // Because a fade out animation is aborted when:
- // (1) Another reorder animation starts, or
- // (2) The apps grid's view model updates due to the reasons such as app
- // installation or model reset.
- // It is meaningless to update item positions in either case.
- if (update_position_closure_ && !abort)
- std::move(update_position_closure_).Run();
- // Record the undo toast's visibility before update.
- const bool old_toast_visible = toast_container_->IsToastVisible();
- toast_container_->OnTemporarySortOrderChanged(new_order);
- HandleFocusAfterSort();
- // Skip the fade in animation if the fade out animation is aborted.
- if (abort) {
- OnReorderAnimationEnded();
- return;
- }
- const bool target_toast_visible = toast_container_->IsToastVisible();
- const bool toast_visibility_change =
- (old_toast_visible != target_toast_visible);
- // When the undo toast's visibility changes, the apps grid's bounds should
- // change. Meanwhile, the fade in animation relies on the apps grid's bounds
- // (because of calculating the visible items). Therefore trigger layout before
- // starting the fade in animation.
- if (toast_visibility_change)
- Layout();
- ash::PaginationModel* pagination_model = apps_grid_view_->pagination_model();
- bool page_change = (pagination_model->selected_page() != 0);
- if (page_change) {
- // Ensure that the undo toast is within the view port after reorder.
- pagination_model->SelectPage(0, /*animate=*/false);
- }
- views::AnimationBuilder animation_builder =
- apps_grid_view_->FadeInVisibleItemsForReorder(base::BindRepeating(
- &AppsContainerView::OnAppsGridViewFadeInAnimationEnded,
- weak_ptr_factory_.GetWeakPtr()));
- // Fade in the undo toast when:
- // (1) The toast's visibility becomes true from false, or
- // (2) The apps page is scrolled to show the toast.
- const bool should_fade_in_toast =
- (target_toast_visible && (page_change || toast_visibility_change));
- if (!should_fade_in_toast)
- return;
- // Hide the toast to prepare for the fade in animation,
- toast_container_->layer()->SetOpacity(0.f);
- animation_builder.GetCurrentSequence().SetOpacity(
- toast_container_->layer(), 1.f, gfx::Tween::ACCEL_5_70_DECEL_90);
- // Continue section should be faded in only when the page changes.
- if (page_change) {
- continue_container_->layer()->SetOpacity(0.f);
- animation_builder.GetCurrentSequence().SetOpacity(
- continue_container_->layer(), 1.f, gfx::Tween::ACCEL_5_70_DECEL_90);
- }
- }
- void AppsContainerView::OnAppsGridViewFadeInAnimationEnded(bool aborted) {
- if (aborted) {
- // Ensure that children are visible when the fade in animation is aborted.
- toast_container_->layer()->SetOpacity(1.f);
- continue_container_->layer()->SetOpacity(1.f);
- }
- OnReorderAnimationEnded();
- }
- void AppsContainerView::OnReorderAnimationEnded() {
- update_position_closure_.Reset();
- if (reorder_animation_done_closure_)
- std::move(reorder_animation_done_closure_).Run();
- }
- void AppsContainerView::HandleFocusAfterSort() {
- // As the sort update on AppsContainerView can be called in both clamshell
- // mode and tablet mode, return early if it's currently in clamshell mode
- // because the AppsContainerView isn't visible.
- if (!contents_view_->app_list_view()->is_tablet_mode())
- return;
- // If the sort is done and the toast is visible and not fading out, request
- // the focus on the undo button on the toast. Otherwise request the focus on
- // the search box.
- if (toast_container_->IsToastVisible()) {
- toast_container_->toast_view()->toast_button()->RequestFocus();
- } else {
- contents_view_->GetSearchBoxView()->search_box()->RequestFocus();
- }
- }
- int AppsContainerView::GetSeparatorHeight() {
- if (!separator_ || !separator_->GetVisible())
- return 0;
- return separator_->GetProperty(views::kMarginsKey)->height() +
- views::Separator::kThickness;
- }
- } // namespace ash
|