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