• 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.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
19 import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
20 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
21 
22 import android.view.View;
23 import android.view.ViewGroup;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.launcher3.BubbleTextView;
28 import com.android.launcher3.model.data.AppInfo;
29 import com.android.launcher3.model.data.ItemInfo;
30 import com.android.launcher3.util.ComponentKey;
31 import com.android.launcher3.util.PackageUserKey;
32 
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.concurrent.CopyOnWriteArrayList;
37 import java.util.function.Consumer;
38 import java.util.function.Predicate;
39 
40 /**
41  * A utility class to maintain the collection of all apps.
42  */
43 public class AllAppsStore {
44 
45     // Defer updates flag used to defer all apps updates to the next draw.
46     public static final int DEFER_UPDATES_NEXT_DRAW = 1 << 0;
47     // Defer updates flag used to defer all apps updates by a test's request.
48     public static final int DEFER_UPDATES_TEST = 1 << 1;
49 
50     private PackageUserKey mTempKey = new PackageUserKey(null, null);
51     private AppInfo mTempInfo = new AppInfo();
52 
53     private AppInfo[] mApps = EMPTY_ARRAY;
54 
55     private final List<OnUpdateListener> mUpdateListeners = new CopyOnWriteArrayList<>();
56     private final ArrayList<ViewGroup> mIconContainers = new ArrayList<>();
57     private int mModelFlags;
58 
59     private int mDeferUpdatesFlags = 0;
60     private boolean mUpdatePending = false;
61 
getApps()62     public AppInfo[] getApps() {
63         return mApps;
64     }
65 
66     /**
67      * Sets the current set of apps.
68      */
setApps(AppInfo[] apps, int flags)69     public void setApps(AppInfo[] apps, int flags) {
70         mApps = apps;
71         mModelFlags = flags;
72         notifyUpdate();
73     }
74 
75     /**
76      * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_ENABLED
77      * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_HAS_SHORTCUT_PERMISSION
78      * @see com.android.launcher3.model.BgDataModel.Callbacks#FLAG_QUIET_MODE_CHANGE_PERMISSION
79      */
hasModelFlag(int mask)80     public boolean hasModelFlag(int mask) {
81         return (mModelFlags & mask) != 0;
82     }
83 
84     /**
85      * Returns {@link AppInfo} if any apps matches with provided {@link ComponentKey}, otherwise
86      * null.
87      */
88     @Nullable
getApp(ComponentKey key)89     public AppInfo getApp(ComponentKey key) {
90         mTempInfo.componentName = key.componentName;
91         mTempInfo.user = key.user;
92         int index = Arrays.binarySearch(mApps, mTempInfo, COMPONENT_KEY_COMPARATOR);
93         return index < 0 ? null : mApps[index];
94     }
95 
enableDeferUpdates(int flag)96     public void enableDeferUpdates(int flag) {
97         mDeferUpdatesFlags |= flag;
98     }
99 
disableDeferUpdates(int flag)100     public void disableDeferUpdates(int flag) {
101         mDeferUpdatesFlags &= ~flag;
102         if (mDeferUpdatesFlags == 0 && mUpdatePending) {
103             notifyUpdate();
104             mUpdatePending = false;
105         }
106     }
107 
disableDeferUpdatesSilently(int flag)108     public void disableDeferUpdatesSilently(int flag) {
109         mDeferUpdatesFlags &= ~flag;
110     }
111 
getDeferUpdatesFlags()112     public int getDeferUpdatesFlags() {
113         return mDeferUpdatesFlags;
114     }
115 
notifyUpdate()116     private void notifyUpdate() {
117         if (mDeferUpdatesFlags != 0) {
118             mUpdatePending = true;
119             return;
120         }
121         for (OnUpdateListener listener : mUpdateListeners) {
122             listener.onAppsUpdated();
123         }
124     }
125 
addUpdateListener(OnUpdateListener listener)126     public void addUpdateListener(OnUpdateListener listener) {
127         mUpdateListeners.add(listener);
128     }
129 
removeUpdateListener(OnUpdateListener listener)130     public void removeUpdateListener(OnUpdateListener listener) {
131         mUpdateListeners.remove(listener);
132     }
133 
registerIconContainer(ViewGroup container)134     public void registerIconContainer(ViewGroup container) {
135         if (container != null && !mIconContainers.contains(container)) {
136             mIconContainers.add(container);
137         }
138     }
139 
unregisterIconContainer(ViewGroup container)140     public void unregisterIconContainer(ViewGroup container) {
141         mIconContainers.remove(container);
142     }
143 
updateNotificationDots(Predicate<PackageUserKey> updatedDots)144     public void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
145         updateAllIcons((child) -> {
146             if (child.getTag() instanceof ItemInfo) {
147                 ItemInfo info = (ItemInfo) child.getTag();
148                 if (mTempKey.updateFromItemInfo(info) && updatedDots.test(mTempKey)) {
149                     child.applyDotState(info, true /* animate */);
150                 }
151             }
152         });
153     }
154 
155     /**
156      * Sets the AppInfo's associated icon's progress bar.
157      *
158      * If this app is installed and supports incremental downloads, the progress bar will be updated
159      * the app's total download progress. Otherwise, the progress bar will be updated to the app's
160      * installation progress.
161      *
162      * If this app is fully downloaded, the app icon will be reapplied.
163      */
updateProgressBar(AppInfo app)164     public void updateProgressBar(AppInfo app) {
165         updateAllIcons((child) -> {
166             if (child.getTag() == app) {
167                 if ((app.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) == 0) {
168                     child.applyFromApplicationInfo(app);
169                 } else {
170                     child.applyProgressLevel();
171                 }
172             }
173         });
174     }
175 
updateAllIcons(Consumer<BubbleTextView> action)176     private void updateAllIcons(Consumer<BubbleTextView> action) {
177         for (int i = mIconContainers.size() - 1; i >= 0; i--) {
178             ViewGroup parent = mIconContainers.get(i);
179             int childCount = parent.getChildCount();
180 
181             for (int j = 0; j < childCount; j++) {
182                 View child = parent.getChildAt(j);
183                 if (child instanceof BubbleTextView) {
184                     action.accept((BubbleTextView) child);
185                 }
186             }
187         }
188     }
189 
190     public interface OnUpdateListener {
onAppsUpdated()191         void onAppsUpdated();
192     }
193 }
194