• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3.taskbar.allapps;
17 
18 import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
19 
20 import android.view.View;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 import androidx.annotation.VisibleForTesting;
25 
26 import com.android.launcher3.R;
27 import com.android.launcher3.appprediction.PredictionRowView;
28 import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
29 import com.android.launcher3.model.data.AppInfo;
30 import com.android.launcher3.model.data.ItemInfo;
31 import com.android.launcher3.taskbar.TaskbarControllers;
32 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
33 import com.android.launcher3.util.PackageUserKey;
34 
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.function.Predicate;
39 /**
40  * Handles the all apps overlay window initialization, updates, and its data.
41  * <p>
42  * All apps is in an application overlay window instead of taskbar's navigation bar panel window,
43  * because a navigation bar panel is higher than UI components that all apps should be below such as
44  * the notification tray.
45  * <p>
46  * The all apps window is created and destroyed upon opening and closing all apps, respectively.
47  * Application data may be bound while the window does not exist, so this controller will store
48  * the models for the next all apps session.
49  */
50 public final class TaskbarAllAppsController {
51 
52     private TaskbarControllers mControllers;
53     private @Nullable TaskbarOverlayContext mOverlayContext;
54     private @Nullable TaskbarAllAppsSlideInView mSlideInView;
55     private @Nullable TaskbarAllAppsContainerView mAppsView;
56     private @Nullable TaskbarSearchSessionController mSearchSessionController;
57 
58     // Application data models.
59     private @NonNull AppInfo[] mApps = EMPTY_ARRAY;
60     private int mAppsModelFlags;
61     private @NonNull List<ItemInfo> mPredictedApps = Collections.emptyList();
62     private @Nullable List<ItemInfo> mZeroStateSearchSuggestions;
63     private boolean mDisallowGlobalDrag;
64     private boolean mDisallowLongClick;
65 
66     private Map<PackageUserKey, Integer> mPackageUserKeytoUidMap = Collections.emptyMap();
67 
68     /** Initialize the controller. */
init(TaskbarControllers controllers, boolean allAppsVisible)69     public void init(TaskbarControllers controllers, boolean allAppsVisible) {
70         mControllers = controllers;
71 
72         /*
73          * Recreate All Apps if it was open in the previous Taskbar instance (e.g. the configuration
74          * changed).
75          */
76         if (allAppsVisible) {
77             show(false);
78         }
79     }
80 
81     /** Clean up the controller. */
onDestroy()82     public void onDestroy() {
83         cleanUpOverlay();
84     }
85 
86     /** Updates the current {@link AppInfo} instances. */
setApps(@ullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map)87     public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
88         mApps = apps == null ? EMPTY_ARRAY : apps;
89         mAppsModelFlags = flags;
90         mPackageUserKeytoUidMap = map;
91         if (mAppsView != null) {
92             mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags, mPackageUserKeytoUidMap);
93         }
94     }
95 
setDisallowGlobalDrag(boolean disableDragForOverviewState)96     public void setDisallowGlobalDrag(boolean disableDragForOverviewState) {
97         mDisallowGlobalDrag = disableDragForOverviewState;
98     }
99 
setDisallowLongClick(boolean disallowLongClick)100     public void setDisallowLongClick(boolean disallowLongClick) {
101         mDisallowLongClick = disallowLongClick;
102     }
103 
104     /** Updates the current predictions. */
setPredictedApps(List<ItemInfo> predictedApps)105     public void setPredictedApps(List<ItemInfo> predictedApps) {
106         mPredictedApps = predictedApps;
107         if (mAppsView != null) {
108             mAppsView.getFloatingHeaderView()
109                     .findFixedRowByType(PredictionRowView.class)
110                     .setPredictedApps(mPredictedApps);
111         }
112         if (mSearchSessionController != null) {
113             mSearchSessionController.setZeroStatePredictedItems(predictedApps);
114         }
115     }
116 
117     /** Updates the current search suggestions. */
setZeroStateSearchSuggestions(List<ItemInfo> zeroStateSearchSuggestions)118     public void setZeroStateSearchSuggestions(List<ItemInfo> zeroStateSearchSuggestions) {
119         mZeroStateSearchSuggestions = zeroStateSearchSuggestions;
120     }
121 
122     /** Updates the current notification dots. */
updateNotificationDots(Predicate<PackageUserKey> updatedDots)123     public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
124         if (mAppsView != null) {
125             mAppsView.getAppsStore().updateNotificationDots(updatedDots);
126         }
127     }
128 
129     /** Toggles visibility of {@link TaskbarAllAppsContainerView} in the overlay window. */
toggle()130     public void toggle() {
131         if (isOpen()) {
132             mSlideInView.close(true);
133         } else {
134             show(true);
135         }
136     }
137 
138     /** Returns {@code true} if All Apps is open. */
isOpen()139     public boolean isOpen() {
140         return mSlideInView != null && mSlideInView.isOpen();
141     }
142 
show(boolean animate)143     private void show(boolean animate) {
144         if (mAppsView != null) {
145             return;
146         }
147         // mControllers and getSharedState should never be null here. Do not handle null-pointer
148         // to catch invalid states.
149         mControllers.getSharedState().allAppsVisible = true;
150 
151         mOverlayContext = mControllers.taskbarOverlayController.requestWindow();
152 
153         // Initialize search session for All Apps.
154         mSearchSessionController = TaskbarSearchSessionController.newInstance(mOverlayContext);
155         mOverlayContext.setSearchSessionController(mSearchSessionController);
156         mSearchSessionController.setZeroStatePredictedItems(mPredictedApps);
157         if (mZeroStateSearchSuggestions != null) {
158             mSearchSessionController.setZeroStateSearchSuggestions(mZeroStateSearchSuggestions);
159         }
160         mSearchSessionController.startLifecycle();
161 
162         mSlideInView = (TaskbarAllAppsSlideInView) mOverlayContext.getLayoutInflater().inflate(
163                 R.layout.taskbar_all_apps_sheet, mOverlayContext.getDragLayer(), false);
164         mSlideInView.addOnCloseListener(() -> {
165             mControllers.getSharedState().allAppsVisible = false;
166             cleanUpOverlay();
167         });
168         TaskbarAllAppsViewController viewController = new TaskbarAllAppsViewController(
169                 mOverlayContext, mSlideInView, mControllers, mSearchSessionController);
170 
171         viewController.show(animate);
172         mAppsView = mOverlayContext.getAppsView();
173         mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags, mPackageUserKeytoUidMap);
174         mAppsView.getFloatingHeaderView()
175                 .findFixedRowByType(PredictionRowView.class)
176                 .setPredictedApps(mPredictedApps);
177         // 1 alternative that would be more work:
178         // Create a shared drag layer between taskbar and taskbarAllApps so that when dragging
179         // starts and taskbarAllApps can close, but the drag layer that the view is being dragged in
180         // doesn't also close
181         mOverlayContext.getDragController().setDisallowGlobalDrag(mDisallowGlobalDrag);
182         mOverlayContext.getDragController().setDisallowLongClick(mDisallowLongClick);
183     }
184 
cleanUpOverlay()185     private void cleanUpOverlay() {
186         // Floating search bar is added to the drag layer in ActivityAllAppsContainerView onAttach;
187         // removed here as this is a special case that we remove the all apps panel.
188         if (mAppsView != null && mOverlayContext != null
189                 && mAppsView.getSearchUiDelegate().isSearchBarFloating()) {
190             mOverlayContext.getDragLayer().removeView(mAppsView.getSearchView());
191             mAppsView.getSearchUiDelegate().onDestroySearchBar();
192         }
193         if (mSearchSessionController != null) {
194             mSearchSessionController.onDestroy();
195             mSearchSessionController = null;
196         }
197         if (mOverlayContext != null) {
198             mOverlayContext.setSearchSessionController(null);
199             mOverlayContext = null;
200         }
201         mSlideInView = null;
202         mAppsView = null;
203     }
204 
205     @VisibleForTesting
getTaskbarAllAppsTopPadding()206     public int getTaskbarAllAppsTopPadding() {
207         // Allow null-pointer since this should only be null if the apps view is not showing.
208         return mAppsView.getActiveRecyclerView().getClipBounds().top;
209     }
210 
211     @VisibleForTesting
getTaskbarAllAppsScroll()212     public int getTaskbarAllAppsScroll() {
213         // Allow null-pointer since this should only be null if the apps view is not showing.
214         return mAppsView.getActiveRecyclerView().computeVerticalScrollOffset();
215     }
216 
217     /** @see TaskbarSearchSessionController#createPreDragConditionForSearch(View) */
218     @Nullable
createPreDragConditionForSearch(View view)219     public PreDragCondition createPreDragConditionForSearch(View view) {
220         return mSearchSessionController != null
221                 ? mSearchSessionController.createPreDragConditionForSearch(view)
222                 : null;
223     }
224 }
225