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