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