• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.allapps;
17 
18 import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION;
19 import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
20 import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
21 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
22 
23 import android.content.Context;
24 import android.os.UserHandle;
25 import android.view.View;
26 import android.view.ViewGroup;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 import androidx.recyclerview.widget.RecyclerView.RecycledViewPool;
31 
32 import com.android.launcher3.BubbleTextView;
33 import com.android.launcher3.model.data.AppInfo;
34 import com.android.launcher3.model.data.ItemInfo;
35 import com.android.launcher3.recyclerview.AllAppsRecyclerViewPool;
36 import com.android.launcher3.util.ComponentKey;
37 import com.android.launcher3.util.PackageUserKey;
38 import com.android.launcher3.views.ActivityContext;
39 
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.concurrent.CopyOnWriteArrayList;
46 import java.util.function.Consumer;
47 import java.util.function.Predicate;
48 
49 /**
50  * A utility class to maintain the collection of all apps.
51  *
52  * @param <T> The type of the context.
53  */
54 public class AllAppsStore<T extends Context & ActivityContext> {
55 
56     // Defer updates flag used to defer all apps updates to the next draw.
57     public static final int DEFER_UPDATES_NEXT_DRAW = 1 << 0;
58     // Defer updates flag used to defer all apps updates by a test's request.
59     public static final int DEFER_UPDATES_TEST = 1 << 1;
60 
61     private PackageUserKey mTempKey = new PackageUserKey(null, null);
62     private AppInfo mTempInfo = new AppInfo();
63 
64     private @NonNull AppInfo[] mApps = EMPTY_ARRAY;
65 
66     private final List<OnUpdateListener> mUpdateListeners = new CopyOnWriteArrayList<>();
67     private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
68     private Map<PackageUserKey, Integer> mPackageUserKeytoUidMap = Collections.emptyMap();
69     private int mModelFlags;
70     private int mDeferUpdatesFlags = 0;
71     private boolean mUpdatePending = false;
72     private final AllAppsRecyclerViewPool mAllAppsRecyclerViewPool = new AllAppsRecyclerViewPool();
73 
74     private final T mContext;
75 
getApps()76     public AppInfo[] getApps() {
77         return mApps;
78     }
79 
AllAppsStore(@onNull T context)80     public AllAppsStore(@NonNull T context) {
81         mContext = context;
82     }
83 
84     /**
85      * Sets the current set of apps and sets mapping for {@link PackageUserKey} to Uid for
86      * the current set of apps.
87      */
setApps(@ullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map)88     public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map)  {
89         mApps = apps == null ? EMPTY_ARRAY : apps;
90         mModelFlags = flags;
91         notifyUpdate();
92         mPackageUserKeytoUidMap = map;
93         // Preinflate all apps RV when apps has changed, which can happen after unlocking screen,
94         // rotating screen, or downloading/upgrading apps.
95         if (ENABLE_ALL_APPS_RV_PREINFLATION.get()) {
96             mAllAppsRecyclerViewPool.preInflateAllAppsViewHolders(mContext);
97         }
98     }
99 
getRecyclerViewPool()100     RecycledViewPool getRecyclerViewPool() {
101         return mAllAppsRecyclerViewPool;
102     }
103 
104     /**
105      * Look up for Uid using package name and user handle for the current set of apps.
106      */
lookUpForUid(String packageName, UserHandle user)107     public int lookUpForUid(String packageName, UserHandle user) {
108         return mPackageUserKeytoUidMap.getOrDefault(new PackageUserKey(packageName, user), -1);
109     }
110 
111     /**
112      * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_ENABLED
113      * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_HAS_SHORTCUT_PERMISSION
114      * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION
115      */
hasModelFlag(int mask)116     public boolean hasModelFlag(int mask) {
117         return (mModelFlags & mask) != 0;
118     }
119 
120     /**
121      * Returns {@link AppInfo} if any apps matches with provided {@link ComponentKey}, otherwise
122      * null.
123      */
124     @Nullable
getApp(ComponentKey key)125     public AppInfo getApp(ComponentKey key) {
126         mTempInfo.componentName = key.componentName;
127         mTempInfo.user = key.user;
128         int index = Arrays.binarySearch(mApps, mTempInfo, COMPONENT_KEY_COMPARATOR);
129         return index < 0 ? null : mApps[index];
130     }
131 
enableDeferUpdates(int flag)132     public void enableDeferUpdates(int flag) {
133         mDeferUpdatesFlags |= flag;
134     }
135 
disableDeferUpdates(int flag)136     public void disableDeferUpdates(int flag) {
137         mDeferUpdatesFlags &= ~flag;
138         if (mDeferUpdatesFlags == 0 && mUpdatePending) {
139             notifyUpdate();
140             mUpdatePending = false;
141         }
142     }
143 
disableDeferUpdatesSilently(int flag)144     public void disableDeferUpdatesSilently(int flag) {
145         mDeferUpdatesFlags &= ~flag;
146     }
147 
getDeferUpdatesFlags()148     public int getDeferUpdatesFlags() {
149         return mDeferUpdatesFlags;
150     }
151 
notifyUpdate()152     private void notifyUpdate() {
153         if (mDeferUpdatesFlags != 0) {
154             mUpdatePending = true;
155             return;
156         }
157         for (OnUpdateListener listener : mUpdateListeners) {
158             listener.onAppsUpdated();
159         }
160     }
161 
addUpdateListener(OnUpdateListener listener)162     public void addUpdateListener(OnUpdateListener listener) {
163         mUpdateListeners.add(listener);
164     }
165 
removeUpdateListener(OnUpdateListener listener)166     public void removeUpdateListener(OnUpdateListener listener) {
167         mUpdateListeners.remove(listener);
168     }
169 
registerIconContainer(ViewGroup container)170     public void registerIconContainer(ViewGroup container) {
171         if (container != null && !mIconContainers.contains(container)) {
172             mIconContainers.add(container);
173         }
174     }
175 
unregisterIconContainer(ViewGroup container)176     public void unregisterIconContainer(ViewGroup container) {
177         mIconContainers.remove(container);
178     }
179 
updateNotificationDots(Predicate<PackageUserKey> updatedDots)180     public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
181         updateAllIcons((child) -> {
182             if (child.getTag() instanceof ItemInfo) {
183                 ItemInfo info = (ItemInfo) child.getTag();
184                 if (mTempKey.updateFromItemInfo(info) && updatedDots.test(mTempKey)) {
185                     child.applyDotState(info, true /* animate */);
186                 }
187             }
188         });
189     }
190 
191     /**
192      * Sets the AppInfo's associated icon's progress bar.
193      *
194      * If this app is installed and supports incremental downloads, the progress bar will be updated
195      * the app's total download progress. Otherwise, the progress bar will be updated to the app's
196      * installation progress.
197      *
198      * If this app is fully downloaded, the app icon will be reapplied.
199      */
updateProgressBar(AppInfo app)200     public void updateProgressBar(AppInfo app) {
201         updateAllIcons((child) -> {
202             if (child.getTag() == app) {
203                 if ((app.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) == 0) {
204                     child.applyFromApplicationInfo(app);
205                 } else {
206                     child.applyProgressLevel();
207                 }
208             }
209         });
210     }
211 
updateAllIcons(Consumer<BubbleTextView> action)212     private void updateAllIcons(Consumer<BubbleTextView> action) {
213         for (int i = mIconContainers.size() - 1; i >= 0; i--) {
214             ViewGroup parent = mIconContainers.get(i);
215             int childCount = parent.getChildCount();
216 
217             for (int j = 0; j < childCount; j++) {
218                 View child = parent.getChildAt(j);
219                 if (child instanceof BubbleTextView) {
220                     action.accept((BubbleTextView) child);
221                 }
222             }
223         }
224     }
225 
226     public interface OnUpdateListener {
onAppsUpdated()227         void onAppsUpdated();
228     }
229 }
230